Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

CdbRooDb.cc

Go to the documentation of this file.
00001 // File and Version Information:
00002 //      $Id: CdbRooDb.cc,v 1.5 2005/10/13 18:49:10 gapon Exp $
00003 
00004 /// The implementation of the CdbRooDb singleton.
00005 /**
00006   * @see CdbRooDb
00007   */
00008 #include "BaBar/BaBar.hh"
00009 
00010 #include "CdbRooDatabase/CdbRooDb.hh"
00011 #include "CdbRooDatabase/CdbRooDatabase.hh"
00012 #include "CdbRooDatabase/CdbRooDbObject.hh"
00013 
00014 #include "CdbSQL/CdbSQLApiDatabase.hh"
00015 #include "CdbSQL/CdbSQLApiDatabaseItr.hh"
00016 #include "CdbSQL/CdbSQLObjectId.hh"
00017 #include "CdbSQL/CdbSQLCondition.hh"
00018 #include "CdbSQL/CdbSQLPartition.hh"
00019 
00020 #include "CdbMySQL/CdbMySQL.hh"
00021 
00022 #include "CdbBase/CdbDatabase.hh"
00023 #include "CdbBase/CdbCondition.hh"
00024 #include "CdbBase/CdbTransactionBase.hh"
00025 #include "CdbBase/CdbDebugStream.hh"
00026 
00027 #include "CdbRoo/CdbRooObjectFactory.hh"
00028 
00029 #include "BbrStdUtils/Tokenize.hh"
00030 #include "BbrStdUtils/String.hh"
00031 using namespace babar::String;
00032 
00033 #include <stdlib.h>     // getenv()
00034 #include <stdio.h>      // sscanf()
00035 
00036 #include <string.h>     // strcmp()
00037 #include <assert.h>
00038 
00039 #include <TBuffer.h>
00040 #include <TClass.h>
00041 
00042 #include <iostream>
00043 using std::cerr;
00044 using std::cout;
00045 using std::endl;
00046 
00047 namespace {
00048 
00049   /// Dummy transaction manager
00050   /**
00051     * DESIGN NOTE:
00052     *
00053     *   At the moment, we don't have a concept of the "transaction" in the current
00054     *   implementation of the CDB API, However we must provide this manager to comply
00055     *   with specifications of the technology-neutral CDB API.
00056     */
00057     class CdbRooDatabaseTransaction : public CdbTransactionBase {
00058 
00059     public:
00060 
00061         CdbRooDatabaseTransaction( ) : CdbTransactionBase( ) { }
00062 
00063         virtual ~CdbRooDatabaseTransaction( ) { }
00064 
00065         virtual void commitAndHold( ) { }
00066     };
00067 }
00068 
00069 CdbRooDb::CdbRooDb( ) :
00070     CdbSQLApi( ),
00071     _isInitialized              (false),    // For the sake of defered initialization
00072     _myDatabaseImplementationPtr(0),        // Will be set during an actual initialization
00073     _defaultDatabaseName        ("host=localhost,user=cdb,database=cdb,port=3306"),  // That's what we'll use of CDB_DATABASE_PATH is not found in the environment
00074     _defaultViewName            ("<local>::<recent>")
00075 {
00076     CDB_DEBUG_STREAM << "Condition/DB API instantiated for"
00077                      << " TECHNOLOGY=\"" << CdbRooDatabase::technology( ) << "\""
00078                      << " IMPLEMENTATION=\"" << CdbRooDatabase::implementation( ) << "\""
00079                      << endl;
00080 
00081   // Try to register itself in the API registry.
00082   //
00083   // NOTE: If the registration will fail then we may probably encounter a fatal
00084   //       unrecoverable problem with implementations of CDB API. One of the possible
00085   //       reasons of the falure would be if another implementation of the API has already
00086   //       registered itself in the dictionary under the same names.
00087 
00088     CdbPtr myPtr = this;
00089 
00090     CdbStatus status = set( myPtr );
00091     assert( CdbStatus::Success == status );
00092 }
00093 
00094 CdbRooDb::~CdbRooDb( )
00095 { }
00096 
00097 const char*
00098 CdbRooDb::technologyName( ) const
00099 {
00100     return CdbRooDatabase::technology( );
00101 }
00102 
00103 const char*
00104 CdbRooDb::implementationName( ) const
00105 {
00106     return CdbRooDatabase::implementation( );
00107 }
00108 
00109 void
00110 CdbRooDb::initialize( )
00111 {
00112     const char* fatalStr = "CdbRooDb::initialize() -- FATAL.";
00113 
00114     if( !_isInitialized ) {
00115 
00116       // Get the database parameters from an optional environment variable.
00117       // If it's not found then we're going to use the default path.
00118 
00119         const char* database = getenv( "CDB_DATABASE_PATH" );
00120         if( 0 != database ) _defaultDatabaseName = database;
00121 
00122       // Translate the current path and establish connection object for the server
00123 
00124         CdbCPtr<CdbSQL> implementationObjectPtr = createImplementationObject( _defaultDatabaseName );
00125         if( implementationObjectPtr.isNull( )) {
00126             cout << fatalStr << endl
00127                  << "    Failed to create an internal implementation object to deal with the specified" << endl
00128                  << "    server because of the incorrect value of the CDB_DATABASE_PATH environment variable." << endl
00129                  << "        CDB_DATABASE_PATH : \"" << _defaultDatabaseName << "\"" << endl
00130                  << "    The valid syntax should be :" << endl
00131                  << "        [host=<host>[,user=<user>[,database=<database>[,port=<port>]]]]" << endl;
00132             assert( 0 );
00133             return;
00134         }
00135         _myDatabaseImplementationPtr = implementationObjectPtr;
00136 
00137       // Get the default view from that database
00138 
00139         if( CdbStatus::Success != _myDatabaseImplementationPtr->find_default_view( _defaultViewName )) {
00140             cout << fatalStr << endl
00141                  << "    Failed to find the default view name at the specified/default database" << endl
00142                  << "        CURRENT/DEFAULT DATABASE NAME : \"" << _defaultDatabaseName << "\"" << endl;
00143             assert( 0 );
00144             return;
00145         }
00146         _isInitialized = true;
00147     }
00148 }
00149 
00150 bool
00151 CdbRooDb::isInitialized( )
00152 {
00153     return _isInitialized;
00154 }
00155 
00156 CdbStatus
00157 CdbRooDb::getDefaultDatabase( std::string& theDatabaseName)
00158 {
00159     assert( isInitialized( ));
00160 
00161     theDatabaseName = _defaultDatabaseName;
00162 
00163     return CdbStatus::Success;
00164 }
00165 
00166 CdbStatus
00167 CdbRooDb::getDefaultView( std::string& theViewName,
00168                           const char*  theDatabaseName )
00169 {
00170     assert( isInitialized( ));
00171 
00172     CdbStatus result = CdbStatus::NotFound;
00173     do {
00174 
00175       // Verify the database name
00176       //
00177       // We only allow the following:
00178       //
00179       //   - "<default>"
00180       //   - the current default path
00181       //
00182       // All these options are treated equally since we only have just one database
00183       // in the current implementation.
00184 
00185         if( 0 == theDatabaseName ) break;
00186 
00187         if( ! (( 0 == strcmp( theDatabaseName, "<default>" )) ||
00188                ( 0 == strcmp( theDatabaseName, _defaultDatabaseName.c_str( ))))) break;
00189 
00190       // Return the current default.
00191 
00192         theViewName = _defaultViewName;
00193 
00194       // Done
00195 
00196         result = CdbStatus::Success;
00197 
00198     } while( false );
00199 
00200     return result; 
00201 }
00202 
00203 CdbStatus
00204 CdbRooDb::setDefaultDatabase( const char* theDatabaseName )
00205 {
00206     const char* errorStr = "CdbRooDb::setDefaultDatabase() -- ERROR.";
00207 
00208     assert( isInitialized( ));
00209 
00210     CdbStatus result = CdbStatus::NotFound;
00211     do {
00212 
00213       // Verify the database name
00214       //
00215       // We only allow the following:
00216       //
00217       //   - "<default>"
00218       //   - the new default path to be checked for the correctness of its syntax
00219       //
00220       // All these options are treated equally since we only have just one database
00221       // in the current implementation.
00222 
00223         if( 0 == theDatabaseName ) break;
00224 
00225         if( 0 == strcmp( theDatabaseName, "<default>" )) {
00226 
00227           // Go along with whatever we already have
00228 
00229             ;
00230 
00231         } else {
00232 
00233           // Try to translate the specified database path, and if it all okay - then use it.
00234 
00235             std::string     database                = theDatabaseName;
00236             CdbCPtr<CdbSQL> implementationObjectPtr = createImplementationObject( database );
00237 
00238             if( implementationObjectPtr.isNull( )) {
00239 
00240                 cout << errorStr << endl
00241                      << "    Failed to create an internal implementation object to deal with the specified" << endl
00242                      << "    server because of the incorrect value of the passed database name." << endl
00243                      << "        DATABASE : \"" << database << "\"" << endl
00244                      << "    The valid syntax is:" << endl
00245                      << "        [host=<host>[,user=<user>[,database=<database>[,port=<port>]]]]" << endl;
00246 
00247                 result = CdbStatus::IllegalParameters;
00248                 break;
00249             }
00250             _defaultDatabaseName         = database;
00251             _myDatabaseImplementationPtr = implementationObjectPtr;
00252 
00253           // Also reset the view to the new default value as the previous name only made
00254           // a sense in the scope of its (older) database.
00255 
00256             _defaultViewName = "<local>::<recent>";
00257         }
00258 
00259       // Done
00260 
00261         result = CdbStatus::Success;
00262 
00263     } while( false );
00264 
00265     return result; 
00266 }
00267 
00268 CdbStatus
00269 CdbRooDb::setDefaultView( const char* theViewName,
00270                                const char* theDatabaseName )
00271 {
00272     assert( isInitialized( ));
00273 
00274   // This method will checks for the correctness of the database and view names.
00275   //
00276   // IMPLEMENTATION NOTE: It will NOT check if specified view is present in the database.
00277   //                      The reason is that certain operations with CDB may be permitted
00278   //                      without having finally established database.
00279 
00280     CdbStatus result = CdbStatus::NotFound;
00281     do {
00282 
00283       // Verify the database name
00284       //
00285       // We only allow the following:
00286       //
00287       //   - "<default>"
00288       //   - the current default path
00289       //
00290       // All these options are treated equally since we only have just one database
00291       // in the current implementation.
00292 
00293         if( 0 == theDatabaseName ) break;
00294 
00295         if( ! (( 0 == strcmp( theDatabaseName, "<default>" )) ||
00296                ( 0 == strcmp( theDatabaseName, _defaultDatabaseName.c_str( ))))) break;
00297 
00298       // Verify the view name
00299 
00300         if( 0 == theViewName ) break;
00301 
00302 /**
00303  ** IMPLEMENTATION NOTE: The following code is disabled to allow operations with
00304  **                      incomplete CDB.
00305  **
00306       // Try open the database and the view to check if they both exist.
00307 
00308         CdbDatabasePtr databasePtr;
00309         if( CdbStatus::Success != findDatabase( databasePtr )) break;
00310 
00311         CdbViewPtr viewPtr;
00312         if( CdbStatus::Success != databasePtr->findView( viewPtr, theViewName  )) break;
00313  **
00314  **/
00315       // Done
00316 
00317         _defaultViewName = theViewName;
00318 
00319         result = CdbStatus::Success;
00320 
00321     } while( false );
00322 
00323     return result; 
00324 }
00325 
00326 CdbStatus
00327 CdbRooDb::findDatabase( CdbDatabasePtr& thePtr,
00328                         const char*     theName )
00329 {
00330     assert( isInitialized( ));
00331 
00332     CdbStatus result = CdbStatus::Error;
00333 
00334     thePtr = 0;
00335 
00336     do {
00337 
00338       // Verify and correct parameters if 0 pointer is passed to indicate
00339       // that default database is needed. The "<default>" string is also allowed
00340       // since the current implementation maps it onto whatever current default is.
00341       //
00342       // IMPLEMENTATION NOTE: This policy may be reconsidered in the future to allow
00343       //                      connecting to the new database w/o changing the current
00344       //                      default value.
00345 
00346         std::string defaultDatabaseName;
00347         if( CdbStatus::Success != getDefaultDatabase( defaultDatabaseName )) break;
00348 
00349         std::string databaseName = defaultDatabaseName;
00350         if( 0 != theName ) {
00351             if( 0 != strcmp( "<default>", theName )) {
00352 
00353               // This is a special keyword to be mapped onto whatever default
00354               // database path name we have.
00355 
00356                 ;
00357 
00358             } else {
00359                 databaseName = theName;
00360             }
00361         }
00362         if( databaseName != defaultDatabaseName ) {
00363 
00364             cout << "CdbRooDb::findDatabase( ) -- ERROR" << endl
00365                  << "    No such database in this implementation:  \"" << databaseName.c_str( )        << "\"" << endl
00366                  << "    The only name allowed is the default one: \"" << defaultDatabaseName.c_str( ) << "\"" << endl;
00367 
00368             break;
00369         }
00370 
00371       // NOTE: - the above corrected parameters object is used.
00372       //       - a smart pointer onto itself is found through the registry.
00373 
00374         CdbPtr selfPtr;
00375         if( CdbStatus::Success != get( selfPtr,
00376                                        technologyName( ),
00377                                        implementationName( ))) {
00378             cout << "CdbRooDb::findDatabase( ) -- FATAL ERROR" << endl
00379                  << "    Failed to recover its own instance of the CDB API." << endl
00380                  << "        TECHNOLOGY     : \"" << technologyName( ) << "\"" << endl
00381                  << "        IMPLEMENTATION : \"" << implementationName( ) << "\"" << endl;
00382 
00383             assert( 0 );
00384 
00385             break;
00386         }
00387         thePtr = new CdbSQLApiDatabase( selfPtr,
00388                                         databaseName.c_str( ),
00389                                         _myDatabaseImplementationPtr );
00390 
00391         result = CdbStatus::Success;
00392 
00393     } while( false );
00394 
00395     return result;
00396 }
00397 
00398 CdbStatus
00399 CdbRooDb::databaseIterator( CdbDatabaseItr& theItr )
00400 {
00401     assert( isInitialized( ));
00402 
00403   // Note, that we find its own smart pointer through the Registry
00404 
00405   // ATTENTION: This is not a memory leak - the created object
00406   //            will be destroyed by the iterator.
00407 
00408     CdbPtr selfPtr;
00409     if( CdbStatus::Success != get( selfPtr,
00410                                    technologyName( ),
00411                                    implementationName( ))) {
00412         cout << "CdbRooDb::databaseIterator( ) -- FATAL ERROR" << endl
00413              << "    Failed to recover its own instance of the CDB API." << endl
00414              << "        TECHNOLOGY     : \"" << technologyName( ) << "\"" << endl
00415              << "        IMPLEMENTATION : \"" << implementationName( ) << "\"" << endl;
00416 
00417         assert( 0 );
00418 
00419         return CdbStatus::Error;
00420     }
00421     theItr = CdbDatabaseItr( new CdbSQLApiDatabaseItr( selfPtr ));
00422 
00423     return CdbStatus::Success;
00424 }
00425 
00426 CdbTransactionBase*
00427 CdbRooDb::transaction( CdbTransaction::Mode theMode ) const
00428 {
00429     return new CdbRooDatabaseTransaction( );
00430 }
00431 
00432 CdbStatus
00433 CdbRooDb::createObject( CdbObjectPtr&          theObjectPtr,
00434                         const CdbConditionPtr& theParentConditionPtr,
00435                         const BdbTime&         theOriginalValidityBeginTime,
00436                         const BdbTime&         theOriginalValidityEndTime,
00437                         const BdbTime&         theVisibleValidityBeginTime,
00438                         const BdbTime&         theVisibleValidityEndTime,
00439                         const BdbTime&         theDurationBeginTime,
00440                         const BdbTime&         theDurationEndTime,
00441                         const BdbTime&         theInsertionTime,
00442                         const CdbSQLObjectId&  theObjectId )
00443 {
00444     assert( isInitialized( ));
00445 
00446   // Verify input parameters
00447 
00448 //  if( theParentConditionPtr.isNull( )) return CdbStatus::IllegalParameters;
00449     assert( !theParentConditionPtr.isNull( ));
00450 
00451 //  if( theOriginalValidityBeginTime >= theOriginalValidityEndTime ) return CdbStatus::IllegalParameters;
00452     assert( !( theOriginalValidityBeginTime >= theOriginalValidityEndTime ));
00453 
00454 //  if( theVisibleValidityBeginTime  >= theVisibleValidityEndTime  ) return CdbStatus::IllegalParameters;
00455     assert( !( theVisibleValidityBeginTime  >= theVisibleValidityEndTime  ));
00456 
00457 //  if( theDurationBeginTime         >= theDurationEndTime         ) return CdbStatus::IllegalParameters;
00458     assert( !( theDurationBeginTime         >= theDurationEndTime         ));
00459 
00460 //  if( BdbTime::plusInfinity == theInsertionTime ) return CdbStatus::IllegalParameters;
00461     assert( !( BdbTime::plusInfinity == theInsertionTime ));
00462 
00463 //  if( !theObjectId.isValid( )) return CdbStatus::IllegalParameters;
00464     assert( theObjectId.isValid( ));
00465 
00466   // Create the object
00467 
00468     theObjectPtr = new CdbRooDbObject( theParentConditionPtr,
00469                                        theOriginalValidityBeginTime,
00470                                        theOriginalValidityEndTime,
00471                                        theVisibleValidityBeginTime,
00472                                        theVisibleValidityEndTime,
00473                                        theDurationBeginTime,
00474                                        theDurationEndTime,
00475                                        theInsertionTime,
00476                                        theObjectId,
00477                                        _myDatabaseImplementationPtr );
00478     return CdbStatus::Success;
00479 }
00480 
00481 CdbStatus
00482 CdbRooDb::storeObject( CdbObjectPtr&             theObjectPtr,
00483                        CdbObjectFactoryBase&     theObjectFactory,
00484                        CdbCPtr<CdbSQLCondition>& thePersistentConditionPtr,
00485                        CdbCPtr<CdbSQLPartition>& thePersistentPartitionPtr,
00486                        const CdbConditionPtr&    theParentConditionPtr,
00487                        const BdbTime&            theOriginalValidityBeginTime,
00488                        const BdbTime&            theOriginalValidityEndTime )
00489 {
00490     const char* errorStr = "CdbRooDb::storeObject() -- ERROR.";
00491 
00492   // Invoke the object creator.
00493   //
00494   // DESIGN NOTE:
00495   //
00496   //   In the current implementation of the API and its factory objects
00497   //   the create method will only create a persistent object, which
00498   //   we will get on the next step and proceed with serizlizing it into
00499   //   a BLOB and registering in the database. That's why we're passing
00500   //   an illegal validity interval for the new object. 
00501   //
00502   //   The supplied metadata object pointer should be returned 0.
00503 
00504     if( CdbStatus::Success != theObjectFactory.create( theObjectPtr,
00505                                                        theParentConditionPtr,
00506                                                        BdbTime::plusInfinity,
00507                                                        BdbTime::minusInfinity )) {
00508         cerr << errorStr << "\n"
00509              << "    Failed to create a persistent object via the supplied factory." << endl;
00510         return CdbStatus::Error;
00511     }
00512     assert( theObjectPtr.isNull( ));
00513 
00514   // Get the actual persistent object which was created above
00515   //
00516   // NOTE: Make sure the right type is passed as a factory base.
00517 
00518     CdbRooObjectFactory* objectFactoryPtr = dynamic_cast< CdbRooObjectFactory* >( &theObjectFactory );
00519     assert( 0 != objectFactoryPtr );
00520 
00521     CdbCPtr<CdbRooObjectR> persistentObjectPtr = objectFactoryPtr->persistentObjectPtr( );
00522     assert( !persistentObjectPtr.isNull( ));
00523 
00524   // This is going to be the insertion time for the new object
00525 
00526     BdbTime insertionTime( BdbTime::now( ));
00527 
00528   // Serialize the object
00529 
00530     const std::string typeName = persistentObjectPtr->ClassName( );
00531 
00532     TBuffer tBuffer( TBuffer::kWrite );
00533     if( 1 != tBuffer.WriteObjectAny( persistentObjectPtr.get( ),
00534                                      CdbRooObjectR::Class( ))) {
00535         cerr << errorStr << "\n"
00536              << "    Failed to serialzie an object of type: " << typeName << "\n"
00537              << "    by a pointer onto its base class: " << CdbRooObjectR::Class( )->GetName( ) << endl;
00538         return CdbStatus::Error;
00539     }
00540 
00541   // And store it in the persistent condition
00542   //
00543   // NOTE: This operation will also generate a unique persistent object identifier
00544 
00545     CdbSQLObjectId persistentObjectId;
00546 
00547     if( CdbStatus::Success != thePersistentConditionPtr->store_object( persistentObjectId,
00548                                                                        thePersistentPartitionPtr,
00549                                                                        theOriginalValidityBeginTime,
00550                                                                        theOriginalValidityEndTime,
00551                                                                        insertionTime,
00552                                                                        typeName,
00553                                                                        tBuffer.Buffer( ) + tBuffer.GetBufferDisplacement( ),
00554                                                                        tBuffer.Length( ) )) {
00555         cerr << errorStr << "\n"
00556              << "    Failed to store an object of type: " << typeName << endl;
00557         return CdbStatus::Error;
00558     }
00559 
00560   // Update partition's modification time if the current condition
00561   // is the partitionable one.
00562 
00563     if( thePersistentConditionPtr->isPartitionable( )) {
00564         if( CdbStatus::Success != thePersistentPartitionPtr->update( insertionTime )) {
00565 
00566             cerr << errorStr << errorStr << "\n"
00567                  << "    Failed to update the partition modification time.\"n"
00568                  << "        PARTITION ID:   " << thePersistentPartitionPtr->id( ) << "\n"
00569                  << "        CONDITION NAME: \"" << theParentConditionPtr->name( ) << "\"" << endl;
00570             return CdbStatus::Error;
00571         }
00572     }
00573 
00574   // Produce a transient metadata object for the stored object
00575 
00576     return createObject( theObjectPtr,
00577                          theParentConditionPtr,
00578                          theOriginalValidityBeginTime,  // begin of the 'original' validity interval
00579                          theOriginalValidityEndTime,    // end   of the 'original' validity interval
00580                          theOriginalValidityBeginTime,  // begin of the 'visible'  validity interval
00581                          theOriginalValidityEndTime,    // end   of the 'visible'  validity interval
00582                          insertionTime,                 // begin of the 'duration' interval
00583                          BdbTime::plusInfinity,         // end   of the 'duration' interval
00584                          insertionTime,                 // creation time of the object
00585                          persistentObjectId );
00586 }
00587 
00588 CdbCPtr<CdbSQL>
00589 CdbRooDb::createImplementationObject( const std::string& theDatabaseName )
00590 {
00591     if( theDatabaseName.empty( )) return 0;
00592 
00593     std::string host     = "localhost";
00594     std::string user     = "cdb";
00595     std::string database = "cdb";
00596 
00597     unsigned int port = 3306;
00598     {
00599         Tokenize    parameters( theDatabaseName );
00600         std::string parameter;
00601 
00602         while ( !( parameter = parameters( "," )).empty( )) {
00603 
00604             Tokenize key_value( parameter );
00605 
00606             std::string key   = key_value( "=" );
00607             std::string value = key_value( "=" );
00608 
00609 //            cout << "DEBUG: key = \"" << key << "\", value = \"" << value << "\"" << endl;
00610 
00611             if( key.empty( ) || value.empty( )) return 0;
00612 
00613             if( "host" == key ) {
00614                 host = value;
00615             } else if( "user" == key ) {
00616                 user = value;
00617             } else if( "database" == key ) {
00618                 database = value;
00619             } else if( "port" == key ) {
00620                 if( 1 != sscanf( value.c_str( ), "%u", &port )) return 0;
00621             } else {
00622                 return 0;
00623             }
00624         }
00625     }
00626 
00627   // Create a top-level implementation object
00628   //
00629   // NOTE: We expect the database to exist before opening it. The API will operate only
00630   //       on a properly created and initialized database.
00631 
00632     const bool notExistingDatabaseFlag = false;
00633 
00634     return CdbCPtr<CdbSQL>( new CdbMySQL( host,
00635                                           user,
00636                                           notExistingDatabaseFlag,
00637                                           database,
00638                                           port ));
00639 }
00640 
00641 /////////////////
00642 // End Of File //
00643 /////////////////

Generated on Mon Dec 5 18:22:08 2005 for CDB by doxygen1.3-rc3