// $Id: IDbiCache.cxx,v 1.1 2011/01/18 05:49:19 finch Exp $ #include "IDbiCache.hxx" #include "IDbiResultSet.hxx" #include "IDbiResultKey.hxx" #include "IDbiResultSetNonAgg.hxx" #include "IDbiSimFlagAssociation.hxx" #include "IDbiValidityRec.hxx" #include #include #include using std::endl; #include "IVldContext.hxx" ClassImp(COMET::IDbiCache) // Typedefs typedef COMET::IDbiCache::ResultList_t ResultList_t; typedef map::const_iterator ConstCacheItr_t; typedef map::iterator CacheItr_t; typedef ResultList_t::const_iterator ConstSubCacheItr_t; typedef ResultList_t::iterator SubCacheItr_t; // Definition of static data members // ********************************* // Definition of all member functions (static or otherwise) // ******************************************************* // // - ordered: ctors, dtor, operators then in alphabetical order. //..................................................................... ///\verbatim /// /// Purpose: Constructor /// /// Arguments: /// in qp Owning COMET::IDbiTableProxy. /// in tableName Name of associated table /// /// Return: n/a /// /// Contact: N. West /// /// Specification:- /// ============= /// /// o Create empty cache. /// /// /// Program Notes:- /// ============= /// /// None. ///\endverbatim COMET::IDbiCache::IDbiCache(COMET::IDbiTableProxy& qp,const string& tableName) : fTableProxy(qp), fTableName(tableName), fCurSize(0), fMaxSize(0), fNumAdopted(0), fNumReused(0) { COMETTrace( "Creating COMET::IDbiCache" << " "); } //..................................................................... ///\verbatim /// /// Purpose: Destructor /// /// Arguments: /// None. /// /// Return: n/a /// /// Contact: N. West /// /// Specification:- /// ============= /// /// o Destroy cache and all owned COMET::TDbiResultSets. /// /// /// Program Notes:- /// ============= /// /// None. ///\endverbatim COMET::IDbiCache::~IDbiCache() { COMETTrace( "Destroying COMET::IDbiCache" << " "); // Purge the AggNo == -1 cache before deleting. For extended // context queries it can have COMET::TDbiResultSetAggs that are clients of // COMET::TDbiResultSetNonAggs in the same cache, so purging will remove clientless // COMET::TDbiResultSetAggs which should in turn make their COMET::TDbiResultSetNonAggs // clientless. if ( this->GetSubCache(-1) ) this->Purge(fCache[-1]); for ( CacheItr_t itr = fCache.begin(); itr != fCache.end(); ++itr) { ResultList_t& subCache = itr->second; for ( SubCacheItr_t sitr = subCache.begin(); sitr != subCache.end(); ++sitr) delete *sitr; } } //..................................................................... ///\verbatim /// /// Purpose: Adopt and own a COMET::IDbiResultSet /// /// Arguments: /// res in The COMET::TDbiResiult to be adopted. /// generateKey in If true generate key /// /// Return: None. /// /// Contact: N. West /// /// Specification:- /// ============= /// /// o Create new sub-cache for aggregate if necessary. /// /// o Purge sub-cache of unwanted data and adopt new result. /// /// Program Notes:- /// ============= /// /// New entries are added to the end of the sub-cache unwanted entries /// are always removed from the beginning so sub-cache is a FIFO. ///\endverbatim void COMET::IDbiCache::Adopt(COMET::IDbiResultSet* res,bool generateKey) { if ( ! res ) return; int aggNo = res->GetValidityRec().GetAggregateNo(); // Prime sub-cache if necessary. if ( ! this->GetSubCache(aggNo) ) { ResultList_t emptyList; fCache[aggNo] = emptyList; } // Purge expired entries and add new result to cache. ResultList_t& subCache = fCache[aggNo]; Purge(subCache, res); subCache.push_back(res); ++fCurSize; ++fNumAdopted; COMETDebug( "Adopting result for " << res->TableName() << " " << res->GetValidityRecGlobal() << "\nCache size now " << fCurSize << " "); if ( fCurSize > fMaxSize ) fMaxSize = fCurSize; // If required generate key. if ( generateKey ) { res->GenerateKey(); COMETInfo( "Caching new results: ResultKey: " << *res->GetKey()); } } //..................................................................... ///\verbatim /// /// Purpose: Return sub-cache for aggregate or 0 if none.. ///\endverbatim const ResultList_t* COMET::IDbiCache::GetSubCache(Int_t aggNo) const { ConstCacheItr_t itr = fCache.find(aggNo); return ( itr == fCache.end() ) ? 0 : &itr->second; } //..................................................................... ///\verbatim /// /// Purpose: Purge all sub-caches. /// /// Arguments: None. /// /// Return: None. /// /// Contact: N. West /// /// Specification:- /// ============= /// /// o Purge all sub_caches. /// /// Program Notes:- /// ============= /// /// The first sub-cached to be purged must be sub-cache -1 as /// its members may be aggregated and consequently will be /// connected to members in other caches. ///\endverbatim void COMET::IDbiCache::Purge() { for ( CacheItr_t itr = fCache.begin(); itr != fCache.end(); ++itr ) Purge(itr->second); } //..................................................................... ///\verbatim /// /// Purpose: Purge surplus sub-cache memebers. /// /// Arguments: /// subCache in/out The sub-cache to be purged /// res in Optional COMET::IDbiResultSet (default =0) /// /// Return: None. /// /// Contact: N. West /// /// Specification:- /// ============= /// /// o Purge surplus sub-cache members i.e. those without clients. /// /// o If a COMET::IDbiResultSet is supplied, only purge entries that have /// expired relative to it or are stale. /// /// Program Notes:- /// ============= ///\endverbatim void COMET::IDbiCache::Purge(ResultList_t& subCache, const COMET::IDbiResultSet* res) { // Passing a COMET::IDbiResultSet allows the sub-cache to hold entries // for different detector types, simulation masks and tasks. for ( SubCacheItr_t itr = subCache.begin(); itr != subCache.end(); ) { COMET::IDbiResultSet* pRes = *itr; if ( pRes->GetNumClients() == 0 && ( ! res || pRes->CanDelete(res) ) ) { COMETDebug( "Purging " << pRes->GetValidityRec() << " from " << pRes->TableName() << " cache. Cache size now " << fCurSize-1 << " "); delete pRes; // Erasing increments iterator. itr = subCache.erase(itr); --fCurSize; } else { ++itr; } } } //..................................................................... ///\verbatim /// /// Purpose: Search sub-cache for COMET::IDbiResultSet set matching a COMET::IDbiValidityRec. /// with an optional sqlQualifiers string. /// Return: Pointer to matching COMET::IDbiResultSet, or = 0 if none. ///\endverbatim const COMET::IDbiResultSet* COMET::IDbiCache::Search(const COMET::IDbiValidityRec& vrec, const string& sqlQualifiers) const { Int_t aggNo = vrec.GetAggregateNo(); COMETTrace( "Secondary cache search of table " << fTableName << " for " << vrec << (sqlQualifiers != "" ? sqlQualifiers : "" ) << " "); const ResultList_t* subCache = this->GetSubCache(aggNo); if ( ! subCache ) { COMETTrace( "Secondary cache search failed." << " "); return 0; } ConstSubCacheItr_t itrEnd = subCache->end(); for ( ConstSubCacheItr_t itr = subCache->begin(); itr != itrEnd; ++itr) { COMET::IDbiResultSet* res = *itr; if ( res->Satisfies(vrec,sqlQualifiers) ) { fNumReused += res->GetNumAggregates(); COMETTrace( "Secondary cache search succeeded. Result set no. of rows: " << res->GetNumRows() << " "); return res; } } COMETTrace( "Secondary cache search failed." << " "); return 0; } //..................................................................... ///\verbatim /// /// Purpose: Search primary cache for COMET::IDbiResultSet set matching a new query. /// /// Arguments: /// vc in Context of new query /// task in Task of new query /// /// Return: Pointer to matching COMET::IDbiResultSet, or = 0 if none. ///\endverbatim const COMET::IDbiResultSet* COMET::IDbiCache::Search(const COMET::IVldContext& vc, const IDbi::Task& task ) const { COMETTrace( "Primary cache search of table " << fTableName << " for " << vc << " with task " << task << " "); const ResultList_t* subCache = this->GetSubCache(-1); if ( ! subCache ) { COMETTrace( "Primary cache search failed - sub-cache -1 is empty" << " "); return 0; } // Loop over all possible SimFlag associations. COMET::DbiDetector::Detector_t det(vc.GetDetector()); COMET::DbiSimFlag::SimFlag_t sim(vc.GetSimFlag()); COMET::IVldTimeStamp ts(vc.GetTimeStamp()); COMET::IDbiSimFlagAssociation::SimList_t simList = COMET::IDbiSimFlagAssociation::Instance().Get(sim); COMET::IDbiSimFlagAssociation::SimList_t::iterator listItr = simList.begin(); COMET::IDbiSimFlagAssociation::SimList_t::iterator listItrEnd = simList.end(); while ( listItr != listItrEnd ) { COMET::DbiSimFlag::SimFlag_t simTry = *listItr; COMET::IVldContext vcTry(det,simTry,ts); COMETDebug( " Searching cache with SimFlag: " << COMET::DbiSimFlag::AsString(simTry) << " "); for ( ConstSubCacheItr_t itr = subCache->begin(); itr != subCache->end(); ++itr) { COMET::IDbiResultSet* res = *itr; if ( res->Satisfies(vcTry,task) ) { fNumReused += res->GetNumAggregates(); COMETTrace( "Primary cache search succeeded. Result set no. of rows: " << res->GetNumRows() << " "); return res; } } COMETTrace( "Primary cache search failed." << " "); ++listItr; } return 0; } //..................................................................... ///\verbatim /// /// Purpose: Search primary cache for COMET::IDbiResultSet set matching a new query. /// /// Arguments: /// sqlQualifiers in The SQL qualifiers (context-sql;data-sql;fill-options) /// /// Return: Pointer to matching COMET::IDbiResultSet, or = 0 if none. ///\endverbatim const COMET::IDbiResultSet* COMET::IDbiCache::Search(const string& sqlQualifiers) const { COMETTrace( "Primary cache search of table " << fTableName << " for SQL " << sqlQualifiers << " "); const ResultList_t* subCache = this->GetSubCache(-1); if ( ! subCache ) { COMETTrace( "Primary cache search failed" << " "); return 0; } for ( ConstSubCacheItr_t itr = subCache->begin(); itr != subCache->end(); ++itr) { COMET::IDbiResultSet* res = *itr; if ( res->Satisfies(sqlQualifiers) ) { fNumReused += res->GetNumAggregates(); COMETTrace( "Primary cache search succeeded Result set no. of rows: " << res->GetNumRows() << " "); return res; } } COMETTrace( "Primary cache search failed" << " "); return 0; } //..................................................................... ///\verbatim /// /// Purpose: Set all entries in the cache as stale i.e. don't reuse. /// /// Arguments: None /// /// Return: n/a /// /// Contact: N. West /// /// Specification:- /// ============= /// /// o Set all entries in the cache as stale i.e. don't reuse. /// /// Program Notes:- /// ============= /// /// This member function can be used to effectively clear the cache. /// As existing COMET::IDbiResultSet objects currently in the cache may currently /// have clients, its not possible simply to delete them, so instead /// this function marks them as stale so they will not be reused and /// will eventually be dropped once all their clients have disconnected. ///\endverbatim void COMET::IDbiCache::SetStale() { for ( CacheItr_t cacheItr = fCache.begin(); cacheItr != fCache.end(); ++cacheItr ) { ResultList_t& subcache = cacheItr->second; for ( SubCacheItr_t subcacheItr = subcache.begin(); subcacheItr != subcache.end(); ++subcacheItr ) (*subcacheItr)->SetCanReuse(kFALSE); } } //..................................................................... ///\verbatim /// /// Purpose: Display statistics for cache on supplied ostream. /// /// Arguments: /// msg in ostream to output on. /// /// Return: Updated ostream. /// /// Contact: N. West /// /// Specification:- /// ============= /// /// o Output : Current Size, Max size, Adopted and Resused as /// 4 10 character wide fields. /// /// Program Notes:- /// ============= /// /// None. ///\endverbatim ostream& COMET::IDbiCache::ShowStatistics(ostream& msg) const { IMsgFormat ifmt("%10i"); msg << ifmt(fCurSize) << ifmt(fMaxSize) << ifmt(fNumAdopted) << ifmt(fNumReused); return msg; } /* Template for New Member Function //..................................................................... COMET::IDbiCache:: { // // // Purpose: // // Arguments: // xxxxxxxxx in yyyyyy // // Return: // // Contact: N. West // // Specification:- // ============= // // o // Program Notes:- // ============= // None. } */