//
// Created by alc on 4/5/17.
//

#include "SpiderCache.h"
#include "SpiderColl.h"
#include "RdbTree.h"
#include "ScopedLock.h"
#include "Collectiondb.h"
#include "Mem.h"

/////////////////////////
/////////////////////////      SpiderCache
/////////////////////////


// a global class extern'd in .h file
SpiderCache g_spiderCache;

SpiderCache::SpiderCache ( ) {
}

// returns false and set g_errno on error
bool SpiderCache::init ( ) {
	// success
	return true;
}

// return false if any tree save blocked
void SpiderCache::save ( bool useThread ) {
	// loop over all SpiderColls and get the best
	for ( int32_t i = 0 ; i < g_collectiondb.getNumRecs(); i++ ) {
		SpiderColl *sc = getSpiderCollIffNonNull(i);//m_spiderColls[i];
		if ( ! sc ) continue;
		RdbTree *tree = &sc->m_waitingTree;
		if ( ! tree->needsSave() ) continue;
		// if already saving from a thread
		if ( tree->isSaving() ) continue;
		char dir[1024];
		sprintf(dir,"%scoll.%s.%" PRId32,g_hostdb.m_dir,
			sc->m_coll,(int32_t)sc->m_collnum);
		// log it for now
		log("spider: saving waiting tree for cn=%" PRId32,(int32_t)i);
		// returns false if it blocked, callback will be called
		tree->fastSave(dir, useThread, NULL, NULL);
	}
}

void SpiderCache::reset ( ) {
	log(LOG_DEBUG,"spider: resetting spidercache");
	// loop over all SpiderColls and get the best
	for ( int32_t i = 0 ; i < g_collectiondb.getNumRecs(); i++ ) {
		CollectionRec *cr = g_collectiondb.getRec(i);
		if ( ! cr ) continue;
		ScopedLock sl(cr->m_spiderCollMutex);
		SpiderColl *sc = cr->m_spiderColl;
		if ( ! sc ) continue;
		sc->reset();
		mdelete ( sc , sizeof(SpiderColl) , "SpiderColl" );
		delete ( sc );
		cr->m_spiderColl = NULL;
	}
}

SpiderColl *SpiderCache::getSpiderCollIffNonNull ( collnum_t collnum ) {
	// "coll" must be invalid
	if ( collnum < 0 ) return NULL;
	if ( collnum >= g_collectiondb.getNumRecs()) return NULL;
	// shortcut
	CollectionRec *cr = g_collectiondb.getRec(collnum);
	// empty?
	if ( ! cr ) return NULL;
	// return it if non-NULL
	ScopedLock sl(cr->m_spiderCollMutex); //not really needed but shuts up helgrind+drd
	return cr->m_spiderColl;
}

// . get SpiderColl for a collection
// . if it is NULL for that collection then make a new one
SpiderColl *SpiderCache::getSpiderColl ( collnum_t collnum ) {
	// "coll" must be invalid
	if ( collnum < 0 ) return NULL;

	// shortcut
	CollectionRec *cr = g_collectiondb.getRec(collnum);
	// collection might have been reset in which case collnum changes
	if ( ! cr ) return NULL;
	ScopedLock sl(cr->m_spiderCollMutex);
	// return it if non-NULL
	SpiderColl *sc = cr->m_spiderColl;
	if ( sc ) return sc;

	// make it
	try { sc = new SpiderColl(cr); }
	catch(std::bad_alloc&) {
		log("spider: failed to make SpiderColl for collnum=%" PRId32,
			(int32_t)collnum);
		return NULL;
	}
	// register it
	mnew ( sc , sizeof(SpiderColl), "SpiderColl" );
	// store it
	cr->m_spiderColl = sc;
	// note it
	logf(LOG_DEBUG,"spider: made spidercoll=%p for cr=%p",
		sc,cr);

	// note it!
	log(LOG_DEBUG,"spider: adding new spider collection for %s", cr->m_coll);
	// that was it
	return sc;
}