// $Id: IDbiDatabaseManager.cxx,v 1.2 2011/06/09 14:44:29 finch Exp $ #include #include #include "TSystem.h" #include "TString.h" #include "IDbiExceptionLog.hxx" #include "IDbiBinaryFile.hxx" #include "IDbiCache.hxx" #include "IDbiCascader.hxx" #include "IDbiConfigSet.hxx" #include "IDbiServices.hxx" #include "IDbiDatabaseManager.hxx" #include "IDbiTableProxy.hxx" #include #include using std::endl; #include "UtilString.hxx" ClassImp(COMET::IDbiDatabaseManager) // Definition of static data members // ********************************* COMET::IDbiDatabaseManager* COMET::IDbiDatabaseManager::fgInstance = 0; int COMET::IDbiDatabaseManager::Cleaner::fgCount = 0; // Definition of all member functions (static or otherwise) // ******************************************************* // // - ordered: ctors, dtor, operators then in alphabetical order. //..................................................................... COMET::IDbiDatabaseManager::IDbiDatabaseManager() : fCascader(0) { // // // Purpose: Constructor // // Arguments: None. // // Return: n/a // // Contact: N. West // // Specification:- // ============= // // o Create factory // Program Notes:- // ============= // None. // Create cascader for database access. fCascader = new COMET::IDbiCascader; // Get any environment configuration. this->SetConfigFromEnvironment(); COMETTrace( "Creating COMET::IDbiDatabaseManager" << " "); } //..................................................................... COMET::IDbiDatabaseManager::~IDbiDatabaseManager() { // // // Purpose: Destructor // // Arguments: // None. // // Return: n/a // // Contact: N. West // // Specification:- // ============= // // o Destroy all COMET::TDbiTableProxies if Shutdown required. if ( COMET::IDbiExceptionLog::GetGELog().Size() ) { COMETInfo( "Database Global Exception Log contains " << COMET::IDbiExceptionLog::GetGELog().Size() << " entries:-" << " ");; COMET::IDbiExceptionLog::GetGELog().Print(); } int shutdown = 0; if ( ! this->GetConfig().Get("Shutdown",shutdown) || shutdown == 0 ) { COMETInfo( "DatabaseInterface shutdown not requested" << " "); return; } COMETInfo( "DatabaseInterface shutting down..." << " "); // Destroy all owned objects. for ( std::map::iterator itr = fTPmap.begin(); itr != fTPmap.end(); ++itr) { COMET::IDbiTableProxy* tp = (*itr).second; delete tp; } delete fCascader; fCascader = 0; COMETTrace( "Destroying COMET::IDbiDatabaseManager" << " "); COMETInfo( "DatabaseInterface shutdown complete." << " "); COMET::IDbiDatabaseManager::fgInstance = 0; } //..................................................................... void COMET::IDbiDatabaseManager::ApplySqlCondition() const { // // // Purpose: Apply Sql condition to existing COMET::TDbiTableProxys. // // Contact: N. West // // Specification:- // ============= // // o Apply global Sql condition, together with any prevailing rollback to // all existing COMET::TDbiTableProxys. std::map::const_iterator itr = fTPmap.begin(); std::map::const_iterator itrEnd = fTPmap.end(); for ( ; itr != itrEnd; ++itr) this->ApplySqlCondition(itr->second); } //..................................................................... void COMET::IDbiDatabaseManager::ApplySqlCondition(COMET::IDbiTableProxy* proxy) const { // // // Purpose: Apply Sql condition to specific COMET::IDbiTableProxy. // // Arguments: // proxy in COMET::IDbiTableProxy to which condition is to be applied. // // Contact: N. West // string sqlFull = fSqlCondition; const string tableName(proxy->GetTableName()); const string& date = fRollbackDates.GetDate(tableName); if ( date.size() ) { if ( sqlFull.size() ) sqlFull += " and "; sqlFull += fRollbackDates.GetType(tableName); sqlFull += " < \'"; sqlFull += date; sqlFull += "\'"; } const string& epoch_condition = fEpochRollback.GetEpochCondition(tableName); if ( epoch_condition.size() ) { if ( sqlFull.size() ) sqlFull += " and "; sqlFull += epoch_condition; } proxy->SetSqlCondition(sqlFull); } //..................................................................... void COMET::IDbiDatabaseManager::ClearRollbacks() { fEpochRollback.Clear(); fRollbackDates.Clear(); this->ApplySqlCondition(); } //..................................................................... void COMET::IDbiDatabaseManager::ClearSimFlagAssociation() { fSimFlagAss.Clear(); } //..................................................................... /// /// /// Purpose: Reconfigure after internal registry update. /// /// /// Throws EBadTDbiRegistryKeys() if IDbiRegistry contains any unknown keys void COMET::IDbiDatabaseManager::Config() { // Contact: N. West // // Specification:- // ============= // // o // Program Notes:- // ============= // None. IDbiRegistry& reg = this->GetConfig(); //Load up SimFlag Associations and remove them from the IDbiRegistry. fSimFlagAss.Set(reg); //Load up Rollback dates and epochs and remove them from the IDbiRegistry. fEpochRollback.Set(reg); fRollbackDates.Set(reg); //Apply any rollback now in force. this->ApplySqlCondition(); // If Level 2 cache enabled establish working directory // for COMET::IDbiBinaryFile. const char* dir; if ( reg.Get("Level2Cache",dir) ) { // Expand any environmental variables. TString tmp(dir); // March 2004 ExpandPathName returns false even if it works, so test for failure // by looking for an unexpanded symbol. gSystem->ExpandPathName(tmp); if ( tmp.Contains("$" ) ) { dir = "./"; COMETWarn( "Directory name expansion failed, using " << dir << " instead" << " "); } else { dir = tmp.Data(); } COMET::IDbiBinaryFile::SetWorkDir(dir); COMETLog( "COMET::IDbiDatabaseManager: Setting L2 Cache to: " << dir << " "); } // Check for request to make all cascade connections permanent // and remove from the IDbiRegistry. int connectionsPermanent = 0; if ( reg.Get("MakeConnectionsPermanent",connectionsPermanent) ) { reg.RemoveKey("MakeConnectionsPermanent"); Int_t dbNo =fCascader->GetNumDb(); if ( connectionsPermanent > 0 ) { while ( --dbNo >= 0 ) fCascader->SetPermanent(dbNo); COMETInfo( "Making all database connections permanent" << " "); // Inform COMET::IDbiServices so that COMET::IDbiConnection can check when opening new connections. COMET::IDbiServices::fAsciiDBConectionsTemporary = false; } else { while ( --dbNo >= 0 ) fCascader->SetPermanent(dbNo,false); COMETInfo( "Forcing all connections, including ASCII DB, to be temporary" << " "); // Inform COMET::IDbiServices so that COMET::IDbiConnection can check when opening new connections. COMET::IDbiServices::fAsciiDBConectionsTemporary = true; } } // Check for request to order context queries and remove from the IDbiRegistry. int OrderContextQuery = 0; if ( reg.Get("OrderContextQuery",OrderContextQuery) ) { reg.RemoveKey("OrderContextQuery"); if ( OrderContextQuery ) { COMET::IDbiServices::fOrderContextQuery = true; COMETInfo( "Forcing ordering of all context queries" << " "); } } // Abort if IDbiRegistry contains any unknown keys const char* knownKeys[] = { "Level2Cache", "Shutdown" }; int numKnownKeys = sizeof(knownKeys)/sizeof(char*); bool hasUnknownKeys = false; IDbiRegistry::IDbiRegistryKey keyItr(&this->GetConfig()); while ( const char* foundKey = keyItr() ) { bool keyUnknown = true; for (int keyNum = 0; keyNum < numKnownKeys; ++keyNum ) { if ( ! strcmp(foundKey,knownKeys[keyNum]) ) keyUnknown = false; } if ( keyUnknown ) { COMETSevere( "FATAL: " << "Illegal registry item: " << foundKey << " "); hasUnknownKeys = true; } } if ( hasUnknownKeys ) { COMETSevere( "FATAL: " << "Aborting due to illegal registry items." << " "); throw EBadTDbiRegistryKeys(); } } //..................................................................... COMET::IDbiTableProxy& COMET::IDbiDatabaseManager::GetTableProxy (const std::string& tableNameReq, const COMET::IDbiTableRow* tableRow) { // // // Purpose: Locate, or if necessary create, COMET::IDbiTableProxy for // named table. // // Arguments: // tableNameReq in Name of table requested. // tableRow in Example of a Table Row object. // // Return: COMET::IDbiTableProxy for table. // // Contact: N. West // // Specification:- // ============= // // o Locate, or if necessary create, COMET::IDbiTableProxy for named table. // // o If creating apply prevailing SQL condition. // Program Notes:- // ============= // None. // Force upper case name. std::string tableName = COMET::UtilString::ToUpper(tableNameReq); std::string proxyName = tableName; proxyName.append("::"); proxyName.append(tableRow->ClassName()); COMET::IDbiTableProxy* qpp = fTPmap[proxyName]; if ( ! qpp ) { qpp = new COMET::IDbiTableProxy(fCascader,tableName,tableRow); this->ApplySqlCondition(qpp); fTPmap[proxyName] = qpp; } return *qpp; } //..................................................................... COMET::IDbiDatabaseManager& COMET::IDbiDatabaseManager::Instance() { // // // Purpose: Locate, or create, COMET::IDbiDatabaseManager singleton. // // Arguments: None. // // Return: COMET::IDbiDatabaseManager singleton. // // Contact: N. West // // Specification:- // ============= // // o Locate, or if necessary create, COMET::IDbiDatabaseManager singleton. // Program Notes:- // ============= // None. if ( ! fgInstance ) { // Delete is handled by Cleaner class based on #include count fgInstance = new COMET::IDbiDatabaseManager(); } return *fgInstance; } //..................................................................... void COMET::IDbiDatabaseManager::PurgeCaches() { // // // Purpose: Purge all caches. // // Arguments: // None. // // Return: n/a // // Contact: N. West // // Specification:- // ============= // // o Purge all caches. // Program Notes:- // ============= // None. // Pruge all caches. for ( std::map::iterator itr = fTPmap.begin(); itr != fTPmap.end(); ++itr) { COMET::IDbiTableProxy* tp = (*itr).second; tp->GetCache()->Purge(); } } //..................................................................... void COMET::IDbiDatabaseManager::RefreshMetaData(const std::string& tableName) { // // // Purpose: Refresh meta data for specied table. // // Arguments: // tableName in Name of table to be refreshed. // Program Notes:- // ============= // This method is currently only used by COMET::IDbiSqlValPacket after // it has created a new table in the database. In such cases // the pre-existing corresponding IDbiTableProxy.hxxas to be refreshed. std::map::iterator itr = fTPmap.begin(); std::map::iterator itrEnd = fTPmap.end(); for ( ; itr != itrEnd; ++itr) { COMET::IDbiTableProxy* table = (*itr).second; if ( table && table->GetTableName() == tableName ) table->RefreshMetaData(); } } //..................................................................... void COMET::IDbiDatabaseManager::SetConfigFromEnvironment() { // // // Purpose: Set up configuration from ENV_DBI environmental variable // which consists of a semi-colon separated list of DBI // configuration requests. const char* strENV_DBI = gSystem->Getenv("ENV_DBI"); if ( strENV_DBI == 0 || strlen(strENV_DBI) == 0 ) return; COMETInfo( "\nConfiguring DatabaseInterface from the environmental " << "variable ENV_DBI:-\n " << strENV_DBI << " "); std::vector configRequests; COMET::UtilString::StringTok(configRequests, strENV_DBI, ";"); for (unsigned entry = 0; entry < configRequests.size(); ++entry ) this->Set(configRequests[entry].c_str()); this->Update(); } //..................................................................... void COMET::IDbiDatabaseManager::SetSqlCondition(const std::string& sql) { // // // Purpose: Record and apply global SQL condition. // // Arguments: // sql in SQL condition string (excluding where). // // See Program Notes. // Contact: N. West // // Specification:- // ============= // // o Record global SQL condition and apply to existing COMET::TDbiTableProxys. // Program Notes:- // ============= // The SQL condition must behave as a single expression as // additional conditions e.g. rollback, may be appended using // AND. This means that if the expression contains sub-expressions // combined using OR, then the entire expression should be enclosed // in parentheses. fSqlCondition = sql; this->ApplySqlCondition(); } //..................................................................... void COMET::IDbiDatabaseManager::ShowStatistics() const { // // // Purpose: Show total statistics. // // Contact: N. West std::ostream& msg=ICOMETLog::GetLogStream(); msg << "\n\nCache statistics:-\n\n" << "Table Name " << " Current Maximum Total Total\n" << " " << " Size Size Adopted Reused" << endl; // Loop over all owned objects. for ( std::map::const_iterator itr = fTPmap.begin(); itr != fTPmap.end(); ++itr) { const COMET::IDbiTableProxy* tp = (*itr).second; std::string name = (*itr).first; if ( name.size() < 40 ) name.append(40-name.size(),' '); msg << name; // Only want to look at cache so by-pass constness. const_cast(tp)->GetCache()->ShowStatistics(msg); msg << endl; } msg << "\n" << endl; // Only want to look at cascader so by-pass constness. COMETInfo( const_cast(this)->GetCascader()); }