Bdb packages | Design docs | Source docs | Guidelines | Recent releases

Search | Site Map .

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

/BdbCond/BdbCondDatabaseMgr.cc

Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 //
00003 // File and Version Information:
00004 //      $Id: BdbCondDatabaseMgr.cc,v 1.46 2002/08/07 21:45:26 gapon Exp $
00005 //
00006 // Description:
00007 //      Class BdbCondDatabaseMgr
00008 //
00009 // Environment:
00010 //      Software developed for the BaBar Detector at the SLAC B-Factory.
00011 //
00012 // Author List:
00013 //      Igor A. Gaponenko       Original Author
00014 //
00015 // Copyright Information:
00016 //      Copyright (C) 1999      Lawrence Berkeley Laboratory
00017 //
00018 //-----------------------------------------------------------------------------
00019 
00020 // -------------------------
00021 // -- This Class's Header --
00022 // -------------------------
00023 
00024 #include "BdbCond/BdbCondDatabaseMgr.hh"
00025 
00026 // ---------------
00027 // -- C Headers --
00028 // ---------------
00029 
00030 extern "C" {
00031 #include <assert.h>
00032 #include <ctype.h>
00033 #include <stddef.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 }
00038 
00039 // -----------------
00040 // -- C++ Headers --
00041 // -----------------
00042 
00043 #include <string>
00044 using std::string;
00045 #include <vector>
00046 using std::vector;
00047 #include <map>
00048 using std::map;
00049 #include <iostream.h>
00050 #include "BbrStdUtils/String.hh"
00051 // ---------------------------------
00052 // -- Collaborating Class Headers --
00053 // ---------------------------------
00054 
00055 #include "BdbApplication/BdbDomain.hh"
00056 #include "BdbApplication/BdbDebug.hh"
00057 #include "BdbAccess/BdbAuth.hh"
00058 #include "BdbAccess/BdbAuthItr.hh"
00059 #include "BdbClustering/BdbCondIndexClusteringHint.hh"
00060 #include "BdbClustering/BdbCondClusteringHint.hh"
00061 #include "BdbCond/BdbCondErrors.hh"
00062 #include "BdbCond/BdbInterval.hh"
00063 #include "BdbCond/BdbIntervalGene.hh"
00064 #include "BdbCond/BdbObject.hh"
00065 #include "BdbCond/BdbCondRevision.hh"
00066 #include "BdbCond/BdbString.hh"
00067 #include "BdbCond/BdbCondHistory.hh"
00068 #include "BdbCond/BdbCondTransientCache.hh"
00069 #include "BdbCond/BdbIntervalItr.hh"
00070 #include "BdbCond/BdbString.hh"
00071 #include "BdbCond/BdbCondContainerLink.hh"
00072 #include "BdbTime/BdbTime.hh"
00073 #include "ErrLogger/ErrLog.hh"
00074 
00075 
00076 // --------------------------------------------------------------------------
00077 // -- Local Macros, Typedefs, Structures, Unions, and Forward Declarations --
00078 // --------------------------------------------------------------------------
00079 
00080 static const char  rcsid[] = "$Id: BdbCondDatabaseMgr.cc,v 1.46 2002/08/07 21:45:26 gapon Exp $";
00081 
00082 // -------------------
00083 // -- Error handler --
00084 // -------------------
00085 
00086 static ooErrorHandlerPtr oldErrorHandlerPtr;
00087 
00088 static ooStatus
00089 vtableWarningsHandler( const ooErrorLevel     errorLevel,
00090                        const ooError&         errorID,
00091                        const ooHandle(ooObj)* contextObj,
00092                        char*                  errorMsg )
00093 {
00094   // Ignore the warnings #69 and #1132 only.
00095 
00096     if(( errorLevel == oocWarning ) &&
00097        (( errorID.errorN == 69 ) || ( errorID.errorN == 1132 ))) {
00098 
00099         errorMsg = (char*) 0;
00100 
00101         return oocSuccess;
00102     }
00103 
00104   // Just forward any other errors further to the regular
00105   // errors handler.
00106 
00107     return oldErrorHandlerPtr( (ooErrorLevel)     errorLevel,
00108                                (ooError&)         errorID,
00109                                (ooHandle(ooObj)*) contextObj,
00110                                                    errorMsg );
00111 }
00112 
00113 // ------------------
00114 // -- Constructors --
00115 // ------------------
00116 
00117 BdbCondDatabaseMgr::BdbCondDatabaseMgr( bool supressVTableWarnings ) :
00118     _supressVTableWarnings(supressVTableWarnings)
00119 {
00120     if ( _supressVTableWarnings ) {
00121 
00122       // Trap the warnings #69 and #1132 temporarily on the time of copy
00123       // execution in order to get rid of these noisy messages about
00124       // missing VTable.
00125       // The real trapping is controlled by a special flag to be set
00126       // by the class's constructor.
00127       //
00128       //    NOTE: The problem is that ::copy() method is trying to call
00129       //          a virtual ::ooCopyInit() method in order to perform
00130       //          user-specific copy operation to follow up the regular
00131       //          shellow copy.
00132 
00133         oldErrorHandlerPtr = ooGetErrorHandler( );
00134         ooRegErrorHandler( (ooErrorHandlerPtr) vtableWarningsHandler );
00135     }
00136 }
00137 
00138 // ----------------
00139 // -- Destructor --
00140 // ----------------
00141 
00142 BdbCondDatabaseMgr::~BdbCondDatabaseMgr( )
00143 {
00144     if ( _supressVTableWarnings ) {
00145         ooRegErrorHandler( oldErrorHandlerPtr );
00146     }
00147 }
00148 
00149 // -----------------------------
00150 // -- Public member Functions --
00151 // -----------------------------
00152 
00153 BdbStatus
00154 BdbCondDatabaseMgr::copyIntervalContainer( const char* theInTLA,
00155                                            const char* theInContName,
00156                                            const char* theOutTLA,
00157                                            const char* theOutContName,
00158                                            LevelType   level,
00159                                            d_ULong     theRevId,
00160                                            bool        copyCondObjects,
00161                                            bool        copyToLocalDb,
00162                                            const char* theContName )
00163 {
00164     const char* errorString = "BdbCondDatabaseMgr::copyIntervalContainer() -- error.";
00165 
00166     BdbStatus status = BdbcError;
00167 
00168     assert( theInTLA       != (char*) 0 );
00169     assert( theInContName  != (char*) 0 );
00170     assert( theOutTLA      != (char*) 0 );
00171     assert( theOutContName != (char*) 0 );
00172 
00173   // Open both databases.
00174 
00175     BdbObsoleteDatabase theInDb( theInTLA );
00176     BdbObsoleteDatabase theOutDb( theOutTLA );
00177 
00178   // Perform operations in a exception-like loop.
00179 
00180     bool operationsLoopWasFailed = true;
00181 
00182     while ( true ) {
00183 
00184       // Prepare the output container.
00185 
00186         status = initOutputContainer( theInDb,
00187                                       theInContName,
00188                                       theOutDb,
00189                                       theOutContName );
00190         if ( BdbcSuccess != status ) {
00191             ErrMsg(error) << errorString << endl
00192                           << "    Failed to initialize the output container." << endmsg;
00193             break;
00194         }
00195 
00196       // Choose the desired copy level.
00197 
00198         switch( level ) {
00199 
00200         case LEVEL_DEEP:
00201 
00202             status = deepCopy( theInDb, theOutDb );
00203             break;
00204 
00205         case LEVEL_TOPMOST:
00206 
00207             status = baselineOrTopmostCopy( theInDb, theOutDb, false );
00208             break;
00209 
00210         case LEVEL_BASELINE:
00211 
00212             status = baselineOrTopmostCopy( theInDb, theOutDb, true );
00213             break;
00214 
00215         case LEVEL_REVISION:
00216 
00217             status = revisionCopy( theInDb, theOutDb, theRevId );
00218             break;
00219 
00220         default:
00221 
00222             status = BdbcError;
00223             break;
00224         }
00225 
00226       // Make a further copy of conditions objects itself if required
00227       // and if the containers belong to two different detectors only.
00228 
00229         if ( BdbcSuccess == status ) {
00230             if ( copyCondObjects ) {
00231                 if ( strcmp( theInDb.subsystemTLA( ), theOutDb.subsystemTLA( ))) {
00232                     status = copyObjects( theOutDb, copyToLocalDb, theContName );
00233                 }
00234             }
00235         }
00236 
00237       // The loop has been sucessfully completed.
00238 
00239         operationsLoopWasFailed = false;
00240         break;
00241     }
00242     if ( operationsLoopWasFailed ) {
00243         ErrMsg(error) << "        Input   detector: \"" << theInTLA << "\"" << endl
00244                       << "               container: \"" << theInContName << "\"" << endl
00245                       << "        Output  detector: \"" << theOutTLA << "\"" << endl
00246                       << "               container: \"" << theOutContName << "\"" << endmsg;
00247         if ( BdbcSuccess == status ) {
00248             status = BdbcError;
00249         }
00250     }
00251 
00252   // Put a record into the History of the output container.
00253 
00254     d_ULong theLastIndex = 0;
00255 
00256     BdbHandle(BdbCondHistory) theInHistoryH;
00257     theInHistoryH = theInDb.getHistoryH( );
00258 
00259     if ( ! BdbIsNull( theInHistoryH )) {
00260         theLastIndex = theInHistoryH->numRecords( );
00261         if ( theLastIndex != 0 ) {
00262             theLastIndex--;
00263         }
00264     }
00265 
00266     theOutDb.historyCCopy( rcsid,
00267                            theLastIndex,
00268                            theInTLA,
00269                            theInContName,
00270                            level,
00271                            theRevId,
00272                            copyCondObjects,
00273                            copyToLocalDb,
00274                            theContName );
00275 
00276     return status;
00277 }
00278 
00279 BdbStatus
00280 BdbCondDatabaseMgr::removeIntervalContainer( const char* theTLA,
00281                                              const char* theContName,
00282                                              bool        removeContainerLinkFlag )
00283 {
00284     const char* errorString = "BdbCondDatabaseMgr::removeIntervalContainer() -- error.";
00285 
00286     BdbStatus status;
00287 
00288     BdbHandle(BdbContObj) theContH;
00289 
00290     assert ( theTLA      != (char*) 0 );
00291     assert ( theContName != (char*) 0 );
00292 
00293   // Open the database.
00294 
00295     BdbObsoleteDatabase theDb( theTLA );
00296 
00297   // Perform initializations in a exception-like loop.
00298 
00299     bool theLoopWasFailed = true;
00300 
00301     while ( true ) {
00302 
00303       // Make sure that a proper authorization level is set.
00304 
00305         if ( ! theDb.verifyAuthLevelOnly( theContName )) {
00306             ErrMsg(error) << errorString << endl
00307                           << "    Failed to set proper Authorization level." << endmsg;
00308             break;
00309         }
00310 
00311       // Check if the container is not write-locked.
00312 
00313         if ( theDb.isWriteLocked( theContName )) {
00314             ErrMsg(error) << errorString << endl
00315                           << "    The container is write-locked and can not be deleted in this federation." << endmsg;
00316             break;
00317         }
00318 
00319       // Setup cache context by locating the container handle, or handles
00320       // for both container link and the target interval container.
00321 
00322         status = theDb.findIntervalCont( theContH, theContName );
00323         if ( BdbcSuccess != status ) {
00324             ErrMsg(error) << errorString << endl
00325                           << "    The container does not exist." << endmsg;
00326             break;
00327         }
00328 
00329       // If this is the link and the link is also has to be deleted
00330       // then use the link deletion procedure, which would also
00331       // delete the interval container itself.
00332 
00333         if( theDb.isLink( ) && removeContainerLinkFlag ) {
00334             return removeIntervalContainerLink( theTLA, theContName, true );
00335         }
00336 
00337       // Delete the container with all their contents.
00338 
00339         BdbDelete( theContH ) ;
00340 
00341         theLoopWasFailed = false;
00342         break;
00343     }
00344     if ( theLoopWasFailed ) {
00345         ErrMsg(error) << "        Detector:  \"" << theTLA << "\"" << endl
00346                       << "        Container: \"" << theContName << "\"" << endmsg;
00347 
00348         if ( BdbcSuccess == status ) {
00349             status = BdbcError;
00350         }
00351 
00352         return status;
00353     }
00354 
00355     return BdbcSuccess;
00356 }
00357 
00358 BdbStatus
00359 BdbCondDatabaseMgr::createIntervalContainerLink( const char* theLinkTLA,
00360                                                  const char* theLinkContName,
00361                                                  const char* theOrigin,
00362                                                  const char* theTLA,
00363                                                  const char* theContName,
00364                                                  bool        verifyRealContainer )
00365 {
00366     const char* errorString = "BdbCondDatabaseMgr::createIntervalContainerLink() -- error.";
00367 
00368   // Verify the parameters.
00369 
00370     assert ( theLinkTLA      != (char*) 0 );
00371     assert ( theLinkContName != (char*) 0 );
00372     assert ( theOrigin       != (char*) 0 );
00373     assert ( theTLA          != (char*) 0 );
00374     assert ( theContName     != (char*) 0 );
00375 
00376   // Local data structures.
00377 
00378     BdbStatus status;
00379 
00380     BdbHandle(BdbContObj) theLinkContH;
00381     BdbHandle(BdbContObj) theContH;
00382 
00383     BdbHandle(BdbString) theLinkH;
00384 
00385     BdbCondIndexClusteringHint theHint( theLinkTLA, theLinkContName, "Link" );
00386 
00387     BdbObsoleteDatabase theLinkDb( theLinkTLA );
00388     BdbObsoleteDatabase theDb( theLinkTLA );
00389 
00390   // Build the link.
00391   //
00392   //    NOTE: We will verify the correctness of the link later.
00393 
00394     BdbCondContainerLink theLink( theOrigin, theTLA, theContName );
00395 
00396   // Perform initializations in a exception-like loop.
00397 
00398     bool theLoopWasFailed = true;
00399 
00400     while ( true ) {
00401 
00402       // Ensure a proper authorization level to be set.
00403 
00404         if ( ! theLinkDb.verifyAuthLevelOnly( theLinkContName )) {
00405             ErrMsg(error) << errorString << endl
00406                           << "    Failed to set proper Authorization level." << endmsg;
00407             break;
00408         }
00409 
00410       // Verify the correctness of the link.
00411 
00412         if ( ! theLink.isValid( )) {
00413             ErrMsg(error) << errorString << endl
00414                           << "    Failed to build the link from specified parameters." << endmsg;
00415             break;
00416         }
00417 
00418       // Check for the presence of the container with specified link name.
00419       // It must not exist.
00420 
00421         bool followLinkFlag = false;
00422 
00423         status = theLinkDb.findIntervalCont( theLinkContH, theLinkContName, followLinkFlag );
00424         if (( BdbcSuccess == status ) && ( ! BdbIsNull( theLinkContH ))) {
00425              ErrMsg(error) << errorString << endl
00426                            << "    The link with such name already exist." << endmsg;
00427              break;
00428         }
00429 
00430       // Create the link container.
00431 
00432         theLinkContH = theHint.updatedHint( );
00433         if ( BdbIsNull(theLinkContH) || ( ! theHint.newContainerCreated( ))) {
00434             ErrMsg(error) << errorString << endl
00435                           << "    The clustering hint did create new interval contaiiner." << endmsg;
00436             break;
00437         }
00438 
00439       // Write the link information into this container.
00440 
00441         theLinkH = new( theLinkContH ) BdbString( theLink.getLinkName().c_str());
00442         theLinkH.nameObj( theLinkContH, "Link" );
00443 
00444       // Now open the same link container and follow the link in order to make sure
00445       // if the real container does exist.
00446 
00447         if ( verifyRealContainer ) {
00448             status = theDb.findIntervalCont( theContH, theLinkContName );
00449             if ( ! (( BdbcSuccess == status ) && theDb.isLink( ))) {
00450                 ErrMsg(error) << errorString << endl
00451                               << "    Failed to verify the presence of the real container for this link." << endl
00452                               << "    The container link would not be created." << endmsg;
00453 
00454               // Remove the newly created container link.
00455 
00456                 removeIntervalContainerLink( theLinkTLA, theLinkContName );
00457 
00458                 break;
00459             }
00460         }
00461 
00462         theLoopWasFailed = false;
00463         break;
00464     }
00465     if ( theLoopWasFailed ) {
00466         ErrMsg(error) << "        LINK Detector  -> " << theLinkTLA << endl
00467                       << "        LINK Container -> " << theLinkContName << endl
00468                       << "            ORIGIN for REAL Container -> " << theOrigin << endl
00469                       << "            REAL Detector             -> " << theTLA << endl
00470                       << "            REAL Container            -> " << theContName << endmsg;
00471         if ( BdbcSuccess == status ) {
00472             status = BdbcError;
00473         }
00474         return status;
00475     }
00476 
00477     return BdbcSuccess;
00478 }
00479 
00480 BdbStatus
00481 BdbCondDatabaseMgr::removeIntervalContainerLink( const char* theLinkTLA,
00482                                                  const char* theLinkContName,
00483                                                  bool        removeIntervalContainerFlag )
00484 {
00485     const char* errorString = "BdbCondDatabaseMgr::removeIntervalContainerLink() -- error.";
00486 
00487   // Verify the parameters.
00488 
00489     assert ( theLinkTLA      != (char*) 0 );
00490     assert ( theLinkContName != (char*) 0 );
00491 
00492   // Local data structures.
00493 
00494     BdbStatus status;
00495 
00496     BdbHandle(BdbContObj) theContH;
00497     BdbHandle(BdbContObj) theLinkContH;
00498 
00499     BdbObsoleteDatabase theLinkDb( theLinkTLA );
00500 
00501   // Perform initializations in a exception-like loop.
00502 
00503     bool theLoopWasFailed = true;
00504 
00505     while ( true ) {
00506 
00507       // Ensure a proper authorization level to be set.
00508       //
00509       // We don't need to check at this point if the target interval container
00510       // is write-locked, because deleting the link itself would not require
00511       // to delete the target interval container.
00512       // Even more, such a checking procedure (agains write locking) would require
00513       // the corresponding interval container to exist, which may not be a case.
00514       //
00515       // However we may need to perform this test if the optional parameter
00516       // to this procedure tells us to remove the interval container.
00517 
00518         if ( ! theLinkDb.verifyAuthLevelOnly( theLinkContName )) {
00519             ErrMsg(error) << errorString << endl
00520                           << "    Failed to set proper Authorization level." << endmsg;
00521             break;
00522         }
00523 
00524       // Check for the presence of the container with specified link name.
00525       //
00526       //    NOTE: We don't follow the link in order to avoid the "noise" when
00527       //          the real container for this link does not exist.
00528       //
00529       // The container finding procedure would return us just 
00530 
00531         bool followLinkFlag = false;
00532 
00533         status = theLinkDb.findIntervalCont( theLinkContH, theLinkContName, followLinkFlag );
00534         if (( BdbcSuccess != status ) || BdbIsNull( theLinkContH )) {
00535             ErrMsg(error) << errorString << endl
00536                           << "    The specified link container does not exist." << endmsg;
00537             break;
00538         }
00539 
00540       // Locate and destroy the interval container, which is referenced
00541       // via the link if the third parameter to this procedure require this
00542       // and if there is no write-lock for this container.
00543       //
00544       // NOTE: we are not interested here in the "old" interval containers
00545       //       which are not referenced through the link.
00546 
00547         if ( removeIntervalContainerFlag ) {
00548 
00549             status = theLinkDb.findIntervalCont( theContH, theLinkContName );
00550             if (( BdbcSuccess == status ) && ( ! BdbIsNull( theContH )) && theLinkDb.isLink( )) {
00551 
00552               // Check if this container is not write-locked.
00553 
00554                 if ( theLinkDb.isWriteLocked( )) {
00555                     ErrMsg(error) << errorString << endl
00556                                   << "    The interval container is write-locked and can't be deleted." << endmsg;
00557                     break;
00558                 }
00559 
00560                 BdbDelete(theContH);
00561 
00562             } else {
00563                 ErrMsg(error) << errorString << endl
00564                               << "    The interval container for specified link does not exist." << endmsg;
00565                 break;
00566             }
00567         }
00568 
00569       // Destroy the link container.
00570 
00571         BdbDelete(theLinkContH);
00572 
00573         theLoopWasFailed = false;
00574         break;
00575     }
00576     if ( theLoopWasFailed ) {
00577         ErrMsg(error) << "        LINK Detector  -> " << theLinkTLA << endl
00578                       << "        LINK Container -> " << theLinkContName << endmsg;
00579         if ( BdbcSuccess == status ) {
00580             status = BdbcError;
00581         }
00582         return status;
00583     }
00584 
00585     return BdbcSuccess;
00586 }
00587 
00588 BdbStatus
00589 BdbCondDatabaseMgr::lockIntervalContainerLink( const char* theLinkTLA,
00590                                                const char* theLinkContName )
00591 {
00592     const char* errorString = "BdbCondDatabaseMgr::lockIntervalContainerLink() -- error.";
00593 
00594   // Verify the parameters.
00595 
00596     assert ( theLinkTLA      != (char*) 0 );
00597     assert ( theLinkContName != (char*) 0 );
00598 
00599   // Local data structures.
00600 
00601     BdbStatus status;
00602 
00603     BdbHandle(BdbContObj) theContH;
00604     BdbHandle(BdbContObj) theLinkContH;
00605 
00606     BdbObsoleteDatabase theLinkDb( theLinkTLA );
00607 
00608   // Perform initializations in a exception-like loop.
00609 
00610     bool theLoopWasFailed = true;
00611 
00612     while ( true ) {
00613 
00614       // Ensure a proper authorization level to be set.
00615       //
00616       // We don't need to check at this point if the target interval container
00617       // is write-locked.
00618 
00619         if ( ! theLinkDb.verifyAuthLevelOnly( theLinkContName )) {
00620             ErrMsg(error) << errorString << endl
00621                           << "    Failed to set proper Authorization level." << endmsg;
00622             break;
00623         }
00624 
00625       // Check for the presence of the container with specified link name.
00626       //
00627       //    NOTE: We don't follow the link in order to avoid the "noise" when
00628       //          the real container for this link does not exist.
00629       //
00630       // The container finding procedure would return us just 
00631 
00632         bool followLinkFlag = false;
00633 
00634         status = theLinkDb.findIntervalCont( theLinkContH, theLinkContName, followLinkFlag );
00635         if (( BdbcSuccess != status ) || BdbIsNull( theLinkContH )) {
00636             ErrMsg(error) << errorString << endl
00637                           << "    The specified link container does not exist." << endmsg;
00638             break;
00639         }
00640 
00641       // Try to obtain the lock from the comtainer.
00642 
00643         BdbHandle(BdbString) theWriteLockH;
00644 
00645         theWriteLockH.lookupObj( theLinkContH, "WriteLock" );
00646         if ( ! BdbIsNull(theWriteLockH)) {
00647             ErrMsg(error) << errorString << endl
00648                           << "    The interval container is already write-locked." << endmsg;
00649             break;
00650         }
00651 
00652       // Create a new persistent lock for the link.
00653 
00654         theWriteLockH = new( theLinkContH ) BdbString( "Link" );
00655         theWriteLockH.nameObj( theLinkContH, "WriteLock" );
00656 
00657         theLoopWasFailed = false;
00658         break;
00659     }
00660     if ( theLoopWasFailed ) {
00661         ErrMsg(error) << "        LINK Detector  -> " << theLinkTLA << endl
00662                       << "        LINK Container -> " << theLinkContName << endmsg;
00663         if ( BdbcSuccess == status ) {
00664             status = BdbcError;
00665         }
00666         return status;
00667     }
00668 
00669     return BdbcSuccess;
00670 }
00671 
00672 BdbStatus
00673 BdbCondDatabaseMgr::unlockIntervalContainerLink( const char* theLinkTLA,
00674                                                  const char* theLinkContName )
00675 {
00676     const char* errorString = "BdbCondDatabaseMgr::unlockIntervalContainerLink() -- error.";
00677 
00678   // Verify the parameters.
00679 
00680     assert ( theLinkTLA      != (char*) 0 );
00681     assert ( theLinkContName != (char*) 0 );
00682 
00683   // Local data structures.
00684 
00685     BdbStatus status;
00686 
00687     BdbHandle(BdbContObj) theContH;
00688     BdbHandle(BdbContObj) theLinkContH;
00689 
00690     BdbObsoleteDatabase theLinkDb( theLinkTLA );
00691 
00692   // Perform initializations in a exception-like loop.
00693 
00694     bool theLoopWasFailed = true;
00695 
00696     while ( true ) {
00697 
00698       // Ensure a proper authorization level to be set.
00699       //
00700       // We don't need to check at this point if the target interval container
00701       // is write-locked.
00702 
00703         if ( ! theLinkDb.verifyAuthLevelOnly( theLinkContName )) {
00704             ErrMsg(error) << errorString << endl
00705                           << "    Failed to set proper Authorization level." << endmsg;
00706             break;
00707         }
00708 
00709       // Check for the presence of the container with specified link name.
00710       //
00711       //    NOTE: We don't follow the link in order to avoid the "noise" when
00712       //          the real container for this link does not exist.
00713       //
00714       // The container finding procedure would return us just 
00715 
00716         bool followLinkFlag = false;
00717 
00718         status = theLinkDb.findIntervalCont( theLinkContH, theLinkContName, followLinkFlag );
00719         if (( BdbcSuccess != status ) || BdbIsNull( theLinkContH )) {
00720             ErrMsg(error) << errorString << endl
00721                           << "    The specified link container does not exist." << endmsg;
00722             break;
00723         }
00724 
00725       // Try to obtain the lock from the comtainer.
00726 
00727         BdbHandle(BdbString) theWriteLockH;
00728 
00729         theWriteLockH.lookupObj( theLinkContH, "WriteLock" );
00730         if ( BdbIsNull(theWriteLockH)) {
00731             ErrMsg(error) << errorString << endl
00732                           << "    The interval container is not write-locked." << endmsg;
00733             break;
00734         }
00735 
00736       // Just delete a persistent object.
00737 
00738         BdbDelete(theWriteLockH);
00739 
00740         theLoopWasFailed = false;
00741         break;
00742     }
00743     if ( theLoopWasFailed ) {
00744         ErrMsg(error) << "        LINK Detector  -> " << theLinkTLA << endl
00745                       << "        LINK Container -> " << theLinkContName << endmsg;
00746         if ( BdbcSuccess == status ) {
00747             status = BdbcError;
00748         }
00749         return status;
00750     }
00751 
00752     return BdbcSuccess;
00753 }
00754 
00755 BdbStatus
00756 BdbCondDatabaseMgr::deleteObjects( const char* theTLA,
00757                                    const char* theContName )
00758 {
00759     const char* errorString = "BdbCondDatabaseMgr::deleteObjects() -- error.";
00760 
00761     BdbHandle(BdbContObj) theContH;
00762 
00763     assert ( theTLA      != (char*) 0 );
00764     assert ( theContName != (char*) 0 );
00765 
00766   // Open the database.
00767 
00768     BdbObsoleteDatabase theDb( theTLA );
00769 
00770   // Perform initializations in a exception-like loop.
00771 
00772     bool theLoopWasFailed = true;
00773 
00774     while ( true ) {
00775 
00776       // Ensure a proper authorization level to be set.
00777 
00778         if ( ! theDb.verifyAuthLevelOnly( theContName )) {
00779             ErrMsg(error) << errorString << endl
00780                           << "    Failed to set proper Authorization level." << endmsg;
00781             break;
00782         }
00783 
00784       // Iterate all the BASELINE intervals and recursivly delete objects
00785       // in each subtree growing from theis interval.
00786 
00787         BdbIntervalItr theItr;
00788         if( ! theItr.setBaseline( theTLA, theContName )) {
00789             ErrMsg(error) << errorString << endl
00790                           << "    Failed to initialize an iterator for BASELINE iintervals." << endmsg;
00791             break;
00792         }
00793 
00794         while( theItr.next( )) {
00795             deleteObjectsInSubTree( theItr );
00796         }
00797 
00798         theLoopWasFailed = false;
00799         break;
00800     }
00801     if ( theLoopWasFailed ) {
00802         ErrMsg(error) << "        Detector:  \"" << theTLA << "\"" << endl
00803                       << "        Container: \"" << theContName << "\"" << endmsg;
00804 
00805         return BdbcError;
00806     }
00807 
00808     return BdbcSuccess;
00809 }
00810 
00811 BdbStatus
00812 BdbCondDatabaseMgr::evaluateIntervalContainer( const char* theTLA,
00813                                                const char* theContName,
00814                                                bool&       exists )
00815 {
00816     const char* errorString = "BdbCondDatabaseMgr::evaluateIntervalContainer() -- error.";
00817 
00818     BdbStatus status;
00819 
00820     BdbHandle(BdbContObj) theContH;
00821 
00822     assert ( theTLA      != (char*) 0 );
00823     assert ( theContName != (char*) 0 );
00824 
00825   // Set the default status of the container.
00826 
00827     exists = false;
00828 
00829   // Open the database.
00830 
00831     BdbObsoleteDatabase theDb( theTLA );
00832 
00833   // Perform initializations in a exception-like loop.
00834 
00835     bool theLoopWasFailed = true;
00836 
00837     while ( true ) {
00838 
00839       // Here we perform a real verification of the container presence.
00840 
00841         status = theDb.findIntervalCont( theContH, theContName );
00842         if (( BdbcSuccess == status ) && ( ! BdbIsNull(  theContH ))) {
00843             exists = true;
00844         }
00845 
00846         theLoopWasFailed = false;
00847         break;
00848     }
00849 
00850     if ( theLoopWasFailed ) {
00851         ErrMsg(error) << "        Detector:  \"" << theTLA << "\"" << endl
00852                       << "        Container: \"" << theContName << "\"" << endmsg;
00853 
00854         if ( BdbcSuccess == status ) {
00855             status = BdbcError;
00856         }
00857 
00858         return status;
00859     }
00860 
00861     return BdbcSuccess;
00862 }
00863 
00864 BdbStatus
00865 BdbCondDatabaseMgr::createCheckpoint( const char* theTLA,
00866                                       const char* theContName )
00867 {
00868     const char* errorString = "BdbCondDatabaseMgr::createCheckpoint() -- error.";
00869 
00870     BdbStatus status = BdbcError;
00871 
00872     assert( theTLA       != (char*) 0 );
00873     assert( theContName  != (char*) 0 );
00874 
00875     BdbHandle(BdbCondHistory) theHistoryH;
00876 
00877   // Open the database.
00878 
00879     BdbObsoleteDatabase theDb( theTLA );
00880 
00881   // Build the backup container name.
00882   // The current time would be the checkpoint time.
00883 
00884     BdbTime theTime;
00885 
00886     char theNumber[11];
00887     sprintf( theNumber, "%.10u", theTime.getGmtSec( ));
00888 
00889     string theBackupContName = string( "_CHECKPOINT_") + string( theNumber ) + string( "_" ) + string( theContName );
00890 
00891   // Perform initializations in a exception-like loop.
00892 
00893     bool theLoopWasFailed = true;
00894 
00895     while ( true ) {
00896 
00897       // Make a copy of the specified container into a backup one without copying the objects.
00898 
00899         status = copyIntervalContainer( theTLA, theContName, theTLA, theBackupContName.c_str() );
00900         if( BdbcSuccess != status ) {
00901             ErrMsg(error) << errorString << endl
00902                           << "    Failed to make a backup copy of specified container." << endmsg;
00903             break;
00904         }
00905 
00906       // Initialize the container cache by a simple operation.
00907 
00908         status = theDb.findHistory( theHistoryH, theContName );
00909         if( BdbcSuccess != status ) {
00910             ErrMsg(error) << errorString << endl
00911                           << "    Failed to get the History of the container." << endmsg;
00912             break;
00913         }
00914 
00915         theLoopWasFailed = false;
00916         break;
00917     }
00918     if ( theLoopWasFailed ) {
00919         ErrMsg(error) << "        Input   detector: \"" << theTLA << "\"" << endl
00920                       << "               container: \"" << theContName << "\"" << endl
00921                       << "        Backup  detector: \"" << theTLA << "\"" << endl
00922                       << "               container: \"" << theBackupContName << "\"" << endmsg;
00923 
00924         if ( BdbcSuccess == status ) {
00925             status = BdbcError;
00926         }
00927 
00928         return status;
00929     }
00930 
00931   // Put a record into the History of the original container.
00932 
00933     theDb.historyCPoint( rcsid,
00934                          theTime,
00935                          theBackupContName.c_str() );
00936 
00937     return BdbcSuccess;
00938 }
00939 
00940 BdbStatus
00941 BdbCondDatabaseMgr::resetRevisions( const char* theTLA,
00942                                     const char* theContName )
00943 {
00944     const char* errorString = "BdbCondDatabaseMgr::resetRevisions() -- error.";
00945 
00946     BdbStatus status;
00947 
00948     ErrMsg(error) << errorString << endl
00949                   << "    The operation is not implemented yet." << endmsg;
00950 
00951     return BdbcError;
00952 }
00953 
00954 BdbStatus
00955 BdbCondDatabaseMgr::createHistory( const char* theTLA,
00956                                    const char* theContName,
00957                                    bool        makeContainerBackup )
00958 {
00959     const char* errorString = "BdbCondDatabaseMgr::createHistory() -- error.";
00960 
00961     BdbStatus status;
00962 
00963     BdbHandle(BdbContObj)           theContH;
00964     BdbHandle(BdbCondHistory)       theHistoryH;
00965     BdbHandle(BdbCondHistoryRecord) theRecordH;
00966 
00967     assert ( theTLA      != (char*) 0 );
00968     assert ( theContName != (char*) 0 );
00969 
00970   // Open the database.
00971 
00972     BdbObsoleteDatabase theDb( theTLA );
00973 
00974   // Perform initializations in a exception-like loop.
00975 
00976     bool theLoopWasFailed = true;
00977 
00978     while ( true ) {
00979 
00980       // Ensure a proper authorization level to be set.
00981 
00982         if ( ! theDb.verifyAuthLevelOnly( theContName )) {
00983             ErrMsg(error) << errorString << endl
00984                           << "    Failed to set proper Authorization level." << endmsg;
00985             break;
00986         }
00987 
00988       // Setup cache context by locating the container handle.
00989 
00990         status = theDb.findIntervalCont( theContH, theContName );
00991         if ( BdbcSuccess != status ) {
00992             ErrMsg(error) << errorString << endl
00993                           << "    The container does not exist." << endmsg;
00994             break;
00995         }
00996 
00997       // Try to obtain the History. It should not exist.
00998 
00999         theHistoryH = theDb.getHistoryH( );
01000         if ( ! BdbIsNull( theHistoryH )) {
01001             ErrMsg(error) << errorString << endl
01002                           << "    The History already exist." << endmsg;
01003             break;
01004         }
01005 
01006       // Make a container backup in order to reflect a state
01007       // of the original container.
01008       //
01009       // NOTE: The backup is a deep copy of interval container contents
01010       //       into a special container with prefixed name.
01011 
01012         string theBackupContName;
01013 
01014         if ( makeContainerBackup ) {
01015 
01016           // Build the backup container name.
01017 
01018             theBackupContName = string( "_HISTORY_" ) + string( theContName );
01019 
01020           // Delete existing backup container (if any).
01021 
01022             BdbObsoleteDatabase theBackupDb( theTLA );
01023             BdbHandle(BdbContObj) theBackupContH;
01024 
01025             status = theBackupDb.findIntervalCont( theBackupContH, theBackupContName.c_str() );
01026             if (( BdbcSuccess == status ) && ( ! BdbIsNull( theBackupContH ))) {
01027                 BdbDelete(theBackupContH);
01028             }
01029 
01030             status = copyIntervalContainer( theTLA, theContName, theTLA, theBackupContName.c_str() );
01031             if ( BdbcSuccess != status ) {
01032                 ErrMsg(error) << errorString << endl
01033                               << "    Failed to make a deep copy of the container." << endmsg;
01034                 break;
01035             }
01036         }
01037 
01038       // Create the History.
01039 
01040         theHistoryH = new( theContH ) BdbCondHistory( );
01041         theHistoryH.nameObj( theContH, "History" );
01042 
01043      // Reopen the interval container with history.
01044      // Then put the very first record into the history of container.
01045 
01046         BdbObsoleteDatabase theNewDb( theTLA );
01047 
01048         theHistoryH = 0;
01049 
01050         status = theNewDb.findHistory( theHistoryH, theContName );
01051         if (( BdbcSuccess != status ) || BdbIsNull( theHistoryH )) {
01052             ErrMsg(error) << errorString << endl
01053                           << "    Failed to locate the newly created History in the container." << endmsg;
01054             break;
01055         }
01056         theNewDb.historyHCreate( rcsid, theBackupContName.c_str() );
01057 
01058         theLoopWasFailed = false;
01059         break;
01060     }
01061     if ( theLoopWasFailed ) {
01062         ErrMsg(error) << "        Detector:  \"" << theTLA << "\"" << endl
01063                       << "        Container: \"" << theContName << "\"" << endmsg;
01064 
01065         if ( BdbcSuccess == status ) {
01066             status = BdbcError;
01067         }
01068         return status;
01069     }
01070 
01071     return BdbcSuccess;
01072 }
01073 
01074 BdbStatus
01075 BdbCondDatabaseMgr::removeHistory( const char* theTLA,
01076                                    const char* theContName )
01077 {
01078     const char* errorString = "BdbCondDatabaseMgr::removeHistory() -- error.";
01079 
01080     BdbStatus status;
01081 
01082     BdbHandle(BdbContObj)     theContH;
01083     BdbHandle(BdbCondHistory) theHistoryH;
01084 
01085     assert ( theTLA      != (char*) 0 );
01086     assert ( theContName != (char*) 0 );
01087 
01088   // Open the database.
01089 
01090     BdbObsoleteDatabase theDb( theTLA );
01091 
01092   // Perform initializations in a exception-like loop.
01093 
01094     bool theLoopWasFailed = true;
01095 
01096     while ( true ) {
01097 
01098       // Ensure a proper authorization level to be set.
01099 
01100         if ( ! theDb.verifyAuthLevelOnly( theContName )) {
01101             ErrMsg(error) << errorString << endl
01102                           << "    Failed to set proper Authorization level." << endmsg;
01103             break;
01104         }
01105 
01106       // Setup cache context by locating the container handle.
01107 
01108         status = theDb.findIntervalCont( theContH, theContName );
01109         if ( BdbcSuccess != status ) {
01110             ErrMsg(error) << errorString << endl
01111                           << "    The container does not exist." << endmsg;
01112             break;
01113         }
01114 
01115       // Try to obtain the History. It should exist.
01116 
01117         theHistoryH = theDb.getHistoryH( );
01118         if ( BdbIsNull( theHistoryH )) {
01119             ErrMsg(error) << errorString << endl
01120                           << "    The History does not exist." << endmsg;
01121             break;
01122         }
01123 
01124       // Delete the History.
01125 
01126         BdbDelete(theHistoryH);
01127 
01128       // Delete backup container (if any) and corresponding
01129       // container link (if it's linked container).
01130 
01131         string theBackupContName = string( "_HISTORY_" ) + string( theContName );
01132 
01133         BdbObsoleteDatabase theBackupDb( theTLA );
01134         BdbHandle(BdbContObj) theBackupContH;
01135         BdbHandle(BdbContObj) theBackupLinkContH;
01136 
01137         status = theBackupDb.findIntervalCont( theBackupContH, theBackupContName.c_str() );
01138         if (( BdbcSuccess == status ) && ( ! BdbIsNull( theBackupContH ))) {
01139             if ( theBackupDb.isLink( )) {
01140                 theBackupDb.getLinkContH( theBackupLinkContH );
01141                 BdbDelete( theBackupLinkContH );
01142             }
01143             BdbDelete(theBackupContH);
01144         }
01145 
01146         theLoopWasFailed = false;
01147         break;
01148     }
01149     if ( theLoopWasFailed ) {
01150         ErrMsg(error) << "        Detector:  \"" << theTLA << "\"" << endl
01151                       << "        Container: \"" << theContName << "\"" << endmsg;
01152 
01153         if ( BdbcSuccess == status ) {
01154             status = BdbcError;
01155         }
01156         return status;
01157     }
01158 
01159     return BdbcSuccess;
01160 }
01161 
01162 BdbStatus
01163 BdbCondDatabaseMgr::commentHistory( const char* theTLA,
01164                                     const char* theContName,
01165                                     const char* theRcsid,
01166                                     const char* theComment )
01167 {
01168     const char* errorString = "BdbCondDatabaseMgr::commentHistory() -- error.";
01169 
01170     BdbStatus status;
01171 
01172     BdbHandle(BdbCondHistory) theHistoryH;
01173 
01174     assert ( theTLA      != (char*) 0 );
01175     assert ( theContName != (char*) 0 );
01176 
01177   // Open the database.
01178 
01179     BdbObsoleteDatabase theDb( theTLA );
01180 
01181   // Perform initializations in a exception-like loop.
01182 
01183     bool theLoopWasFailed = true;
01184 
01185     while ( true ) {
01186 
01187       // Ensure a proper authorization level to be set.
01188 
01189         if ( ! theDb.verifyAuthLevelOnly( theContName )) {
01190             ErrMsg(error) << errorString << endl
01191                           << "    Failed to set proper Authorization level." << endmsg;
01192             break;
01193         }
01194 
01195       // Setup cache context by locating the container handle.
01196 
01197         status = theDb.findHistory( theHistoryH, theContName );
01198         if (( BdbcSuccess != status ) || ( BdbIsNull( theHistoryH ))) {
01199             ErrMsg(error) << errorString << endl
01200                           << "    Failed to locate the History in the container." << endmsg;
01201             break;
01202         }
01203 
01204       // Make a record for the History
01205 
01206         theDb.historyComment( theRcsid, theComment );
01207 
01208         theLoopWasFailed = false;
01209         break;
01210     }
01211     if ( theLoopWasFailed ) {
01212         ErrMsg(error) << "        Detector:  \"" << theTLA << "\"" << endl
01213                       << "        Container: \"" << theContName << "\"" << endmsg;
01214 
01215         if ( BdbcSuccess == status ) {
01216             status = BdbcError;
01217         }
01218         return status;
01219     }
01220 
01221     return BdbcSuccess;
01222 }
01223 
01224 BdbStatus
01225 BdbCondDatabaseMgr::evaluateIntervalDatabase( const char* theTLA,
01226                                               bool&       exists )
01227 {
01228     const char* errorString = "BdbCondDatabaseMgr::evaluateIntervalDatabase() -- error.";
01229 
01230     BdbStatus status;
01231 
01232     assert( theTLA != (const char*) 0 );
01233 
01234   // Build the name of the link database.
01235 
01236     BdbObsoleteDatabase theDb( theTLA );
01237     string dbSysName;
01238 
01239     dbSysName = theDb.linkDatabaseName( theTLA );  
01240     if ( dbSysName == (char*) 0 ) {
01241         ErrMsg(error) << errorString << endl
01242                       << "    Failed to build the link database name from the detector name." << endl
01243                       << "        DETECTOR: " << theTLA << endmsg;
01244         return BdbcError;
01245     }
01246 
01247   // Check the existence of the link database
01248 
01249     BdbHandle(BdbDBObj) theDbH;
01250     COUT1 << "CONDDBOPEN (exist only): db=" << dbSysName << endl;
01251     exists = theDbH.exist( BdbApplicationOrDomain::activeInstance()->fd(), dbSysName.c_str(), BdbcNoOpen );
01252 
01253     return BdbcSuccess;
01254 }
01255 
01256 BdbStatus
01257 BdbCondDatabaseMgr::getDatabasesForContainer( vector<string>& theList,
01258                                               const char*                     theTLA,
01259                                               const char*                     theContName )
01260 {
01261     const char* errorString = "BdbCondDatabaseMgr::getDatabasesForContainer() -- error.";
01262 
01263     BdbStatus status;
01264 
01265     assert( theTLA      != (const char*) 0 );
01266     assert( theContName != (const char*) 0 );
01267 
01268     theList.clear( );
01269 
01270   // Prepare the data structures.
01271 
01272     map<string, BdbRef(ooDBObj)>* theDict;
01273     theDict = new map<string, BdbRef(ooDBObj)>;
01274 
01275     BdbObsoleteDatabase theDb( theTLA );
01276 
01277   // Run the container scanner.
01278 
01279     status = scanContainer( *theDict, theDb, theContName );
01280     if( BdbcSuccess != status ) {
01281         ErrMsg(error) << errorString << endl
01282                       << "    Failed to obtain databases to be referenced through the container." << endl
01283                       << "        DETECTOR  -> " << theTLA << endl
01284                       << "        CONTAINER -> " << theContName << endmsg;
01285         delete theDict;
01286         return status;
01287     }
01288 
01289   // Now browse the hash dictionary and get the system name of each database
01290   // found in there.
01291 
01292     map<string, BdbRef(ooDBObj)>::iterator theDictItr=theDict->begin();
01293     BdbRef(ooDBObj) theDbRef;
01294 
01295     while( theDictItr!=theDict->end()) {
01296         theDbRef = theDictItr->second;
01297         theList.push_back( string( theDbRef.name( )));
01298         theDictItr++;
01299     }
01300     delete theDict;
01301 
01302     return BdbcSuccess;
01303 }
01304 
01305 BdbStatus
01306 BdbCondDatabaseMgr::getDatabases( vector<string>&       theList,
01307                                   const vector<string>& theKeywordsList,
01308                                   const vector<string>& theDetectorsList,
01309                                   bool                                  theExcludeFlag )
01310 {
01311     const char* errorString = "BdbCondDatabaseMgr::getDatabases() -- ERROR.";
01312 
01313     BdbStatus status;
01314 
01315     theList.clear( );
01316 
01317   // Build the list of detectors.
01318 
01319     vector<string> theFinalDetectorsList;
01320 
01321     status = selectDetectors( theFinalDetectorsList, theDetectorsList, theExcludeFlag );
01322     if( BdbcSuccess != status ) {
01323         ErrMsg(error) << errorString << endl
01324                       << "    Failed to build a list of detectors to be scanned." << endmsg;
01325         return status;
01326     }
01327 
01328   // Iterate through the final list of detectors.
01329 
01330     vector<string>                     theContainers;
01331     map<string, BdbRef(ooDBObj)>* theDict;
01332     theDict = new map<string, BdbRef(ooDBObj)>;
01333 
01334     int detectors = theFinalDetectorsList.size( );
01335     for( int detectorIndex = 0; detectorIndex < detectors; detectorIndex++ ) {
01336 
01337       // List all the containers in this detector.
01338 
01339         BdbObsoleteDatabase theDb( theFinalDetectorsList[detectorIndex].c_str() );
01340 
01341         theContainers.clear( );
01342         theDb.listAllClasses( theContainers );
01343 
01344       // Iterate through the list of containers.
01345 
01346         int containers = theContainers.size( );
01347         for( int containerIndex = 0; containerIndex < containers; containerIndex++ ) {
01348 
01349           // If the list of keywords is non-empty then match the keywords
01350           // in a container name.
01351 
01352             if( ! theKeywordsList.empty( )) {
01353 
01354               // Just skip a container if it does not have none of specified
01355               // keywords.
01356 
01357                 bool keywordWasFound = false;
01358 
01359                 int keywords = theKeywordsList.size( );
01360                 for( int keywordIndex = 0; keywordIndex < keywords; keywordIndex++ ) {
01361                     if( theContainers[containerIndex].find( theKeywordsList[keywordIndex] )!=string::npos) {
01362                         keywordWasFound = true;
01363                         break;
01364                     }
01365                 }
01366                 if( ! keywordWasFound ) {
01367                     continue;
01368                 }
01369             }
01370 
01371           // Run the container scanner.
01372 
01373             status = scanContainer( *theDict, theDb, theContainers[containerIndex].c_str() );
01374             if( BdbcSuccess != status ) {
01375                 ErrMsg(error) << errorString << endl
01376                               << "    Failed to obtain databases to be referenced through the container." << endl
01377                               << "        DETECTOR  -> " << theFinalDetectorsList[detectorIndex] << endl
01378                               << "        CONTAINER -> " << theContainers[containerIndex] << endmsg;
01379                 delete theDict;
01380                 return status;
01381             }
01382         }
01383     }
01384 
01385   // Now browse the hash dictionary and get the system name of each database
01386   // found in there.
01387 
01388     map<string, BdbRef(ooDBObj)>::iterator theDictItr=theDict->begin();
01389     BdbRef(ooDBObj) theDbRef;
01390 
01391     while( theDictItr!=theDict->end( )) {
01392         theDbRef = theDictItr->second;
01393         theList.push_back( string( theDbRef.name( )));
01394         theDictItr++;
01395     }
01396     delete theDict;
01397 
01398     return BdbcSuccess;
01399 }
01400 
01401 BdbStatus
01402 BdbCondDatabaseMgr::getContainers( map<string, vector<string> >& theDict,
01403                                    const vector<string>&                             theKeywordsList,
01404                                    const vector<string>&                             theDetectorsList,
01405                                    bool                                                              theExcludeFlag )
01406 {
01407     const char* errorString = "BdbCondDatabaseMgr::getContainers() -- error.";
01408 
01409     BdbStatus status;
01410 
01411     theDict.clear( );
01412 
01413   // Build the list of detectors.
01414 
01415     vector<string> theFinalDetectorsList;
01416 
01417     status = selectDetectors( theFinalDetectorsList, theDetectorsList, theExcludeFlag );
01418     if( BdbcSuccess != status ) {
01419         ErrMsg(error) << errorString << endl
01420                       << "    Failed to build a list of detectors to be scanned." << endmsg;
01421         return status;
01422     }
01423 
01424   // Iterate through the final list of detectors.
01425   // Our goal is to build a hash dictionary where the database is a key
01426   // and list of containers are the values of the dictionary.
01427 
01428     vector<string> theContainers;
01429     vector<string> theDatabases;
01430 
01431     int detectors = theFinalDetectorsList.size( );
01432     for( int detectorIndex = 0; detectorIndex < detectors; detectorIndex++ ) {
01433 
01434       // List all the containers in this detector.
01435 
01436         BdbObsoleteDatabase theDb( theFinalDetectorsList[detectorIndex].c_str() );
01437 
01438         theContainers.clear( );
01439 
01440         theDb.listAllClasses( theContainers );
01441 
01442       // Iterate through the list of containers.
01443 
01444         int containers = theContainers.size( );
01445         for( int containerIndex = 0; containerIndex < containers; containerIndex++ ) {
01446 
01447           // If the list of keywords is non-empty then match the keywords
01448           // in a container name.
01449 
01450             if( ! theKeywordsList.empty( )) {
01451 
01452               // Just skip a container if it does not have none of specified
01453               // keywords.
01454 
01455                 bool keywordWasFound = false;
01456 
01457                 int keywords = theKeywordsList.size( );
01458                 for( int keywordIndex = 0; keywordIndex < keywords; keywordIndex++ ) {
01459                     if( theContainers[containerIndex].find( theKeywordsList[keywordIndex])!=string::npos ) {
01460                         keywordWasFound = true;
01461                         break;
01462                     }
01463                 }
01464                 if( ! keywordWasFound ) {
01465                     continue;
01466                 }
01467             }
01468 
01469           // Get a list of databases for a container.
01470 
01471             status = getDatabasesForContainer( theDatabases,
01472                                                theFinalDetectorsList[detectorIndex].c_str(),
01473                                                theContainers[containerIndex].c_str() );
01474             if( BdbcSuccess != status ) {
01475                 ErrMsg(error) << errorString << endl
01476                               << "    Failed to obtain a list of databases for specified container." << endmsg;
01477                 return BdbcError;
01478             }
01479 
01480           // Iterate over all the databases associated to given container,
01481 
01482             int databases = theDatabases.size( );
01483             for( int databaseIndex = 0; databaseIndex < databases; databaseIndex++ ) {
01484                 theDict[theDatabases[databaseIndex]].push_back( theFinalDetectorsList[detectorIndex] +
01485                                                              string( " " ) +
01486                                                              theContainers[containerIndex] );
01487             }
01488         }
01489     }
01490 
01491     return BdbcSuccess;
01492 }
01493 
01494 BdbStatus
01495 BdbCondDatabaseMgr::getClasses( map<string, int>& theDict,
01496                                 const char*                           theTLA,
01497                                 const char*                           theContName )
01498 {
01499     const char* errorString = "BdbCondDatabaseMgr::getClasses() -- error.";
01500 
01501     BdbStatus status;
01502 
01503     assert( theTLA      != (const char*) 0 );
01504     assert( theContName != (const char*) 0 );
01505 
01506     theDict.clear( );
01507 
01508   // Prepare the data structures.
01509 
01510     BdbObsoleteDatabase theDb( theTLA );
01511 
01512     BdbHandle(BdbInterval) theIntervalH;
01513     BdbHandle(BdbInterval) theNextIntervalH;
01514     BdbHandle(BdbObject)   theObjectH;
01515 
01516     string name;
01517 
01518   // Extract the class names from the objects (if they are non-zero)
01519   // and put them into the hash dictionary as pesistent references.
01520 
01521     status = theDb.firstInterval( theIntervalH, theContName );
01522     if(( BdbcSuccess != status ) || BdbIsNull(theIntervalH)) {
01523         ErrMsg(error) << errorString << endl
01524                       << "    Failed to obtain the FIRST interval from the container." << endl
01525                       << "        DETECTOR  -> " << theDb.subsystemTLA( ) << endl
01526                       << "        CONTAINER -> " << theContName << endmsg;
01527         return BdbcError;
01528     }
01529 
01530   // Take the version trees one-by-one starting from the very first interval.
01531   // Each next tree will be accessed following the "next TOPMOST"
01532   // link until NULL interval is met.
01533 
01534   // Analyze the FIRST interval itself.
01535 
01536     theObjectH = theIntervalH->getObject( );
01537     if( ! BdbIsNull(theObjectH)) {
01538         if( theObjectH.isValid( )) {
01539             name = theObjectH.typeName( );
01540         } else {
01541             name = "???";
01542         }
01543         if( theDict.find( name )!=theDict.end()) {
01544             theDict[name]++;
01545         } else {
01546             theDict[name] = 1;
01547         }
01548     }
01549 
01550   // Then start working with trees.
01551 
01552     vector<BdbHandle(BdbInterval)> theTree;
01553     int numBranches;
01554 
01555     do {
01556 
01557       // Avoid a problem of "zero" [-oo,-oo] FIRST interval because the next
01558       // interval would also start from [-oo, *]. And this introduces some
01559       // ambiguity into the interval locating algorithm.
01560       // Check also the correct structure of the next interval.
01561 
01562         if( BdbTime::minusInfinity == theIntervalH->endTime( )) {
01563 
01564             theNextIntervalH = theIntervalH->next( );
01565             theIntervalH     = theNextIntervalH;
01566 
01567             if( theIntervalH->beginTime( ) == theIntervalH->endTime( )) {
01568                 ErrMsg(error) << errorString << endl
01569                               << "    The invalid interval found in the container." << endl
01570                               << "        BEGIN TIME -> " << theIntervalH->beginTime( ) << endl
01571                               << "        END TIME   -> " << theIntervalH->endTime( ) << endl
01572                               << "        DETECTOR   -> " << theDb.subsystemTLA( ) << endl
01573                               << "        CONTAINER  -> " << theContName << endmsg;
01574                 return BdbcError;
01575             }
01576             status = theDb.getTree( theTree, numBranches, theContName, theIntervalH->beginTime( ) + 1 );
01577         } else {
01578             status = theDb.getTree( theTree, numBranches, theContName, theIntervalH->beginTime( ));
01579         }
01580         if(( BdbcSuccess != status ) || ( numBranches <= 0 )) {
01581             ErrMsg(error) << errorString << endl
01582                           << "    Failed to obtain the version tree from the container." << endl
01583                           << "        BEGIN TIME -> " << theIntervalH->beginTime( ) << endl
01584                           << "        DETECTOR   -> " << theDb.subsystemTLA( ) << endl
01585                           << "        CONTAINER  -> " << theContName << endmsg;
01586             return BdbcError;
01587         }
01588 
01589         int entries = theTree.size( );
01590         for( int i = 0; i < entries; i++ ) {
01591 
01592           // Skip NULL delimiters.
01593 
01594             if( ! BdbIsNull(theTree[i])) {
01595 
01596                 theIntervalH = theTree[i];
01597 
01598                 theObjectH = theIntervalH->getObject( );
01599                 if( ! BdbIsNull(theObjectH)) {
01600                     if( theObjectH.isValid( )) {
01601                         name = theObjectH.typeName( );
01602                     } else {
01603                         name = "???";
01604                     }
01605                     if( theDict.find( name )!=theDict.end()) {
01606                         theDict[name]++;
01607                     } else {
01608                         theDict[name] = 1;
01609                     }
01610                 }
01611             }
01612         }
01613 
01614         theNextIntervalH = theIntervalH->next( );
01615         theIntervalH     = theNextIntervalH;
01616 
01617     } while( ! BdbIsNull(theIntervalH));
01618 
01619 
01620     return BdbcSuccess;
01621 }
01622 
01623 BdbStatus
01624 BdbCondDatabaseMgr::validateContainer( vector<BdbHandle(BdbInterval)>& theList,
01625                                        const char*                                  theTLA,
01626                                        const char*                                  theContName )
01627 {
01628     const char* errorString = "BdbCondDatabaseMgr::getDatabasesForContainer() -- error.";
01629 
01630     BdbStatus status;
01631 
01632     assert( theTLA      != (const char*) 0 );
01633     assert( theContName != (const char*) 0 );
01634 
01635     theList.clear( );
01636 
01637   // Prepare the data structures.
01638 
01639     BdbObsoleteDatabase theDb( theTLA );
01640     BdbHandle(BdbInterval) theIntervalH;
01641     BdbHandle(BdbInterval) theNextIntervalH;
01642     BdbHandle(BdbObject)   theObjectH;
01643 
01644   // Validate objects (if they are non-zero) and if they are not
01645   // - put the corresponding interval into the list as pesistent references.
01646 
01647     status = theDb.firstInterval( theIntervalH, theContName );
01648     if(( BdbcSuccess != status ) || BdbIsNull(theIntervalH)) {
01649         ErrMsg(error) << errorString << endl
01650                       << "    Failed to obtain the FIRST interval from the container." << endl
01651                       << "        DETECTOR  -> " << theDb.subsystemTLA( ) << endl
01652                       << "        CONTAINER -> " << theContName << endmsg;
01653         return BdbcError;
01654     }
01655 
01656   // Take the version trees one-by-one starting from the very first interval.
01657   //
01658   // Each next tree will be accessed following the "next TOPMOST"
01659   // link until NULLinterval is met.
01660 
01661   // Analyze the FIRST interval itself.
01662 
01663     theObjectH = theIntervalH->getObject( );
01664     if( ! BdbIsNull(theObjectH)) {
01665         if( ! theObjectH.isValid( )) {
01666             theList.push_back( theIntervalH );
01667         }
01668     }
01669 
01670   // Then start working with trees.
01671 
01672     vector<BdbHandle(BdbInterval)> theTree;
01673     int numBranches;
01674 
01675     do {
01676 
01677       // Avoid a problem of "zero" [-oo,-oo] FIRST interval because the next
01678       // interval would also start from [-oo, *]. And this introduces some
01679       // ambiguity into the interval locating algorithm.
01680       // Check also the correct structure of the next interval.
01681 
01682         if( BdbTime::minusInfinity == theIntervalH->endTime( )) {
01683 
01684             theNextIntervalH = theIntervalH->next( );
01685             theIntervalH     = theNextIntervalH;
01686 
01687             if( theIntervalH->beginTime( ) == theIntervalH->endTime( )) {
01688                 ErrMsg(error) << errorString << endl
01689                               << "    The invalid interval found in the container." << endl
01690                               << "        BEGIN TIME -> " << theIntervalH->beginTime( ) << endl
01691                               << "        END TIME   -> " << theIntervalH->endTime( ) << endl
01692                               << "        DETECTOR   -> " << theDb.subsystemTLA( ) << endl
01693                               << "        CONTAINER  -> " << theContName << endmsg;
01694                 return BdbcError;
01695             }
01696             status = theDb.getTree( theTree, numBranches, theContName, theIntervalH->beginTime( ) + 1 );
01697         } else {
01698             status = theDb.getTree( theTree, numBranches, theContName, theIntervalH->beginTime( ));
01699         }
01700         if(( BdbcSuccess != status ) || ( numBranches <= 0 )) {
01701             ErrMsg(error) << errorString << endl
01702                           << "    Failed to obtain the version tree from the container." << endl
01703                           << "        BEGIN TIME -> " << theIntervalH->beginTime( ) << endl
01704                           << "        DETECTOR   -> " << theDb.subsystemTLA( ) << endl
01705                           << "        CONTAINER  -> " << theContName << endmsg;
01706             return BdbcError;
01707         }
01708 
01709         int entries = theTree.size( );
01710         for( int i = 0; i < entries; i++ ) {
01711 
01712           // Skip NULL delimiters.
01713 
01714             if( ! BdbIsNull(theTree[i])) {
01715 
01716                 theIntervalH = theTree[i];
01717 
01718                 theObjectH = theIntervalH->getObject( );
01719                 if( ! BdbIsNull(theObjectH)) {
01720                     if( ! theObjectH.isValid( )) {
01721                         theList.push_back( theIntervalH );
01722                     }
01723                 }
01724             }
01725         }
01726 
01727         theNextIntervalH = theIntervalH->next( );
01728         theIntervalH     = theNextIntervalH;
01729 
01730     } while( ! BdbIsNull(theIntervalH));
01731 
01732     return BdbcSuccess;
01733 }
01734 
01735 BdbStatus
01736 BdbCondDatabaseMgr::mergeIntervalContainers( const char*    theInTLA,
01737                                              const char*    theInContName,
01738                                              const char*    theOutTLA,
01739                                              const char*    theOutContName,
01740                                              const BdbTime& theMergeTime,
01741                                              bool           mergeToLeft,
01742                                              bool           verifyOnly )
01743 {
01744     const char* errorString = "BdbCondDatabaseMgr::mergeIntervalContainers() -- error.";
01745 
01746     BdbStatus status = BdbcError;
01747 
01748     assert( theInTLA       != (char*) 0 );
01749     assert( theInContName  != (char*) 0 );
01750     assert( theOutTLA      != (char*) 0 );
01751     assert( theOutContName != (char*) 0 );
01752 
01753   // Open both databases.
01754 
01755     BdbObsoleteDatabase theInDb( theInTLA );
01756     BdbObsoleteDatabase theOutDb( theOutTLA );
01757 
01758   // Intervals intervals at a merging point. These are obtained during
01759   // an evaluaton of a merge point/time and then they will be used for
01760   // merging.
01761 
01762     BdbHandle(BdbIntervalR) theInLeftBaselineIntervalH;
01763     BdbHandle(BdbIntervalR) theInRightBaselineIntervalH;
01764     BdbHandle(BdbIntervalR) theOutLeftBaselineIntervalH;
01765     BdbHandle(BdbIntervalR) theOutRightBaselineIntervalH;
01766 
01767   // Perform operations in a exception-like loop.
01768 
01769     bool operationsLoopWasFailed = true;
01770 
01771     while ( true ) {
01772 
01773       // Locate both containers - they must exist.
01774       // Check if it's not the same container.
01775 
01776         BdbHandle(BdbContObj) theInContH;
01777         status = theInDb.findIntervalCont( theInContH, theInContName );
01778         if (( BdbcSuccess != status ) || ( BdbIsNull( theInContH ))) {
01779             ErrMsg(error) << errorString << endl
01780                           << "    The input container does not exist in the database." << endmsg;
01781             break;
01782         }
01783 
01784         BdbHandle(BdbContObj) theOutContH;
01785         status = theOutDb.findIntervalCont( theOutContH, theOutContName );
01786         if (( BdbcSuccess != status ) || ( BdbIsNull( theOutContH ))) {
01787             ErrMsg(error) << errorString << endl
01788                           << "    The output container does not exist in the database." << endmsg;
01789             break;
01790         }
01791 
01792         if ( theInContH == theOutContH ) {
01793             ErrMsg(error) << errorString << endl
01794                           << "    An attempt to merge a container with itself." << endmsg;
01795             break;
01796         }
01797 
01798       // Check if specified merge time meets criteria.
01799       //
01800       // NOTE: An essential side effect of this operation is also a set of baseline
01801       //       intervals in both containers, which correspond to the merging point.
01802 
01803         status = evaluateMergePoint( theInDb,
01804                                      theOutDb,
01805                                      theMergeTime,
01806                                      theInLeftBaselineIntervalH,
01807                                      theInRightBaselineIntervalH,
01808                                      theOutLeftBaselineIntervalH,
01809                                      theOutRightBaselineIntervalH );
01810         if ( BdbcSuccess != status ) {
01811             ErrMsg(error) << errorString << endl
01812                           << "    This time can not be used as the merge point. See detailes above." << endmsg;
01813             break;
01814         }
01815 
01816       // Print algorithm DEBUG info if it's just a verification path.
01817 
01818         if ( verifyOnly ) {
01819 
01820             ErrMsg(routine) << "EVALUATE MERGE POINT: most important intervals." << endl
01821                             << endl
01822                             << "    theInLeftBaselineIntervalH   = " << getOID( theInLeftBaselineIntervalH ) << endl
01823                             << "    theInRightBaselineIntervalH  = " << getOID( theInRightBaselineIntervalH ) << endl
01824                             << endl
01825                             << "    theOutLeftBaselineIntervalH  = " << getOID( theOutLeftBaselineIntervalH ) << endl
01826                             << "    theOutRightBaselineIntervalH = " << getOID( theOutRightBaselineIntervalH ) << endl
01827                             << endmsg;
01828         }
01829 
01830       // Compare revisions, assuming their partial equivalence (pay attention
01831       // to the third parameter of the comparision method), which means
01832       // that the input set of revisions is a true subset of the output one.
01833       // We also assume that matching revisions must be structurally equivalent
01834       // (the forth parameter is set to false) rather then have the same contents.
01835 
01836         status = compareRevisions( theInDb, theOutDb, false, false );
01837         if ( BdbcSuccess != status ) {
01838             ErrMsg(error) << errorString << endl
01839                           << "    The revisions are incompatible for merging. See detailes above." << endmsg;
01840             break;
01841         }
01842 
01843       // Do not proceed further if it's just a trial (verification) path.
01844 
01845         if ( ! verifyOnly ) {
01846 
01847           // Now we are about to begin the merging...
01848 
01849             if ( mergeToLeft ) {
01850 
01851               // Put a record for the "history" into an output container.
01852 
01853                 theOutDb.historyCMerge( rcsid, BdbTime::minusInfinity, theMergeTime );
01854 
01855               // And then begin merging...
01856 
01857                 status = mergeLeftFromBaseline( theInDb,
01858                                                 theOutDb,
01859                                                 theInLeftBaselineIntervalH,
01860                                                 theInRightBaselineIntervalH,
01861                                                 theOutLeftBaselineIntervalH,
01862                                                 theOutRightBaselineIntervalH );
01863                 if ( BdbcSuccess != status ) break;
01864 
01865             } else {
01866 
01867               // Yet to be implemented.
01868 
01869                 ErrMsg(error) << errorString << endl
01870                               << "    Merging to the right side of the output container is not" << endl
01871                               << "    implemented in this code." << endmsg;
01872                 break;
01873             }
01874         }
01875 
01876       // The loop has been sucessfully completed.
01877 
01878         operationsLoopWasFailed = false;
01879         break;
01880     }
01881     if ( operationsLoopWasFailed ) {
01882         ErrMsg(error) << "        INPUT   DETECTOR: \"" << theInTLA << "\"" << endl
01883                       << "               CONTAINER: \"" << theInContName << "\"" << endl
01884                       << "        OUTPUT  DETECTOR: \"" << theOutTLA << "\"" << endl
01885                       << "               CONTAINER: \"" << theOutContName << "\"" << endmsg;
01886         return BdbcError;
01887     }
01888 
01889     return BdbcSuccess;
01890 }
01891 
01892 BdbStatus
01893 BdbCondDatabaseMgr::mergeIntervalContainers( const char*    theInTLA,
01894                                              const char*    theInContName,
01895                                              const char*    theOutTLA,
01896                                              const char*    theOutContName,
01897                                              const BdbTime& theBeginMergeTime,
01898                                              const BdbTime& theEndMergeTime,
01899                                              bool           mergeInner,
01900                                              bool           verifyOnly )
01901 {
01902     const char* errorString = "BdbCondDatabaseMgr::mergeIntervalContainers() -- error.";
01903 
01904     BdbStatus status = BdbcError;
01905 
01906     assert( theInTLA       != (char*) 0 );
01907     assert( theInContName  != (char*) 0 );
01908     assert( theOutTLA      != (char*) 0 );
01909     assert( theOutContName != (char*) 0 );
01910 
01911   // Open both databases.
01912 
01913     BdbObsoleteDatabase theInDb( theInTLA );
01914     BdbObsoleteDatabase theOutDb( theOutTLA );
01915 
01916   // Intervals intervals at a merging point. These are obtained during
01917   // an evaluaton of a merge point/time and then they will be used for
01918   // merging.
01919 
01920     BdbHandle(BdbIntervalR) theInBeginLeftBaselineIntervalH;
01921     BdbHandle(BdbIntervalR) theInBeginRightBaselineIntervalH;
01922     BdbHandle(BdbIntervalR) theInEndLeftBaselineIntervalH;
01923     BdbHandle(BdbIntervalR) theInEndRightBaselineIntervalH;
01924 
01925     BdbHandle(BdbIntervalR) theOutBeginLeftBaselineIntervalH;
01926     BdbHandle(BdbIntervalR) theOutBeginRightBaselineIntervalH;
01927     BdbHandle(BdbIntervalR) theOutEndLeftBaselineIntervalH;
01928     BdbHandle(BdbIntervalR) theOutEndRightBaselineIntervalH;
01929 
01930   // Perform operations in a exception-like loop.
01931 
01932     bool operationsLoopWasFailed = true;
01933 
01934     while ( true ) {
01935 
01936       // Locate both containers - they must exist.
01937       // Check if it's not the same container.
01938 
01939         BdbHandle(BdbContObj) theInContH;
01940         status = theInDb.findIntervalCont( theInContH, theInContName );
01941         if (( BdbcSuccess != status ) || ( BdbIsNull( theInContH ))) {
01942             ErrMsg(error) << errorString << endl
01943                           << "    The input container does not exist in the database." << endmsg;
01944             break;
01945         }
01946 
01947         BdbHandle(BdbContObj) theOutContH;
01948         status = theOutDb.findIntervalCont( theOutContH, theOutContName );
01949         if (( BdbcSuccess != status ) || ( BdbIsNull( theOutContH ))) {
01950             ErrMsg(error) << errorString << endl
01951                           << "    The output container does not exist in the database." << endmsg;
01952             break;
01953         }
01954 
01955         if ( theInContH == theOutContH ) {
01956             ErrMsg(error) << errorString << endl
01957                           << "    An attempt to merge a container with itself." << endmsg;
01958             break;
01959         }
01960 
01961         if (( BdbTime::minusInfinity == theBeginMergeTime ) ||
01962             ( BdbTime::plusInfinity  == theEndMergeTime   ) ||
01963             ( theBeginMergeTime >= theEndMergeTime )) {
01964             ErrMsg(error) << errorString << endl
01965                           << "    Incorrect validity time limits for the merging area were specified ." << endl
01966                           << "    Neither of these values should equal to (any) \"infinity\"." << endl
01967                           << "    The begin time must be more than (but not equal to) the end time." << endmsg;
01968             break;
01969         }
01970 
01971       // Check if specified merge time points meet criteria.
01972       //
01973       // NOTE: An essential side effect of this operation is also a set of baseline
01974       //       intervals in both containers, which correspond to the merging point.
01975 
01976         status = evaluateMergePoint( theInDb,
01977                                      theOutDb,
01978                                      theBeginMergeTime,
01979                                      theInBeginLeftBaselineIntervalH,
01980                                      theInBeginRightBaselineIntervalH,
01981                                      theOutBeginLeftBaselineIntervalH,
01982                                      theOutBeginRightBaselineIntervalH );
01983         if ( BdbcSuccess != status ) {
01984             ErrMsg(error) << errorString << endl
01985                           << "    The begin merge time can not be used as the merge point. See detailes above." << endmsg;
01986             break;
01987         }
01988         status = evaluateMergePoint( theInDb,
01989                                      theOutDb,
01990                                      theEndMergeTime,
01991                                      theInEndLeftBaselineIntervalH,
01992                                      theInEndRightBaselineIntervalH,
01993                                      theOutEndLeftBaselineIntervalH,
01994                                      theOutEndRightBaselineIntervalH );
01995         if ( BdbcSuccess != status ) {
01996             ErrMsg(error) << errorString << endl
01997                           << "    The end merg time can not be used as the merge point. See detailes above." << endmsg;
01998             break;
01999         }
02000 
02001       // Print algorithm DEBUG info if it's just a verification path.
02002 
02003         if ( verifyOnly ) {
02004 
02005             ErrMsg(routine) << "EVALUATE MERGE POINT: most important intervals." << endl
02006                             << endl
02007                             << "    theInBeginLeftBaselineIntervalH   = " << getOID( theInBeginLeftBaselineIntervalH ) << endl
02008                             << "    theInBeginRightBaselineIntervalH  = " << getOID( theInBeginRightBaselineIntervalH ) << endl
02009                             << "    theInEndLeftBaselineIntervalH     = " << getOID( theInEndLeftBaselineIntervalH ) << endl
02010                             << "    theInEndRightBaselineIntervalH    = " << getOID( theInEndRightBaselineIntervalH ) << endl
02011                             << endl
02012                             << "    theOutBeginLeftBaselineIntervalH  = " << getOID( theOutBeginLeftBaselineIntervalH ) << endl
02013                             << "    theOutBeginRightBaselineIntervalH = " << getOID( theOutBeginRightBaselineIntervalH ) << endl
02014                             << "    theOutEndLeftBaselineIntervalH    = " << getOID( theOutEndLeftBaselineIntervalH ) << endl
02015                             << "    theOutEndRightBaselineIntervalH   = " << getOID( theOutEndRightBaselineIntervalH ) << endl
02016                             << endmsg;
02017         }
02018 
02019       // Compare revisions, assuming their partial equivalence (pay attention
02020       // to the third parameter of the comparision method), which means
02021       // that the input set of revisions is a true subset of the output one.
02022       // We also assume that matching revisions must be structurally equivalent
02023       // (the forth parameter is set to false) rather then have the same contents.
02024 
02025         status = compareRevisions( theInDb, theOutDb, false, false );
02026         if ( BdbcSuccess != status ) {
02027             ErrMsg(error) << errorString << endl
02028                           << "    The revisions are incompatible for merging. See detailes above." << endmsg;
02029             break;
02030         }
02031 
02032       // Do not proceed further if it's just a trial (verification) path.
02033 
02034         if ( ! verifyOnly ) {
02035 
02036           // Now we are about to begin the merging...
02037 
02038             if ( mergeInner ) {
02039 
02040               // Put a record for the "history" into an output container.
02041 
02042                 theOutDb.historyCMerge( rcsid, theBeginMergeTime, theEndMergeTime );
02043 
02044               // And then begin merging...
02045 
02046                 status = mergeInnerFromBaseline( theInDb,
02047                                                  theOutDb,
02048                                                  theInBeginLeftBaselineIntervalH,
02049                                                  theInBeginRightBaselineIntervalH,
02050                                                  theInEndLeftBaselineIntervalH,
02051                                                  theInEndRightBaselineIntervalH,
02052                                                  theOutBeginLeftBaselineIntervalH,
02053                                                  theOutBeginRightBaselineIntervalH,
02054                                                  theOutEndLeftBaselineIntervalH,
02055                                                  theOutEndRightBaselineIntervalH );
02056                 if ( BdbcSuccess != status ) break;
02057 
02058             } else {
02059 
02060               // Yet to be implemented.
02061 
02062                 ErrMsg(error) << errorString << endl
02063                               << "    Merging to the outer part of the output container is not" << endl
02064                               << "    implemented in this code." << endmsg;
02065                 break;
02066             }
02067         }
02068 
02069       // The loop has been sucessfully completed.
02070 
02071         operationsLoopWasFailed = false;
02072         break;
02073     }
02074     if ( operationsLoopWasFailed ) {
02075         ErrMsg(error) << "        INPUT   DETECTOR: \"" << theInTLA << "\"" << endl
02076                       << "               CONTAINER: \"" << theInContName << "\"" << endl
02077                       << "        OUTPUT  DETECTOR: \"" << theOutTLA << "\"" << endl
02078                       << "               CONTAINER: \"" << theOutContName << "\"" << endmsg;
02079         return BdbcError;
02080     }
02081 
02082     return BdbcSuccess;
02083 }
02084 
02085 BdbStatus
02086 BdbCondDatabaseMgr::evaluateMergePoint( BdbObsoleteDatabase&             theInDb,
02087                                         BdbObsoleteDatabase&             theOutDb,
02088                                         const BdbTime&           theMergeTime,
02089                                         BdbHandle(BdbIntervalR)& theInLeftBaselineIntervalH,
02090                                         BdbHandle(BdbIntervalR)& theInRightBaselineIntervalH,
02091                                         BdbHandle(BdbIntervalR)& theOutLeftBaselineIntervalH,
02092                                         BdbHandle(BdbIntervalR)& theOutRightBaselineIntervalH )
02093 {
02094     const char* errorString = "BdbCondDatabaseMgr::evaluateMergePoint() -- error.";
02095 
02096     BdbStatus status = BdbcError;
02097 
02098   // NULL-ify results.
02099 
02100     theInLeftBaselineIntervalH   = 0;
02101     theInRightBaselineIntervalH  = 0;
02102     theOutLeftBaselineIntervalH  = 0;
02103     theOutRightBaselineIntervalH = 0;
02104 
02105   // A very trivial check for the merging time.
02106 
02107     if ( theMergeTime <= BdbTime::minusInfinity ||
02108          theMergeTime >= BdbTime::plusInfinity ) {
02109         ErrMsg(error) << errorString << endl
02110                       << "    Incorrect merging time was specified: " << theMergeTime << endl
02111                       << "    It can not be infinite (either negative or positive)." << endmsg;
02112         return BdbcError;
02113     }
02114 
02115   // Locate and verify baseline intervals in both conatiners.
02116 
02117     status = locateBaselineIntervals( theInLeftBaselineIntervalH,
02118                                       theInRightBaselineIntervalH,
02119                                       theInDb,
02120                                       theMergeTime );
02121     if ( BdbcSuccess != status ) return status;
02122 
02123     status = locateBaselineIntervals( theOutLeftBaselineIntervalH,
02124                                       theOutRightBaselineIntervalH,
02125                                       theOutDb,
02126                                       theMergeTime );
02127     if ( BdbcSuccess != status ) return status;
02128 
02129   // Evalueate the merge point.
02130   //
02131   // The merge point is considered valid if it falls into a border between
02132   // two baseline intervals at both containers.
02133   //
02134   //         the merge time
02135   //               :
02136   //               v
02137   // -----+--------+--------+-----
02138   //  ... | Left   |  Right | ...
02139   // -----+--------+--------+-----
02140   //
02141   // In this case the handle to the left interval will not be NULL.
02142 
02143     if ( BdbIsNull(theInLeftBaselineIntervalH) || BdbIsNull(theOutLeftBaselineIntervalH)) {
02144         ErrMsg(error) << errorString << endl
02145                       << "    PROBLEM:    The merge time does not fall exactly onto a border between" << endl
02146                       << "                two baseline intervals in one (or both) containers." << endl
02147                       << "    REASON:     Containers may have different structure of baseline intervals" << endl
02148                       << "                at a point of merging." << endl
02149                       << "    CONCLUSION: Merging is not possible." << endmsg;
02150         return BdbcError;
02151     }
02152 
02153     return BdbcSuccess;
02154 }
02155 
02156 BdbStatus
02157 BdbCondDatabaseMgr::locateBaselineIntervals( BdbHandle(BdbIntervalR)& theLeftBaselineIntervalH,
02158                                              BdbHandle(BdbIntervalR)& theRightBaselineIntervalH,
02159                                              BdbObsoleteDatabase&             theDb,
02160                                              const BdbTime&           theMergeTime )
02161 {
02162     const char* errorString = "BdbCondDatabaseMgr::locateBaselineIntervals() -- error.";
02163 
02164     BdbStatus status = BdbcError;
02165 
02166     theLeftBaselineIntervalH  = 0;
02167     theRightBaselineIntervalH = 0;
02168 
02169   // Get the right interval.
02170 
02171     status = theDb.getBaselineInterval( theRightBaselineIntervalH, theDb.containerName( ), theMergeTime );
02172     if ( BdbcSuccess != status ) {
02173         ErrMsg(error) << errorString << endl
02174                       << "    Failed to locate RIGHT baseline interval for the merge time:" << theMergeTime << endmsg;
02175         return BdbcError;
02176     }
02177 
02178   // Get the left baseline interval only if the merge time is exactly
02179   // on the border between baseline intervals.
02180 
02181     theLeftBaselineIntervalH = 0;
02182     if ( theRightBaselineIntervalH->beginTime( ) == theMergeTime ) {
02183         theRightBaselineIntervalH->getBaselinePrevious( theLeftBaselineIntervalH );
02184     }
02185 
02186     return BdbcSuccess;
02187 }
02188 
02189 BdbStatus
02190 BdbCondDatabaseMgr::compareRevisions( BdbObsoleteDatabase& theInDb,
02191                                       BdbObsoleteDatabase& theOutDb,
02192                                       bool         exactEquivalence,
02193                                       bool         equalContensVsStructure )
02194 {
02195     const char* errorString = "BdbCondDatabaseMgr::compareRevisions() -- error.";
02196 
02197     BdbStatus status = BdbcError;
02198 
02199   // Get the handles to Registries, assuming that the proper context
02200   // of the passed access classes has been properly set.
02201 
02202     BdbHandle(BdbCondRegistry) theInRegistryH;
02203     BdbHandle(BdbCondRegistry) theOutRegistryH;
02204 
02205     theInDb.getRegistryH( theInRegistryH );
02206     theOutDb.getRegistryH( theOutRegistryH );
02207 
02208     if ( BdbIsNull(theInRegistryH) || BdbIsNull(theOutRegistryH)) {
02209         ErrMsg(error) << errorString << endl
02210                       << "    This function has been called in a proper context." << endl
02211                       << "    It looks like an internal bug has been encountered." << endmsg;
02212         return BdbcError;
02213     }
02214 
02215   // Iterate over all known revisions in both containers and compare
02216   // them one-by-one.
02217   //
02218   // Depending on the comparision mode, we may require either "exact" equivalence
02219   // (when both Registries have similar revisions) or "partial" equivalence (when
02220   // the input Registry has a subset of revisions only).
02221   //
02222   // NOTE: Two revisions are considered as equal if their contents and the number
02223   //       its base revisions are equal.
02224 
02225     BdbHandle(BdbCondRevision) theInRevisionH;
02226     BdbHandle(BdbCondRevision) theOutRevisionH;
02227 
02228     BdbItr(BdbCondRevision) theInItr;
02229     BdbItr(BdbCondRevision) theOutItr;
02230 
02231     theInRegistryH->setRevisionItr( theInItr );
02232     theOutRegistryH->setRevisionItr( theOutItr );
02233 
02234     while ( theOutItr.next( )) {
02235 
02236         theOutRevisionH = theOutItr;
02237 
02238         if ( ! theInItr.next( )) {
02239             if ( exactEquivalence ) {
02240                 ErrMsg(error) << errorString << endl
02241                               << "    The list of revisions in the INPUT container is shorter" << endl
02242                               << "    then in the OUTPUT one." << endmsg;
02243                 return BdbcError;
02244             } else {
02245                 return BdbcSuccess; // Partial equivalence is OK.
02246             }
02247         }
02248         theInRevisionH = theInItr;
02249 
02250       // Compare revisions using specified method.
02251 
02252         if ( equalContensVsStructure ) {
02253             if ( ! theOutRevisionH->isEqualTo( theInRevisionH )) {
02254                 ErrMsg(error) << errorString << endl
02255                               << "    The lists of revisions in specified containers have" << endl
02256                               << "    revisions with non-equal contents." << endmsg;
02257                 return BdbcError;
02258             }
02259         } else {
02260             if ( ! theOutRevisionH->isSimilarTo( theInRevisionH )) {
02261                 ErrMsg(error) << errorString << endl
02262                               << "    The lists of revisions in specified containers have" << endl
02263                               << "    revisions which are non structurally equivalent." << endmsg;
02264                 return BdbcError;
02265             }
02266         }
02267     }
02268     if ( theInItr.next( )) {
02269         ErrMsg(error) << errorString << endl
02270                       << "    The list of revisions in the OUTPUT container is shorter" << endl
02271                       << "    then in the INPUT one." << endmsg;
02272         return BdbcError;
02273     }
02274 
02275     return BdbcSuccess;
02276 }
02277 
02278 BdbStatus
02279 BdbCondDatabaseMgr::mergeLeftFromBaseline( BdbObsoleteDatabase&             theInDb,
02280                                            BdbObsoleteDatabase&             theOutDb,
02281                                            BdbHandle(BdbIntervalR)& theInLeftBaselineIntervalH,
02282                                            BdbHandle(BdbIntervalR)& theInRightBaselineIntervalH,
02283                                            BdbHandle(BdbIntervalR)& theOutLeftBaselineIntervalH,
02284                                            BdbHandle(BdbIntervalR)& theOutRightBaselineIntervalH )
02285 {
02286     const char* errorString = "BdbCondDatabaseMgr::mergeLeftFromBaseline() -- error.";
02287 
02288     BdbStatus status = BdbcError;
02289 
02290   // Locate the "border" intervals in both containers.
02291 
02292     BdbHandle(BdbIntervalR) theInFirstIntervalH;
02293     BdbHandle(BdbIntervalR) theInLastIntervalH;
02294     BdbHandle(BdbIntervalR) theOutFirstIntervalH;
02295     BdbHandle(BdbIntervalR) theOutLastIntervalH;
02296 
02297     status = locateBorderIntervals( theInDb,
02298                                     theOutDb,
02299                                     theInFirstIntervalH,
02300                                     theInLastIntervalH,
02301                                     theOutFirstIntervalH,
02302                                     theOutLastIntervalH );
02303     if( BdbcSuccess != status ) return status;
02304 
02305   // Get the handles for the output container itself and its baseline
02306   // revision.
02307   // We expect that these values are cached by the previous procedure.
02308 
02309     BdbHandle(BdbContObj) theOutContH;
02310     theOutDb.getIntervalContH( theOutContH );
02311 
02312     BdbHandle(BdbCondRevision) theOutBaselineRevisionH;
02313     theOutDb.getBaselineRevisionH( theOutBaselineRevisionH );
02314 
02315   // Locate the topmost interval on the left side of the "right" baseline
02316   // interval of the output container. This will be needed later to connect
02317   // the last copied interval into there.
02318 
02319     BdbHandle(BdbIntervalR) theOutRightTopmostIntervalH;
02320 
02321     status = theOutDb.getTopmostInterval( theOutRightTopmostIntervalH,
02322                                           theOutDb.containerName( ),
02323                                           theOutRightBaselineIntervalH->beginTime( ));
02324     if ( BdbcSuccess != status ) return status;
02325 
02326   // Step I: Remove old intervals from the left side in the output container.
02327   //
02328   //   NOTE: Since a trivial obkectdeletion macro BdbDelete() does not delete
02329   //         vertical (child) versions of baseline intervals then we are using
02330   //         a special helper method deleteIntervalsInSubTree() to do this recursivly.
02331   //
02332   //         We also tell this deletetion method to delete the genealogy object
02333   //         as well.
02334 
02335     BdbHandle(BdbIntervalR) theBaselineIntervalH;
02336     BdbHandle(BdbIntervalR) thePrevBaselineIntervalH;
02337 
02338     theBaselineIntervalH = theOutLeftBaselineIntervalH;
02339     do {
02340         theBaselineIntervalH->getBaselinePrevious( thePrevBaselineIntervalH );
02341         deleteIntervalsInSubTree( theBaselineIntervalH, true );
02342         theBaselineIntervalH = thePrevBaselineIntervalH;
02343     } while ( ! BdbIsNull(theBaselineIntervalH));
02344 
02345   // Step II: Make a copy of the FIRST interval. We create this interval separately
02346   //          just because it's named in a different way (in the scope of the container).
02347 
02348     theOutFirstIntervalH = new( theOutContH ) BdbIntervalR( theInFirstIntervalH->getObject( ),
02349                                                             theInFirstIntervalH->getBeginTime( ),
02350                                                             theInFirstIntervalH->getEndTime( ),
02351                                                             theInFirstIntervalH->getTag( ));
02352     theOutFirstIntervalH->setVersionTime( theInFirstIntervalH->getVersionTime( ));
02353     theOutFirstIntervalH->setRevision( theOutBaselineRevisionH );
02354     theOutFirstIntervalH.nameObj( theOutContH, "FirstInterval" );
02355 
02356   // Step III: Make a copy of remaining baseline intervals until (excluding) the "right"
02357   //           baseline interval.
02358 
02359     BdbHandle(BdbIntervalR) theInPrevBaselineIntervalH;
02360     BdbHandle(BdbIntervalR) theInBaselineIntervalH;
02361     BdbHandle(BdbIntervalR) theOutPrevBaselineIntervalH;
02362     BdbHandle(BdbIntervalR) theOutBaselineIntervalH;
02363 
02364     theInPrevBaselineIntervalH  = theInFirstIntervalH;
02365     theOutPrevBaselineIntervalH = theOutFirstIntervalH;
02366 
02367     theInPrevBaselineIntervalH->getBaselineNext( theInBaselineIntervalH );
02368     while ( theInBaselineIntervalH != theInRightBaselineIntervalH ) {
02369 
02370         theOutBaselineIntervalH = new( theOutContH ) BdbIntervalR( theInBaselineIntervalH->getObject( ),
02371                                                                    theInBaselineIntervalH->getBeginTime( ),
02372                                                                    theInBaselineIntervalH->getEndTime( ),
02373                                                                    theInBaselineIntervalH->getTag( ));
02374 
02375         theOutBaselineIntervalH->setVersionTime( theInBaselineIntervalH->getVersionTime( ));
02376         theOutBaselineIntervalH->setRevision( theOutBaselineRevisionH );
02377 
02378         theOutPrevBaselineIntervalH->setTopNext( theOutBaselineIntervalH );
02379         theOutPrevBaselineIntervalH->setBaselineNext( theOutBaselineIntervalH );
02380 
02381         theOutBaselineIntervalH->setTopPrevious( theOutPrevBaselineIntervalH );
02382         theOutBaselineIntervalH->setBaselinePrevious( theOutPrevBaselineIntervalH );
02383 
02384         theOutPrevBaselineIntervalH = theOutBaselineIntervalH;
02385 
02386         theInPrevBaselineIntervalH = theInBaselineIntervalH;
02387         theInPrevBaselineIntervalH->getBaselineNext( theInBaselineIntervalH );
02388     }
02389 
02390     theOutPrevBaselineIntervalH->setTopNext( theOutRightTopmostIntervalH );
02391     theOutPrevBaselineIntervalH->setBaselineNext( theOutRightBaselineIntervalH );
02392 
02393     theOutRightTopmostIntervalH->setTopPrevious( theOutPrevBaselineIntervalH );
02394     theOutRightBaselineIntervalH->setBaselinePrevious( theOutPrevBaselineIntervalH );
02395 
02396   // Step IV: traverse baseline intervals and build the version trees.
02397   //          Copy information from the input intervals into output ones.
02398   //
02399   //    NOTE: the pointers (handles) in both containers advance
02400   //          along containers synchronosly (pay attention to the check
02401   //          after the "while" loop ends.
02402   //
02403   //          This operation lasts until (excluding) the "right" baseline interval.
02404 
02405     BdbHandle(BdbIntervalR) theInIntervalH;
02406     BdbHandle(BdbIntervalR) theInNextIntervalH;
02407     BdbHandle(BdbIntervalR) theOutIntervalH;
02408     BdbHandle(BdbIntervalR) theOutNextIntervalH;
02409 
02410     theInFirstIntervalH->getBaselineNext( theInIntervalH );
02411     theOutFirstIntervalH->getBaselineNext( theOutIntervalH );
02412 
02413     while( theInIntervalH != theInRightBaselineIntervalH ) {
02414 
02415         status = copySubTree( theInIntervalH,
02416                               theOutDb,
02417                               theOutIntervalH );
02418         if( BdbcSuccess != status ) {
02419             ErrMsg(error) << errorString << endl
02420                           << "    Failed to copy the next tree of versions." << endmsg;
02421             return status;
02422         }
02423 
02424         theInIntervalH->getBaselineNext( theInNextIntervalH );
02425         theInIntervalH = theInNextIntervalH;
02426 
02427         theOutIntervalH->getBaselineNext( theOutNextIntervalH );
02428         theOutIntervalH = theOutNextIntervalH;
02429     }
02430     if ( theOutIntervalH != theOutRightBaselineIntervalH ) {
02431         ErrMsg(error) << errorString << endl
02432                       << "    The output container has incorrect internal structure." << endmsg;
02433         return status;
02434     }
02435 
02436   // Step V: Connect the topmost intervals into the double linked list.
02437 
02438     BdbHandle(BdbIntervalR) theOutPreviousIntervalH;
02439 
02440     theOutPreviousIntervalH = theOutFirstIntervalH;
02441     theOutPreviousIntervalH->getBaselineNext( theOutIntervalH );
02442 
02443     while( theOutIntervalH != theOutRightBaselineIntervalH ) {
02444 
02445         status = linkTopIntervalsInSubTree( theOutIntervalH,
02446                                             theOutPreviousIntervalH );
02447         if( BdbcSuccess != status ) {
02448             ErrMsg(error) << errorString << endl
02449                           << "    Failed to process the next tree of versions." << endmsg;
02450             return status;
02451         }
02452 
02453         theOutIntervalH->getBaselineNext( theOutNextIntervalH );
02454         theOutIntervalH = theOutNextIntervalH;
02455     }
02456 
02457     theOutPreviousIntervalH->setTopNext( theOutRightTopmostIntervalH );
02458     theOutRightTopmostIntervalH->setTopPrevious( theOutPreviousIntervalH );
02459    
02460     return BdbcSuccess;
02461 }
02462 
02463 BdbStatus
02464 BdbCondDatabaseMgr::mergeInnerFromBaseline( BdbObsoleteDatabase&             theInDb,
02465                                             BdbObsoleteDatabase&             theOutDb,
02466                                             BdbHandle(BdbIntervalR)& theInBeginLeftBaselineIntervalH,
02467                                             BdbHandle(BdbIntervalR)& theInBeginRightBaselineIntervalH,
02468                                             BdbHandle(BdbIntervalR)& theInEndLeftBaselineIntervalH,
02469                                             BdbHandle(BdbIntervalR)& theInEndRightBaselineIntervalH,
02470                                             BdbHandle(BdbIntervalR)& theOutBeginLeftBaselineIntervalH,
02471                                             BdbHandle(BdbIntervalR)& theOutBeginRightBaselineIntervalH,
02472                                             BdbHandle(BdbIntervalR)& theOutEndLeftBaselineIntervalH,
02473                                             BdbHandle(BdbIntervalR)& theOutEndRightBaselineIntervalH )
02474 {
02475     const char* errorString = "BdbCondDatabaseMgr::mergeInnerFromBaseline() -- error.";
02476 
02477     BdbStatus status = BdbcError;
02478 
02479   // Locate the "border" intervals in both containers.
02480 
02481     BdbHandle(BdbIntervalR) theInFirstIntervalH;
02482     BdbHandle(BdbIntervalR) theInLastIntervalH;
02483     BdbHandle(BdbIntervalR) theOutFirstIntervalH;
02484     BdbHandle(BdbIntervalR) theOutLastIntervalH;
02485 
02486     status = locateBorderIntervals( theInDb,
02487                                     theOutDb,
02488                                     theInFirstIntervalH,
02489                                     theInLastIntervalH,
02490                                     theOutFirstIntervalH,
02491                                     theOutLastIntervalH );
02492     if( BdbcSuccess != status ) return status;
02493 
02494   // Get the handles for the output container itself and its baseline
02495   // revision.
02496   // We expect that these values are cached by the previous procedure.
02497 
02498     BdbHandle(BdbContObj) theOutContH;
02499     theOutDb.getIntervalContH( theOutContH );
02500 
02501     BdbHandle(BdbCondRevision) theOutBaselineRevisionH;
02502     theOutDb.getBaselineRevisionH( theOutBaselineRevisionH );
02503 
02504   // Locate the topmost intervals on:
02505   //
02506   //    - the right side of the left  outer part
02507   //    - the left  side of the right outer part
02508   //
02509   // of the output containers. This will be needed later to connect
02510   // the leftmost and rightmost topmost intervals of the copied innner
02511   // part.
02512   //
02513   //         this is what we are
02514   //           looking for
02515   //              :   :
02516   //          +...+   +...+
02517   //          :           :
02518   //          v           v
02519   //        +---+       +---+
02520   //        | * |.......| * |
02521   //    ----+---+.......+---+----
02522   //    .........................
02523   //    --------+.......+--------
02524   //                ^
02525   //                :
02526   //              Inner
02527   //
02528   // NOTE: the techniques we are using to locate the interval on the left -  we are
02529   //       locating the first topmost interval in the inner side and then are taking
02530   //       one step back in the topmost link to the rightmost topmost interval
02531   //       from the left outer part.
02532 
02533     BdbHandle(BdbIntervalR) theIntervalH;
02534     BdbHandle(BdbIntervalR) theOutBeginLeftTopmostIntervalH;
02535     BdbHandle(BdbIntervalR) theOutEndRightTopmostIntervalH;
02536 
02537     status = theOutDb.getTopmostInterval( theIntervalH,
02538                                           theOutDb.containerName( ),
02539                                           theOutBeginRightBaselineIntervalH->beginTime( ));
02540     if ( BdbcSuccess != status ) return status;
02541     theIntervalH->getTopPrevious( theOutBeginLeftTopmostIntervalH );
02542 
02543     status = theOutDb.getTopmostInterval( theOutEndRightTopmostIntervalH,
02544                                           theOutDb.containerName( ),
02545                                           theOutEndRightBaselineIntervalH->beginTime( ));
02546     if ( BdbcSuccess != status ) return status;
02547 
02548   // Step I: Remove old intervals from the left side in the output container.
02549   //
02550   //   NOTE: Since a trivial obkectdeletion macro BdbDelete() does not delete
02551   //         vertical (child) versions of baseline intervals then we are using
02552   //         a special helper method deleteIntervalsInSubTree() to do this recursivly.
02553   //
02554   //         We also tell this deletetion method to delete the genealogy object
02555   //         as well.
02556 
02557     BdbHandle(BdbIntervalR) theBaselineIntervalH;
02558     BdbHandle(BdbIntervalR) theNextBaselineIntervalH;
02559 
02560     theBaselineIntervalH = theOutBeginRightBaselineIntervalH;   // This interval will be deleted first.
02561     do {
02562         theBaselineIntervalH->getBaselineNext( theNextBaselineIntervalH );
02563         deleteIntervalsInSubTree( theBaselineIntervalH, true );
02564         theBaselineIntervalH = theNextBaselineIntervalH;
02565     } while ( theBaselineIntervalH != theOutEndRightBaselineIntervalH );
02566 
02567   // Step II: Make a copy of baseline intervals until (excluding) the "right"
02568   //          baseline interval.
02569 
02570     BdbHandle(BdbIntervalR) theInPrevBaselineIntervalH;
02571     BdbHandle(BdbIntervalR) theInBaselineIntervalH;
02572     BdbHandle(BdbIntervalR) theOutPrevBaselineIntervalH;
02573     BdbHandle(BdbIntervalR) theOutBaselineIntervalH;
02574 
02575     theInPrevBaselineIntervalH  = theInBeginLeftBaselineIntervalH;
02576     theOutPrevBaselineIntervalH = theOutBeginLeftBaselineIntervalH;
02577 
02578     theInPrevBaselineIntervalH->getBaselineNext( theInBaselineIntervalH );
02579     while ( theInBaselineIntervalH != theInEndRightBaselineIntervalH ) {
02580 
02581         theOutBaselineIntervalH = new( theOutContH ) BdbIntervalR( theInBaselineIntervalH->getObject( ),
02582                                                                    theInBaselineIntervalH->getBeginTime( ),
02583                                                                    theInBaselineIntervalH->getEndTime( ),
02584                                                                    theInBaselineIntervalH->getTag( ));
02585 
02586         theOutBaselineIntervalH->setVersionTime( theInBaselineIntervalH->getVersionTime( ));
02587         theOutBaselineIntervalH->setRevision( theOutBaselineRevisionH );
02588 
02589         theOutPrevBaselineIntervalH->setTopNext( theOutBaselineIntervalH );
02590         theOutPrevBaselineIntervalH->setBaselineNext( theOutBaselineIntervalH );
02591 
02592         theOutBaselineIntervalH->setTopPrevious( theOutPrevBaselineIntervalH );
02593         theOutBaselineIntervalH->setBaselinePrevious( theOutPrevBaselineIntervalH );
02594 
02595         theOutPrevBaselineIntervalH = theOutBaselineIntervalH;
02596 
02597         theInPrevBaselineIntervalH = theInBaselineIntervalH;
02598         theInPrevBaselineIntervalH->getBaselineNext( theInBaselineIntervalH );
02599     }
02600 
02601     theOutPrevBaselineIntervalH->setTopNext( theOutEndRightTopmostIntervalH );
02602     theOutPrevBaselineIntervalH->setBaselineNext( theOutEndRightBaselineIntervalH );
02603 
02604     theOutEndRightTopmostIntervalH->setTopPrevious( theOutPrevBaselineIntervalH );
02605     theOutEndRightBaselineIntervalH->setBaselinePrevious( theOutPrevBaselineIntervalH );
02606 
02607   // Step III: traverse baseline intervals and build the version trees.
02608   //           Copy information from the input intervals into output ones.
02609   //
02610   //    NOTE: the pointers (handles) in both containers advance
02611   //          along containers synchronosly (pay attention to the check
02612   //          after the "while" loop ends.
02613   //
02614   //          This operation lasts until (excluding) the "right" baseline interval.
02615 
02616     BdbHandle(BdbIntervalR) theInIntervalH;
02617     BdbHandle(BdbIntervalR) theInNextIntervalH;
02618     BdbHandle(BdbIntervalR) theOutIntervalH;
02619     BdbHandle(BdbIntervalR) theOutNextIntervalH;
02620 
02621     theInBeginLeftBaselineIntervalH->getBaselineNext( theInIntervalH );
02622     theOutBeginLeftBaselineIntervalH->getBaselineNext( theOutIntervalH );
02623 
02624     while( theInIntervalH != theInEndRightBaselineIntervalH ) {
02625 
02626         status = copySubTree( theInIntervalH,
02627                               theOutDb,
02628                               theOutIntervalH );
02629         if( BdbcSuccess != status ) {
02630             ErrMsg(error) << errorString << endl
02631                           << "    Failed to copy the next tree of versions." << endmsg;
02632             return status;
02633         }
02634 
02635         theInIntervalH->getBaselineNext( theInNextIntervalH );
02636         theInIntervalH = theInNextIntervalH;
02637 
02638         theOutIntervalH->getBaselineNext( theOutNextIntervalH );
02639         theOutIntervalH = theOutNextIntervalH;
02640     }
02641     if ( theOutIntervalH != theOutEndRightBaselineIntervalH ) {
02642         ErrMsg(error) << errorString << endl
02643                       << "    The output container has incorrect internal structure." << endmsg;
02644         return status;
02645     }
02646 
02647   // Step IV: Connect the topmost intervals into the double linked list.
02648 
02649     BdbHandle(BdbIntervalR) theOutPreviousIntervalH;
02650 
02651     theOutPreviousIntervalH = theOutBeginLeftTopmostIntervalH;
02652     theOutBeginLeftBaselineIntervalH->getBaselineNext( theOutIntervalH );
02653 
02654     while( theOutIntervalH != theOutEndRightBaselineIntervalH ) {
02655 
02656         status = linkTopIntervalsInSubTree( theOutIntervalH,
02657                                             theOutPreviousIntervalH );
02658         if( BdbcSuccess != status ) {
02659             ErrMsg(error) << errorString << endl
02660                           << "    Failed to process the next tree of versions." << endmsg;
02661             return status;
02662         }
02663 
02664         theOutIntervalH->getBaselineNext( theOutNextIntervalH );
02665         theOutIntervalH = theOutNextIntervalH;
02666     }
02667 
02668     theOutPreviousIntervalH->setTopNext( theOutEndRightTopmostIntervalH );
02669     theOutEndRightTopmostIntervalH->setTopPrevious( theOutPreviousIntervalH );
02670 
02671     return BdbcSuccess;
02672 }
02673 
02674 BdbStatus
02675 BdbCondDatabaseMgr::purgeIntervalContainer( const char*    theTLA,
02676                                             const char*    theContName,
02677                                             const BdbTime& theBeginTime,
02678                                             const BdbTime& theEndTime,
02679                                             bool           keepRevisedIntervals,
02680                                             d_ULong        maxNumOfTopLayers,
02681                                             d_ULong        maxNumOfLayersUnderRevisedInterval )
02682 {
02683     const char* errorString = "BdbCondDatabaseMgr::purgeIntervalContainer() -- error.";
02684 
02685     BdbStatus status = BdbcSuccess;
02686 
02687     assert( theTLA       != (char*) 0 );
02688     assert( theContName  != (char*) 0 );
02689     assert( theBeginTime <= theEndTime );
02690 
02691   // Open the database.
02692 
02693     BdbObsoleteDatabase theDb( theTLA );
02694 
02695     BdbHandle(BdbIntervalR) theFirstIntervalH;
02696     BdbHandle(BdbIntervalR) theLastIntervalH;
02697 
02698     BdbHandle(BdbIntervalR) theInBeginBaselineIntervalH;
02699     BdbHandle(BdbIntervalR) theInEndBaselineIntervalH;
02700     BdbHandle(BdbIntervalR) theInBaselineIntervalH;
02701     BdbHandle(BdbIntervalR) theInPreviousBaselineIntervalH;
02702     BdbHandle(BdbIntervalR) theInNextBaselineIntervalH;
02703 
02704     BdbHandle(BdbIntervalR) theBeginTopIntervalH;
02705     BdbHandle(BdbIntervalR) theEndTopIntervalH;
02706     BdbHandle(BdbIntervalR) theTopIntervalH;
02707 
02708     BdbHandle(BdbIntervalR) theOutBeginBaselineIntervalH;
02709     BdbHandle(BdbIntervalR) theOutEndBaselineIntervalH;
02710     BdbHandle(BdbIntervalR) theOutBaselineIntervalH;
02711     BdbHandle(BdbIntervalR) theOutNextBaselineIntervalH;
02712 
02713   // Perform firther operations in a exception-like loop.
02714 
02715     bool operationsLoopWasFailed = true;
02716 
02717     while( true ) {
02718 
02719       // Make sure that both begin and end time were correctly specified.
02720 
02721         if ( theBeginTime > theEndTime ) {
02722             ErrMsg(error) << errorString << endl
02723                           << "    Wrong values of the procedure's parameters - the begin time" << endl
02724                           << "    must be less or equal to the end time." << endmsg;
02725             break;
02726         }
02727 
02728       // Get the FIRST and the LAST intervals.
02729 
02730         status = theDb.firstInterval( theFirstIntervalH, theContName );
02731         if ( BdbcSuccess != status ) {
02732             ErrMsg(error) << errorString << endl
02733                           << "    Failed to locate the FIRST interval in the specified container." << endmsg;
02734             break;
02735         }
02736         status = theDb.lastInterval( theLastIntervalH, theContName );
02737         if ( BdbcSuccess != status ) {
02738             ErrMsg(error) << errorString << endl
02739                           << "    Failed to locate the LAST interval in the specified container." << endmsg;
02740             break;
02741         }
02742 
02743       // Get the baseline intervals corresponding to specified begin and end times.
02744       // These intervals will be included into the processing.
02745       //
02746       // NOTE: A trivial optimization in case if one (or both) of specified time(s)
02747       //       goes (go) into either infinity has been done.
02748 
02749         if ( BdbTime::minusInfinity == theBeginTime ) {
02750             theInBeginBaselineIntervalH = theFirstIntervalH;
02751         } else {
02752             status = theDb.getBaselineInterval( theInBeginBaselineIntervalH, theContName, theBeginTime );
02753             if ( BdbcSuccess != status ) {
02754                 ErrMsg(error) << errorString << endl
02755                               << "    Failed to locate a baseline interval for specified begin time." << endmsg;
02756                 break;
02757             }
02758         }
02759         if ( BdbTime::plusInfinity == theEndTime ) {
02760             theInEndBaselineIntervalH = theLastIntervalH;
02761         } else {
02762             status = theDb.getBaselineInterval( theInEndBaselineIntervalH, theContName, theEndTime );
02763             if ( BdbcSuccess != status ) {
02764                 ErrMsg(error) << errorString << endl
02765                               << "    Failed to locate a baseline interval for specified end time." << endmsg;
02766                 break;
02767             }
02768         }
02769 
02770       // Just skip the processing of the FIRST and LAST intervals.
02771       //
02772       // NOTE: the adjusted intervals could be NULL in the following cases:
02773       //
02774       //       ================================================
02775       //       CASE I: both times fall into the FIRST interval.
02776       //       ================================================
02777       //
02778       //         beginTime   endTime
02779       //              :         :
02780       //              +...+  +..+
02781       //                  :  :
02782       //                  V  V
02783       //                [ FIRST )...
02784       //
02785       //       ================================================
02786       //       CASE II: both times fall into the LAST interval.
02787       //       ================================================
02788       //
02789       //         beginTime   endTime
02790       //              :         :
02791       //              +...+  +..+
02792       //                  :  :
02793       //                  V  V
02794       //             ...[ LAST )
02795       //
02796       //       ======================================================
02797       //       CASE III: just FIST and LAST intervals in a container.
02798       //       ======================================================
02799       //
02800       //         beginTime      endTime
02801       //              :            :
02802       //              +...+    +...+
02803       //                  :    :
02804       //                  V    V
02805       //            [ FIRST )[ LAST )
02806       //
02807 
02808         if ( theInBeginBaselineIntervalH == theFirstIntervalH ) {
02809             theFirstIntervalH->getBaselineNext( theInBeginBaselineIntervalH );
02810         }
02811         if ( theInBeginBaselineIntervalH == theLastIntervalH ) {
02812             theInBeginBaselineIntervalH = 0;    // CASE: I or III.
02813         }
02814         if ( theInEndBaselineIntervalH == theLastIntervalH ) {
02815             theLastIntervalH->getBaselinePrevious( theInEndBaselineIntervalH );
02816         }
02817         if ( theInEndBaselineIntervalH == theFirstIntervalH ) {
02818             theInEndBaselineIntervalH = 0;      // CASE: II or III.
02819         }
02820 
02821       // Proceed if there are other intervals in between the begin
02822       // and the end ones.
02823 
02824         if (( ! BdbIsNull(theInBeginBaselineIntervalH)) &&
02825             ( ! BdbIsNull(theInEndBaselineIntervalH))) {
02826 
02827           // Get the nearest topmost intervals left and right from the found
02828           // baseline intervals.
02829           // These intervals will be used later when drawing the topmost path
02830           // over the newely created sub-sequence.
02831           //
02832           // NOTE: That we are doing this operation _before_ we create any new intervals
02833           //       in this container. Otherwise the Objectivity's index will supply us
02834           //       a list of wrong intervals.
02835           //
02836           // Here is a picture of what we are looking for:
02837           //
02838           // ----------------------+                                                               +--------------------+
02839           //  theBeginTopIntervalH |                                                               | theEndTopIntervalH |
02840           // ----------------------+                                                               +--------------------+
02841           //                       :                                                               :
02842           // ----------------------+-----------------------------+     +---------------------------+---------------------
02843           //                       | theInBeginBaselineIntervalH | ... | theInEndBaselineIntervalH |
02844           // ----------------------+-----------------------------+     +---------------------------+---------------------
02845           //  
02846 
02847             status = theDb.getTopmostInterval( theTopIntervalH,
02848                                                theContName,
02849                                                theInBeginBaselineIntervalH->getBeginTime( ));
02850             if( BdbcSuccess != status ) {
02851                 ErrMsg(error) << errorString << endl
02852                               << "    Failed to locate a topmost interval interval at: " << theInBeginBaselineIntervalH->getBeginTime( ) << endmsg;
02853                 break;
02854             }
02855             theTopIntervalH->getTopPrevious( theBeginTopIntervalH );
02856 
02857 
02858             status = theDb.getTopmostInterval( theEndTopIntervalH,
02859                                                theContName,
02860                                                theInEndBaselineIntervalH->getEndTime( ));
02861             if( BdbcSuccess != status ) {
02862                 ErrMsg(error) << errorString << endl
02863                               << "    Failed to locate a topmost interval interval at: " << theInEndBaselineIntervalH->getEndTime( ) << endmsg;
02864                 break;
02865             }
02866 
02867           // Put a record for the "history" of this container.
02868 
02869             theDb.historyCPurge( rcsid,
02870                                  theBeginTime,
02871                                  theEndTime,
02872                                  keepRevisedIntervals,
02873                                  maxNumOfTopLayers,
02874                                  maxNumOfLayersUnderRevisedInterval );
02875 
02876           // And then begin merging...
02877 
02878           // Copy baseline intervals. Then replace this new sequence instead of
02879           // of the old one.
02880           //
02881           // NOTE; that after these operations we will still have the incomplete
02882           //       topmost layer. We'll do it later after we copy the required
02883           //       fraction of vertical versions.
02884 
02885             status = copySubSequenceOfBaselineIntervals( theDb,
02886                                                          theInBeginBaselineIntervalH,
02887                                                          theInEndBaselineIntervalH,
02888                                                          theDb,
02889                                                          theOutBeginBaselineIntervalH,
02890                                                          theOutEndBaselineIntervalH );
02891             if ( BdbcSuccess != status ) {
02892                 ErrMsg(error) << errorString << endl
02893                               << "    Failed to copy a sub-sequence of original baseline intervals." << endmsg;
02894                 break;
02895             }
02896 
02897             theInBeginBaselineIntervalH->getBaselinePrevious( theInPreviousBaselineIntervalH );
02898             theInPreviousBaselineIntervalH->setBaselineNext( theOutBeginBaselineIntervalH );
02899             theOutBeginBaselineIntervalH->setBaselinePrevious( theInPreviousBaselineIntervalH );
02900 
02901             theInEndBaselineIntervalH->getBaselineNext( theInNextBaselineIntervalH );
02902             theOutEndBaselineIntervalH->setBaselineNext( theInNextBaselineIntervalH );
02903             theInNextBaselineIntervalH->setBaselinePrevious( theOutEndBaselineIntervalH );
02904 
02905           // The enclosed (into "if") list of actions makes a sense if specified number of top intervals
02906           // to keep is more then 0. If it's equal to 0 then we are copying just baseline intervals.
02907 
02908             if ( keepRevisedIntervals || ( maxNumOfTopLayers > 0 )) {
02909 
02910               // Copy the top fractions of the subtrees for all baseline intervals
02911               // starting from the found begin and end ones.
02912 
02913                 theInNextBaselineIntervalH  = theInBeginBaselineIntervalH;
02914                 theOutNextBaselineIntervalH = theOutBeginBaselineIntervalH;
02915 
02916                 do {
02917 
02918                     theInBaselineIntervalH  = theInNextBaselineIntervalH;
02919                     theOutBaselineIntervalH = theOutNextBaselineIntervalH;
02920 
02921 
02922                   // Correct the copying conditions if the revised intervals should
02923                   // be kept and if the current versioning tree has at least one
02924                   // such interval.
02925                   //
02926                   // NOTE: The BASELINE intervals do not count.
02927 
02928                     if (( 0 == maxNumOfTopLayers ) &&
02929                           keepRevisedIntervals     &&
02930                           hasRevisedIntervalInSubTree( theInBaselineIntervalH )) {
02931 
02932                       // Since we have at least one revised interval in this tree then
02933                       // we would need the topmost layer to be copied as well in order to fill
02934                       // potential gaps after explicit copying of the revised interval(s).
02935 
02936                         status = copyTopIntervalsInSubTree( theDb,
02937                                                             theInBaselineIntervalH,
02938                                                             theOutBaselineIntervalH,
02939                                                             keepRevisedIntervals,
02940                                                             1,
02941                                                             maxNumOfLayersUnderRevisedInterval );
02942                     } else {
02943 
02944                         status = copyTopIntervalsInSubTree( theDb,
02945                                                             theInBaselineIntervalH,
02946                                                             theOutBaselineIntervalH,
02947                                                             keepRevisedIntervals,
02948                                                             maxNumOfTopLayers,
02949                                                             maxNumOfLayersUnderRevisedInterval );
02950                     }
02951                     if ( BdbcSuccess != status ) {
02952                         ErrMsg(error) << errorString << endl
02953                                       << "    Failed to copy a top slice of intervals for a version tree staring" << endl
02954                                       << "    at: " << theInBaselineIntervalH->beginTime( ) << endmsg;
02955                         break;
02956                     }
02957 
02958                     theInBaselineIntervalH->getBaselineNext( theInNextBaselineIntervalH );
02959                     theOutBaselineIntervalH->getBaselineNext( theOutNextBaselineIntervalH );
02960 
02961                 } while ( theInBaselineIntervalH != theInEndBaselineIntervalH );
02962 
02963                 if ( BdbcSuccess != status ) break;
02964             }
02965 
02966           // Connect new topmost intervals into a linked list.
02967           // We do this operation in 2 steps:
02968           //
02969           //    1. Routinly link the intervals in cycle up to (including) the last
02970           //       cluster of newely created intervals.
02971           //    2. Connect the rightmost top interval of the last cluster with the rest
02972           //       of the container.
02973           //
02974           // IMPORTANT NOTE: In all these steps we are using the same
02975           //    interval "theBeginTopIntervalH" as a link to the previous topmost interval.
02976           //    Due to a way the "::linkTopIntervalsInSubTree()" method works, the value
02977           //    of this back link is always modified upon the completion of the method.
02978 
02979 
02980             theOutNextBaselineIntervalH = theOutBeginBaselineIntervalH;
02981 
02982             do {
02983 
02984                 theOutBaselineIntervalH = theOutNextBaselineIntervalH;
02985 
02986                 status = linkTopIntervalsInSubTree( theOutBaselineIntervalH,
02987                                                     theBeginTopIntervalH );
02988                 if( BdbcSuccess != status ) {
02989                     ErrMsg(error) << errorString << endl
02990                                   << "    Failed to draw the topmost line at: " << theOutBaselineIntervalH->getBeginTime( ) << endmsg;
02991                     break;
02992                 }
02993 
02994                 theOutBaselineIntervalH->getBaselineNext( theOutNextBaselineIntervalH );
02995 
02996             } while ( theOutBaselineIntervalH != theOutEndBaselineIntervalH );
02997 
02998             if ( BdbcSuccess != status ) break;
02999 
03000             theBeginTopIntervalH->setTopNext( theEndTopIntervalH );
03001             theEndTopIntervalH->setTopPrevious( theBeginTopIntervalH );
03002 
03003           // Delete the old clusters of intervals.
03004           //
03005           // NOTE: There is one very important assumption which we bear in mind
03006           //       when running the following algorithm - when the object pointed by
03007           //       a handle is deleted then the OID in this handle is not destroyed.
03008           //       This assumption is in a base of the check at the end of the loop.
03009 
03010             theInNextBaselineIntervalH = theInBeginBaselineIntervalH;
03011 
03012             do {
03013 
03014                 theInBaselineIntervalH = theInNextBaselineIntervalH;
03015                 theInBaselineIntervalH->getBaselineNext( theInNextBaselineIntervalH );
03016 
03017                 deleteIntervalsInSubTree( theInBaselineIntervalH, true );
03018 
03019             } while ( theInBaselineIntervalH != theInEndBaselineIntervalH );
03020         }
03021 
03022       // The processing has been sucessfully completed.
03023 
03024         operationsLoopWasFailed = false;
03025         break;
03026     }
03027     if ( operationsLoopWasFailed ) {
03028         ErrMsg(error) << "        DETECTOR:   " << theTLA << endl
03029                       << "        CONTAINER:  " << theContName << endl
03030                       << "        BEGIN TIME: " << theBeginTime << endl
03031                       << "        END TIME:   " << theEndTime << endmsg;
03032         return BdbcError;
03033     }
03034 
03035     return BdbcSuccess;
03036 }
03037 
03038 BdbStatus
03039 BdbCondDatabaseMgr::nanoCorrection( const char*                 theTLA,
03040                                     const char*                 theContName,
03041                                     const BdbTime&              theBeginTime,
03042                                     const BdbTime&              theEndTime,
03043                                     vector<ooId>&  theFoundIntervalsList,
03044                                     bool                        verifyOnly )
03045 {
03046     const char* errorString = "BdbCondDatabaseMgr::nanoCorrection() -- error.";
03047 
03048     BdbStatus status = BdbcSuccess;
03049 
03050     assert( theTLA       != (char*) 0 );
03051     assert( theContName  != (char*) 0 );
03052     assert( theBeginTime <= theEndTime );
03053 
03054     theFoundIntervalsList.clear( );
03055 
03056   // Correct the input times to be sure that we are working in a proper range
03057   // of validity time.
03058 
03059     BdbTime theCorrectedBeginTime( theBeginTime.getGmtSec( ));
03060     BdbTime theCorrectedEndTime  ( theEndTime.getGmtSec  ( ));
03061 
03062   // Open the database.
03063 
03064     BdbObsoleteDatabase theDb( theTLA );
03065 
03066     BdbHandle(BdbIntervalR) theFirstIntervalH;
03067     BdbHandle(BdbIntervalR) theLastIntervalH;
03068 
03069   // Perform initializations in a exception-like loop.
03070 
03071     BdbHandle(BdbIntervalR) theIntervalH;
03072 
03073     bool theLoopWasFailed = true;
03074 
03075     while ( true ) {
03076 
03077       // Get the FIRST and the LAST intervals.
03078       //
03079       // NOTE: These operations are useless in the current context, but they
03080       //       would bring in the cache of the BdbObsoleteDatabase object which would
03081       //       be needed for a subsequent "non-verify-only" operation mode.
03082 
03083         status = theDb.firstInterval( theFirstIntervalH, theContName );
03084         if ( BdbcSuccess != status ) {
03085             ErrMsg(error) << errorString << endl
03086                           << "    Failed to locate the FIRST interval in the specified container." << endmsg;
03087             break;
03088         }
03089         status = theDb.lastInterval( theLastIntervalH, theContName );
03090         if ( BdbcSuccess != status ) {
03091             ErrMsg(error) << errorString << endl
03092                           << "    Failed to locate the LAST interval in the specified container." << endmsg;
03093             break;
03094         }
03095 
03096       // Ensure a proper authorization level to be set if we are not
03097       // running in the "verify" mode.
03098 
03099         if( ! verifyOnly ) {
03100             if ( ! theDb.verifyAuthLevelOnly( theContName )) {
03101                 ErrMsg(error) << errorString << endl
03102                               << "    Failed to set proper Authorization level." << endmsg;
03103                 break;
03104             }
03105         }
03106 
03107       // Iterate all the BASELINE intervals and recursivly process
03108       // in each subtree growing from these intervals.
03109 
03110         BdbIntervalItr theItr;
03111         if( ! theItr.setBaseline( theTLA, theContName, theCorrectedBeginTime )) {
03112             ErrMsg(error) << errorString << endl
03113                           << "    Failed to initialize an iterator for BASELINE iintervals." << endmsg;
03114             break;
03115         }
03116 
03117       // Put a record for the "history" of this container if we are not
03118       // running in the "verify" mode.
03119 
03120         if( ! verifyOnly ) {
03121             theDb.historyNCorrection( rcsid,
03122                                       theBeginTime,
03123                                       theEndTime );
03124         }
03125         while( theItr.next( )) {
03126 
03127             theIntervalH = (BdbHandle(BdbIntervalR)&) theItr;
03128             if( theIntervalH->beginTime( ) >= theCorrectedEndTime ) break;
03129 
03130              nanoCorrectionInSubTree( theIntervalH, theFoundIntervalsList, verifyOnly );
03131         }
03132         if( BdbcSuccess != status ) break;
03133 
03134         theLoopWasFailed = false;
03135         break;
03136     }
03137     if ( theLoopWasFailed ) {
03138         ErrMsg(error) << "        Detector:  \"" << theTLA << "\"" << endl
03139                       << "        Container: \"" << theContName << "\"" << endmsg;
03140 
03141         return BdbcError;
03142     }
03143 
03144     return BdbcSuccess;
03145 }
03146 
03147 void
03148 BdbCondDatabaseMgr::nanoCorrectionInSubTree( const BdbHandle(BdbIntervalR)& theBaseIntervalH,
03149                                              vector<ooId>&     theFoundIntervalsList,
03150                                              bool                           verifyOnly )
03151 {
03152   // Check the base interval first.
03153 
03154     const BdbTime& theBeginTime = theBaseIntervalH->beginTime( );
03155     const BdbTime& theEndTime   = theBaseIntervalH->endTime  ( );
03156 
03157     ooId id = theBaseIntervalH;
03158 
03159     if(( 0 != theBeginTime.getGmtNsec( )) || ( 0 != theEndTime.getGmtNsec( ))) {
03160 
03161         BdbRef(BdbIntervalR) theIntervalRef( theBaseIntervalH );
03162         ooId theId = theIntervalRef;
03163 
03164         theFoundIntervalsList.push_back( theId );
03165 
03166         if( ! verifyOnly ) {
03167             theBaseIntervalH->ooUpdate( );
03168             theBaseIntervalH->setBeginTime( BdbTime( theBeginTime.getGmtSec( )));
03169             theBaseIntervalH->setEndTime  ( BdbTime( theEndTime.getGmtSec  ( )));
03170         }
03171     }
03172 
03173   // Proceed to the child versions (if any).
03174 
03175     BdbHandle(BdbIntervalR) theIntervalH;
03176     BdbItr(BdbPersObj)      theItr;
03177 
03178     theBaseIntervalH->nextVers( theItr );
03179     while ( theItr.next( )) {
03180         theIntervalH = (BdbHandle(BdbIntervalR)&) theItr;
03181         nanoCorrectionInSubTree( theIntervalH, theFoundIntervalsList, verifyOnly );
03182     }
03183 
03184     return;
03185 }
03186 
03187 BdbStatus
03188 BdbCondDatabaseMgr::initOutputContainer( BdbObsoleteDatabase& theInDb,
03189                                          const char*  theInContName,
03190                                          BdbObsoleteDatabase& theOutDb,
03191                                          const char*  theOutContName )
03192 {
03193     const char* errorString = "BdbCondDatabaseMgr::initOutputContainer() -- error.";
03194 
03195     BdbStatus status;
03196 
03197     BdbHandle(BdbContObj) theInContH;
03198     BdbHandle(BdbContObj) theOutContH;
03199 
03200     BdbHandle(BdbInterval) theInFirstIntervalH;
03201 
03202   // Perform initializations in a exception-like loop.
03203 
03204     bool initLoopWasFailed = true;
03205 
03206     while( true ) {
03207 
03208       // Open the input container. The container must exist.
03209 
03210         status = theInDb.findIntervalCont( theInContH, theInContName );
03211         if (( BdbcSuccess != status ) || ( BdbIsNull( theInContH ))) {
03212             ErrMsg(error) << errorString << endl
03213                           << "    The input container does not exist in the database." << endmsg;
03214             break;
03215         }
03216 
03217       // Locate the FIRST interval in the input container:
03218 
03219         theInFirstIntervalH.lookupObj( theInContH, "FirstInterval", BdbcRead );
03220         if ( BdbIsNull( theInFirstIntervalH )) {
03221             ErrMsg(error) << errorString << endl
03222                           << "    The FIRST was not found in the input container." << endl
03223                           << "    The container may have incorrect internal structure." << endmsg;
03224             break;
03225         }
03226 
03227       // First of all we want to make sure that no conainer link with such name exists
03228       // in the link database.
03229       //
03230       // We don't care about "non-link"-ed containers at all, because new containers
03231       // are always created in the link database.
03232 
03233         status = theOutDb.findIntervalCont( theOutContH, theOutContName );
03234         if( BdbcSuccess == status ) {
03235             if( theOutDb.isLink( )) {
03236                 ErrMsg(error) << errorString << endl
03237                               << "    The output container link with such name already exist." << endl
03238                               << "    You may want to delete the link before to perform this operation." << endmsg;
03239                 break;
03240             }
03241         }
03242 
03243       // Ensure the proper context to be set.
03244 
03245         if ( ! theOutDb.verifyIndexMode( ))             break;
03246         if ( ! theOutDb.setAuthLevel( theOutContName )) break;
03247 
03248       // Create the output container.
03249 
03250         status = theOutDb.createIntervalCont( theOutContName,
03251                                               0,
03252                                               theInFirstIntervalH->getEndTime( ));
03253         if( BdbcSuccess != status ) {
03254             ErrMsg(error) << errorString << endl
03255                           << "    Failed to create the output container." << endmsg;
03256             break;
03257         }
03258 
03259       // Copy all revisions relevant information from the input container
03260       // to the output one.
03261 
03262         BdbHandle(BdbCondRegistry) theInRegistryH;
03263         BdbHandle(BdbCondRegistry) theOutRegistryH;
03264 
03265         theInDb.getRegistryH (theInRegistryH );
03266         theOutDb.getRegistryH( theOutRegistryH );
03267 
03268         status = copyRevisions( theInRegistryH, theOutRegistryH );
03269         if( BdbcSuccess != status ) {
03270             ErrMsg(error) << errorString << endl
03271                           << "    Failed to make a copy of revision infromation from the input" << endl
03272                           << "    container to the output one." << endmsg;
03273             break;
03274         }
03275 
03276       // The initialization has been sucessfully completed.
03277 
03278         initLoopWasFailed = false;
03279         break;
03280     }
03281     if( initLoopWasFailed ) {
03282 
03283         if( BdbcSuccess == status ) {
03284             status = BdbcError;
03285         }
03286 
03287         return status;
03288     }
03289  
03290     return BdbcSuccess;
03291 }
03292 
03293 BdbStatus
03294 BdbCondDatabaseMgr::copyRevisions( const BdbHandle(BdbCondRegistry)& theInRegistryH,
03295                                    const BdbHandle(BdbCondRegistry)& theOutRegistryH )
03296 {
03297     const char* errorString = "BdbCondDatabaseMgr::copyRevisions() -- error.";
03298 
03299     BdbStatus status = BdbcError;
03300 
03301     assert( ! BdbIsNull( theInRegistryH ));
03302     assert( ! BdbIsNull( theOutRegistryH ));
03303 
03304   // The operation is disable d for the same container.
03305 
03306     if ( theInRegistryH == theOutRegistryH ) {
03307         ErrMsg(error) << errorString << endl
03308                       << "    Unabled to perform the operation within the same container." << endmsg;
03309         return BdbcError;
03310     }
03311 
03312   // Locate baseline revisions for both containers. They must exist
03313   // if the containers were properly intialized.
03314 
03315     BdbHandle(BdbCondRevision) theInBaselineRevisionH;
03316     BdbHandle(BdbCondRevision) theOutBaselineRevisionH;
03317 
03318     theInRegistryH->getRevision( theInBaselineRevisionH, BdbCondRevision::BASELINE );
03319     if ( BdbIsNull( theInBaselineRevisionH )) {
03320         ErrMsg(error) << errorString << endl
03321                       << "    The baseline revision can't be located at the input container." << endl
03322                       << "    The container may have inconsistent internal structure due" << endl
03323                       << "    to unproper initialization." << endmsg;
03324         return BdbcError;
03325     }
03326 
03327     theOutRegistryH->getRevision( theOutBaselineRevisionH, BdbCondRevision::BASELINE );
03328     if ( BdbIsNull( theOutBaselineRevisionH )) {
03329         ErrMsg(error) << errorString << endl
03330                       << "    The baseline revision can't be located at the output container." << endl
03331                       << "    The container may have inconsistent internal structure due" << endl
03332                       << "    to unproper initialization." << endmsg;
03333         return BdbcError;
03334     }
03335 
03336   // Update baseline revision description in the output container
03337   // with the information taken from the input one.
03338 
03339     theOutBaselineRevisionH->setCreationTime( theInBaselineRevisionH->creationTime( ));
03340     theOutBaselineRevisionH->setSite(         theInBaselineRevisionH->site( ));
03341     theOutBaselineRevisionH->setDescription(  theInBaselineRevisionH->description( ));
03342 
03343   // Locate all the revisions connected to the output registry
03344   // and destroy all of them except the baseline one.
03345   // This operation does not destroy intervals connected to these
03346   // revisions although these intervals will have NULL references
03347   // with revisions.
03348 
03349     BdbItr(BdbCondRevision) theItr;
03350 
03351     theOutRegistryH->setRevisionItr( theItr );
03352     while ( theItr.next( )) {
03353         if ( theItr != theOutBaselineRevisionH ) {
03354             BdbDelete( theItr );
03355         }
03356     }
03357 
03358   // Iterate all the known revisions (except the baseline one) in the input
03359   // registry and copy them to the output one.
03360 
03361     BdbHandle(BdbCondRevision) theRevisionH;
03362 
03363     theInRegistryH->setRevisionItr( theItr );
03364     while ( theItr.next( )) {
03365         if ( theItr != theInBaselineRevisionH ) {
03366 
03367             theRevisionH = new( theOutRegistryH ) BdbCondRevision( theItr->id( ),
03368                                                                    theItr->creationTime( ),
03369                                                                    theItr->site( ),
03370                                                                    theItr->description( ));
03371             theOutRegistryH->addRevision( theRevisionH );
03372         }
03373     }
03374 
03375   // The second path. Set the same "base" relationships for all the revision
03376   // in the output container as in the input one.
03377   // NOTE: The baseline revision is ignored.
03378 
03379     BdbHandle(BdbCondRevision) theBaseRevisionH;
03380 
03381     theOutRegistryH->setRevisionItr( theItr );
03382     while ( theItr.next( )) {
03383         if ( theItr != theOutBaselineRevisionH ) {
03384 
03385             d_ULong theRevId = theItr->id( );
03386             theInRegistryH->getRevision( theRevisionH, theRevId );
03387             if( BdbIsNull( theRevisionH )) {
03388                 ErrMsg(error) << errorString << endl
03389                               << "    Failed to locate revision with ID = " << theRevId << " in input container." << endl
03390                               << "    The containers have inconsistent revisions." << endmsg;
03391                 return BdbcError;
03392             }
03393 
03394             theRevisionH->getBaseRevision( theBaseRevisionH );
03395             if( BdbIsNull( theBaseRevisionH )) {
03396                 ErrMsg(error) << errorString << endl
03397                               << "    Failed to locate base revision for a revision with ID = " << theRevId << endl
03398                               << "    in input container." << endl
03399                               << "    The containers have inconsistent revisions." << endmsg;
03400                 return BdbcError;
03401             }
03402 
03403             d_ULong theBaseRevId = theBaseRevisionH->id( );
03404             theOutRegistryH->getRevision( theRevisionH, theBaseRevId );
03405             if( BdbIsNull( theRevisionH )) {
03406                 ErrMsg(error) << errorString << endl
03407                               << "    Failed to locate revision with ID = " << theBaseRevId << " in output container." << endl
03408                               << "    The containers have inconsistent revisions." << endmsg;
03409                 return BdbcError;
03410             }
03411 
03412             status = theItr->setBaseRevision( theRevisionH );
03413             if( BdbcSuccess != status ) {
03414                 ErrMsg(error) << errorString << endl
03415                               << "    Failed to set base revision in output container." << endmsg;
03416                 return BdbcError;
03417             }
03418         }
03419     }
03420 
03421     return BdbcSuccess;
03422 }
03423 
03424 BdbStatus
03425 BdbCondDatabaseMgr::deepCopy( BdbObsoleteDatabase& theInDb,
03426                               BdbObsoleteDatabase& theOutDb )
03427 {
03428     const char* errorString = "BdbCondDatabaseMgr::deepCopy() -- error.";
03429 
03430     BdbStatus status = BdbcError;
03431 
03432     BdbHandle(BdbIntervalR) theInFirstIntervalH;
03433     BdbHandle(BdbIntervalR) theInPreviousIntervalH;
03434     BdbHandle(BdbIntervalR) theInIntervalH;
03435     BdbHandle(BdbIntervalR) theInNextIntervalH;
03436     BdbHandle(BdbIntervalR) theInLastIntervalH;
03437 
03438     BdbHandle(BdbIntervalR) theOutFirstIntervalH;
03439     BdbHandle(BdbIntervalR) theOutPreviousIntervalH;
03440     BdbHandle(BdbIntervalR) theOutIntervalH;
03441     BdbHandle(BdbIntervalR) theOutNextIntervalH;
03442     BdbHandle(BdbIntervalR) theOutLastIntervalH;
03443 
03444   // Step I: make a copy of baseline intervals.
03445 
03446     status = baselineOrTopmostCopy( theInDb, theOutDb, true );
03447     if ( BdbcSuccess != status ) {
03448         ErrMsg(error) << errorString << endl
03449                       << "    Failed to copy baseline intervals." << endmsg;
03450         return status;
03451     }
03452 
03453   // Locate the "border" intervals in both containers.
03454 
03455     status = locateBorderIntervals( theInDb,
03456                                     theOutDb,
03457                                     theInFirstIntervalH,
03458                                     theInLastIntervalH,
03459                                     theOutFirstIntervalH,
03460                                     theOutLastIntervalH );
03461     if( BdbcSuccess != status ) {
03462         return status;
03463     }
03464 
03465   // Step II: traverse baseline intervals and build the version trees.
03466   //          Copy information from the input intervals into output ones.
03467   //
03468   //    NOTE: the pointers (handles) in both containers advance
03469   //          along containers synchronosly.
03470   //          (pay attention to the check after the "while" loop ends.
03471 
03472     theInFirstIntervalH->getBaselineNext( theInIntervalH );
03473     theOutFirstIntervalH->getBaselineNext( theOutIntervalH );
03474 
03475     while( theInIntervalH != theInLastIntervalH ) {
03476 
03477         status = copySubTree( theInIntervalH,
03478                               theOutDb,
03479                               theOutIntervalH );
03480         if( BdbcSuccess != status ) {
03481             ErrMsg(error) << errorString << endl
03482                           << "    Failed to copy the next tree of versions." << endmsg;
03483             return status;
03484         }
03485 
03486         theInIntervalH->getBaselineNext( theInNextIntervalH );
03487         theInIntervalH = theInNextIntervalH;
03488 
03489         theOutIntervalH->getBaselineNext( theOutNextIntervalH );
03490         theOutIntervalH = theOutNextIntervalH;
03491     }
03492     if ( theOutIntervalH != theOutLastIntervalH ) {
03493         ErrMsg(error) << errorString << endl
03494                       << "    The output container has incorrect internal structure." << endmsg;
03495         return status;
03496     }
03497 
03498   // Step III: Connect the topmost intervals into the double linked list.
03499 
03500     theOutPreviousIntervalH = theOutFirstIntervalH;
03501     theOutPreviousIntervalH->getBaselineNext( theOutIntervalH );
03502 
03503     while( theOutIntervalH != theOutLastIntervalH ) {
03504 
03505         status = linkTopIntervalsInSubTree( theOutIntervalH,
03506                                             theOutPreviousIntervalH );
03507         if( BdbcSuccess != status ) {
03508             ErrMsg(error) << errorString << endl
03509                           << "    Failed to process the next tree of versions." << endmsg;
03510             return status;
03511         }
03512 
03513         theOutIntervalH->getBaselineNext( theOutNextIntervalH );
03514         theOutIntervalH = theOutNextIntervalH;
03515     }
03516 
03517     theOutPreviousIntervalH->setTopNext( theOutLastIntervalH );
03518     theOutLastIntervalH->setTopPrevious( theOutPreviousIntervalH );
03519 
03520     return BdbcSuccess;
03521 }
03522 
03523 BdbStatus
03524 BdbCondDatabaseMgr::baselineOrTopmostCopy( BdbObsoleteDatabase& theInDb,
03525                                            BdbObsoleteDatabase& theOutDb,
03526                                            bool         baselineFlag )
03527 {
03528     const char* errorString = "BdbCondDatabaseMgr::baselineOrTopmostCopy() -- error.";
03529 
03530     BdbStatus status = BdbcError;
03531 
03532     BdbHandle(BdbIntervalR) theInFirstIntervalH;
03533     BdbHandle(BdbIntervalR) theInPreviousIntervalH;
03534     BdbHandle(BdbIntervalR) theInIntervalH;
03535     BdbHandle(BdbIntervalR) theInNextIntervalH;
03536     BdbHandle(BdbIntervalR) theInLastIntervalH;
03537 
03538     BdbHandle(BdbIntervalR) theOutFirstIntervalH;
03539     BdbHandle(BdbIntervalR) theOutPreviousIntervalH;
03540     BdbHandle(BdbIntervalR) theOutIntervalH;
03541     BdbHandle(BdbIntervalR) theOutLastIntervalH;
03542 
03543   // Locate the "border" intervals in both containers.
03544 
03545     status = locateBorderIntervals( theInDb,
03546                                     theOutDb,
03547                                     theInFirstIntervalH,
03548                                     theInLastIntervalH,
03549                                     theOutFirstIntervalH,
03550                                     theOutLastIntervalH );
03551     if( BdbcSuccess != status ) {
03552         return status;
03553     }
03554 
03555   // Get the handles for the output container itself and its baseline
03556   // revision.
03557   // We expect that these values are cached by the previous procedure.
03558 
03559     BdbHandle(BdbContObj) theOutContH;
03560     theOutDb.getIntervalContH( theOutContH );
03561 
03562     BdbHandle(BdbCondRevision) theOutBaselineRevisionH;
03563     theOutDb.getBaselineRevisionH( theOutBaselineRevisionH );
03564 
03565   // Delete the LAST interval from the output container.
03566   // This interval was created temporarily.
03567 
03568     theOutFirstIntervalH->getBaselineNext( theOutIntervalH );
03569     if( theOutIntervalH != theOutLastIntervalH ) {
03570         ErrMsg(error) << errorString << endl
03571                       << "    The output container has incorrect initial structure." << endmsg;
03572         return BdbcError;
03573     }
03574     BdbDelete( theOutLastIntervalH );
03575 
03576   // Locate the FIRST->NEXT interval from the input container.
03577   // This interval must exist.
03578 
03579     if( baselineFlag ) {
03580         theInFirstIntervalH->getBaselineNext( theInIntervalH );
03581     } else {
03582         theInFirstIntervalH->getTopNext( theInIntervalH );
03583     }
03584     if( BdbIsNull( theInIntervalH )) {
03585         ErrMsg(error) << errorString << endl
03586                       << "    The input container has incorrect structure." << endmsg;
03587         return BdbcError;
03588     }
03589 
03590   // Iterate over the list of baseline intervals and create duplicates
03591   // in the corresponding places.
03592 
03593     theOutFirstIntervalH->setObject          ( theInFirstIntervalH->getObject( ));
03594     theOutFirstIntervalH->setVersionTime     ( theInFirstIntervalH->getVersionTime( ));
03595     theOutFirstIntervalH->setTag             ( theInFirstIntervalH->getTag( ));
03596     theOutFirstIntervalH->setTopPrevious     ( NULL );
03597     theOutFirstIntervalH->setTopNext         ( NULL );
03598     theOutFirstIntervalH->setBaselinePrevious( NULL );
03599     theOutFirstIntervalH->setBaselineNext    ( NULL );
03600     theOutFirstIntervalH->setRevision        ( theOutBaselineRevisionH );
03601 
03602     theOutPreviousIntervalH = theOutFirstIntervalH;
03603 
03604     do {
03605 
03606       // Make a copy of an input interval within the output container.
03607 
03608         theOutIntervalH = new( theOutContH ) BdbIntervalR( theInIntervalH->getObject( ),
03609                                                            theInIntervalH->getBeginTime( ),
03610                                                            theInIntervalH->getEndTime( ),
03611                                                            theInIntervalH->getTag( ));
03612 
03613         theOutIntervalH->setVersionTime( theInIntervalH->getVersionTime( ));
03614 
03615       // Always connect interval to the baseline revision.
03616 
03617         theOutIntervalH->setRevision( theOutBaselineRevisionH );
03618 
03619       // Include this interval into the list 
03620 
03621         theOutPreviousIntervalH->setTopNext(      theOutIntervalH );
03622         theOutPreviousIntervalH->setBaselineNext( theOutIntervalH );
03623 
03624         theOutIntervalH->setTopPrevious(      theOutPreviousIntervalH );
03625         theOutIntervalH->setTopNext(          NULL );
03626         theOutIntervalH->setBaselinePrevious( theOutPreviousIntervalH );
03627         theOutIntervalH->setBaselineNext(     NULL );
03628 
03629       // Advance pointers for both containers.
03630 
03631         if( baselineFlag ) {
03632             theInIntervalH->getBaselineNext( theInNextIntervalH );
03633         } else {
03634             theInIntervalH->getTopNext( theInNextIntervalH );
03635         }
03636         theInIntervalH = theInNextIntervalH;
03637 
03638         theOutPreviousIntervalH = theOutIntervalH;
03639         theOutLastIntervalH     = theOutIntervalH;
03640 
03641     } while( ! BdbIsNull( theInIntervalH ));
03642 
03643   // Set the proper scope name to the LAST interval in the output container.
03644 
03645     theOutLastIntervalH.nameObj( theOutContH, "LastInterval" );
03646 
03647     return BdbcSuccess;
03648 }
03649 
03650 BdbStatus
03651 BdbCondDatabaseMgr::revisionCopy( BdbObsoleteDatabase& theInDb,
03652                                   BdbObsoleteDatabase& theOutDb,
03653                                   d_ULong      theRevId )
03654 {
03655     const char* errorString = "BdbCondDatabaseMgr::revisionCopy() -- error.";
03656 
03657     BdbStatus status = BdbcError;
03658 
03659   // A minor optimizaton of the baseline revision ID has
03660   // been specified.
03661 
03662     if( BdbCondRevision::BASELINE == theRevId ) {
03663         return baselineOrTopmostCopy( theInDb, theOutDb, true );
03664     }
03665 
03666   // For any other revision this operation is not implemented yet.
03667 
03668     ErrMsg(error) << errorString << endl
03669                   << "    The operation is not implemented yet." << endmsg;
03670 
03671     return BdbcError;
03672 }
03673 
03674 BdbStatus
03675 BdbCondDatabaseMgr::locateBorderIntervals( BdbObsoleteDatabase&            theInDb,
03676                                            BdbObsoleteDatabase&            theOutDb,
03677                                            BdbHandle(BdbInterval)& theInFirstIntervalH,
03678                                            BdbHandle(BdbInterval)& theInLastIntervalH,
03679                                            BdbHandle(BdbInterval)& theOutFirstIntervalH,
03680                                            BdbHandle(BdbInterval)& theOutLastIntervalH )
03681 {
03682     const char* errorString = "BdbCondDatabaseMgr::locateBorderIntervals() -- error.";
03683 
03684     BdbStatus status = BdbcError;
03685 
03686     status = theInDb.firstInterval( theInFirstIntervalH, theInDb.containerName( ));
03687     if(( BdbcSuccess != status ) || ( BdbIsNull( theInFirstIntervalH ))) {
03688         ErrMsg(error) << errorString << endl
03689                       << "    Failed to locate the FIRST interval in the input container." << endmsg;
03690         return BdbcError;
03691     }
03692 
03693     status = theInDb.lastInterval( theInLastIntervalH, theInDb.containerName( ));
03694     if(( BdbcSuccess != status ) || ( BdbIsNull( theInLastIntervalH ))) {
03695         ErrMsg(error) << errorString << endl
03696                       << "    Failed to locate the LAST interval in the input container." << endmsg;
03697         return BdbcError;
03698     }
03699 
03700     status = theOutDb.firstInterval( theOutFirstIntervalH, theOutDb.containerName( ));
03701     if(( BdbcSuccess != status ) || ( BdbIsNull( theOutFirstIntervalH ))) {
03702         ErrMsg(error) << errorString << endl
03703                       << "    Failed to locate the FIRST interval in the output container." << endmsg;
03704         return BdbcError;
03705     }
03706 
03707     status = theOutDb.lastInterval( theOutLastIntervalH, theOutDb.containerName( ));
03708     if(( BdbcSuccess != status ) || ( BdbIsNull( theOutLastIntervalH ))) {
03709         ErrMsg(error) << errorString << endl
03710                       << "    Failed to locate the LAST interval in the output container." << endmsg;
03711         return BdbcError;
03712     }
03713 
03714     return BdbcSuccess;
03715 }
03716 
03717 BdbStatus
03718 BdbCondDatabaseMgr::matchRevision( const BdbHandle(BdbIntervalR)& theInNextIntervalH,
03719                                    BdbObsoleteDatabase&                   theOutDb,
03720                                    BdbHandle(BdbCondRevision)&    theOutRevisionH )
03721 {
03722     BdbStatus status = BdbcSuccess;
03723     BdbHandle(BdbCondRevision) theInRevisionH;
03724 
03725     theInNextIntervalH->getRevision( theInRevisionH );
03726     if( BdbIsNull( theInRevisionH )) {
03727         theOutRevisionH = NULL;
03728         status = BdbcSuccess;
03729     } else {
03730 
03731         BdbHandle(BdbCondRegistry) theOutRegistryH;
03732         theOutDb.getRegistryH( theOutRegistryH );
03733 
03734         theOutRegistryH->getRevision( theOutRevisionH,
03735                                       theInRevisionH->id( ));
03736         if( BdbIsNull( theOutRevisionH )) {
03737             status = BdbcError;
03738         }
03739     }
03740 
03741     return status;
03742 }
03743 
03744 BdbStatus
03745 BdbCondDatabaseMgr::linkTopIntervalsInSubTree( const BdbHandle(BdbIntervalR)& theIntervalH,
03746                                                BdbHandle(BdbIntervalR)&       thePreviousIntervalH )
03747 {
03748     const char* errorString = "BdbCondDatabaseMgr::linkTopIntervalsInSubTree() -- error.";
03749 
03750     BdbStatus status = BdbcError;
03751 
03752   // This check will prevent us from accidental crashing.
03753 
03754     if( BdbIsNull( theIntervalH ) || BdbIsNull( thePreviousIntervalH )) {
03755         ErrMsg(error) << errorString << endl
03756                       << "    NULL handles have been detected." << endl
03757                       << "    The output container may have incorrect internal structure." << endmsg;
03758         return BdbcError;
03759     }
03760 
03761   // Iterate over sub-tree(s) (if any).
03762 
03763     bool subTreeFound = false;
03764 
03765     BdbItr(BdbPersObj) theItr;
03766 
03767     theIntervalH->nextVers( theItr );
03768     while( theItr.next( )) {
03769 
03770         status = linkTopIntervalsInSubTree( (BdbHandle(BdbIntervalR)&) theItr,
03771                                             thePreviousIntervalH );
03772         if( BdbcSuccess != status ) {
03773             return status;
03774         }
03775 
03776         subTreeFound = true;
03777     }
03778 
03779   // If the subtree was not found this means that the current interval
03780   // is the TOPMOST one and must be included into the list.
03781 
03782     if ( ! subTreeFound ) {
03783 
03784         thePreviousIntervalH->setTopNext( theIntervalH );
03785         theIntervalH->setTopPrevious( thePreviousIntervalH );
03786 
03787         thePreviousIntervalH = theIntervalH;
03788     }
03789 
03790     return BdbcSuccess;
03791 }
03792 
03793 BdbStatus
03794 BdbCondDatabaseMgr::copySubTree( const BdbHandle(BdbIntervalR)& theInIntervalH,
03795                                  BdbObsoleteDatabase&                   theOutDb,
03796                                  BdbHandle(BdbIntervalR)&       theOutIntervalH )
03797 {
03798     const char* errorString = "BdbCondDatabaseMgr::copySubTree() -- error.";
03799 
03800     BdbStatus status = BdbcError;
03801     
03802     int i;
03803 
03804   // This check will prevent us from accidental crashing.
03805 
03806     if( BdbIsNull( theInIntervalH ) || BdbIsNull( theOutIntervalH )) {
03807         ErrMsg(error) << errorString << endl
03808                       << "    NULL handles have been detected." << endl
03809                       << "    The output container may have incorrect internal structure." << endmsg;
03810         return BdbcError;
03811     }
03812 
03813   // Get sub-trees (if any).
03814 
03815     vector<BdbHandle(BdbIntervalR)> theInNextIntervalH;
03816     BdbItr(BdbPersObj)                           theItr;
03817 
03818     theInIntervalH->nextVers( theItr );
03819     while( theItr.next( )) {
03820         theInNextIntervalH.push_back((BdbHandle(BdbIntervalR)&) theItr );
03821     }
03822 
03823   // Create duplicate sub-trees in the output container if at leas one
03824   // sub-tree was found in the input one.
03825 
03826     int numSubTrees = theInNextIntervalH.size( );
03827 
03828     if( numSubTrees > 0 ) {
03829 
03830       // Enable linear/branch versioning on the original interval object.
03831 
03832         if( numSubTrees == 1 ) {
03833             theOutIntervalH.setVersStatus( oocLinearVers );
03834         } else {
03835             theOutIntervalH.setVersStatus( oocBranchVers );
03836         }
03837 
03838       // Create as many linear/branch version(s) for the output interval
03839       // as it were found for the input interval.
03840 
03841         BdbHandle(BdbIntervalR)                      theOutNewIntervalH;
03842         vector<BdbHandle(BdbIntervalR)> theOutNextIntervalH;
03843 
03844         for( i = 0; i < numSubTrees; i++ ) {
03845             theOutDb.createVersion( theOutIntervalH, theOutNewIntervalH );
03846             theOutNextIntervalH.push_back( theOutNewIntervalH );
03847         }
03848 
03849       // Disable versioning of the current interval.
03850 
03851         theOutIntervalH.setVersStatus( oocNoVers );
03852 
03853       // Copy the interval name in the scope of the genealogy object
03854       // with the following steps:
03855       //
03856       //    1. Locate a genealogy object for the input version tree (must exist).
03857       //    2. Locate or create the genealogy object for the output tree.
03858       //    3. Copy the version name of the input branch interval into the output one.
03859       //    4. Copy the last known (to the input genealogy object) into
03860       //       output genealogy object.
03861 
03862         BdbHandle(BdbIntervalGene) theInGeneH;
03863         if( ! theInIntervalH->exist_geneObj( )) {
03864             ErrMsg(error) << errorString << endl
03865                           << "    The genealogy object does not exist for an interval." << endl
03866                           << "    The input container may have incorrect internal structure." << endmsg;
03867             return BdbcError;
03868         }
03869         theInGeneH = (const BdbHandle(BdbIntervalGene)&) theInIntervalH->geneObj( );
03870 
03871         BdbHandle(BdbIntervalGene) theOutGeneH;
03872         if( theOutIntervalH->exist_geneObj( )) {
03873 
03874           // Use existing genealogy object.
03875 
03876             theOutGeneH = (const BdbHandle(BdbIntervalGene)&) theOutIntervalH->geneObj( );
03877 
03878         } else {
03879 
03880           // Crate new genealogy object. Name the current version (which is expected
03881           // to be a BASELINE interval) in the scope of ths ngenealogy object.
03882 
03883             theOutGeneH = new( theOutIntervalH ) BdbIntervalGene( );
03884 
03885             theOutIntervalH.nameObj( theOutGeneH, theInIntervalH.getObjName( theInGeneH ));
03886 
03887             theOutGeneH->set_defaultVers( theOutIntervalH );
03888             theOutGeneH->add_allVers(     theOutIntervalH );
03889         }
03890 
03891       // Attach newely created versions to the Genealogy object and name
03892       // these versions.
03893 
03894         for( i = 0; i < numSubTrees; i++ ) {
03895             theOutGeneH->add_allVers( theOutNextIntervalH[i] );
03896             theOutNextIntervalH[i].nameObj( theOutGeneH, theInNextIntervalH[i].getObjName( theInGeneH ));
03897             theOutGeneH->setVersionName( theInGeneH->getVersionName( ));
03898         }
03899 
03900       // Copy information from the input intervals into the output ones.
03901 
03902         for( i = 0; i < numSubTrees; i++ ) {
03903 
03904           // Copy the basic characteristics.
03905 
03906             theOutNextIntervalH[i]->setObject(      theInNextIntervalH[i]->getObject( ));
03907             theOutNextIntervalH[i]->setBeginTime(   theInNextIntervalH[i]->getBeginTime( ));
03908             theOutNextIntervalH[i]->setEndTime(     theInNextIntervalH[i]->getEndTime( ));
03909             theOutNextIntervalH[i]->setVersionTime( theInNextIntervalH[i]->getVersionTime( ));
03910             theOutNextIntervalH[i]->setTag(         theInNextIntervalH[i]->getTag( ));
03911 
03912           // Copy a revision.
03913 
03914             BdbHandle(BdbCondRevision) theOutRevisionH;
03915 
03916             status = matchRevision( theInNextIntervalH[i],
03917                                     theOutDb,
03918                                     theOutRevisionH );
03919             if( BdbcSuccess != status ) {
03920                 ErrMsg(error) << errorString << endl
03921                               << "    Failed to locate a matching revision for an interval." << endl
03922                               << "    The output container may have incorrect internal structure." << endmsg;
03923                 return status;
03924             }
03925             theOutNextIntervalH[i]->setRevision( theOutRevisionH );
03926         }
03927 
03928       // Proceed alongside the version tree.
03929 
03930         for( i = 0; i < numSubTrees; i++ ) {
03931 
03932             status = copySubTree( theInNextIntervalH[i],
03933                                   theOutDb,
03934                                   theOutNextIntervalH[i] );
03935             if( BdbcSuccess != status ) {
03936                 ErrMsg(error) << errorString << endl
03937                               << "    Failed to copy the next tree of versions." << endmsg;
03938                 return status;
03939             }
03940         }
03941     }
03942 
03943     return BdbcSuccess;
03944 }
03945 
03946 BdbStatus
03947 BdbCondDatabaseMgr::copyObjects( BdbObsoleteDatabase& theDb,
03948                                  bool         copyToLocalDb,
03949                                  const char*  theContName )
03950 {
03951     const char* errorString = "BdbCondDatabaseMgr::copyObjects() -- error.";
03952 
03953     BdbStatus status = BdbcError;
03954 
03955   // Locate the FIRST interval in the container to start with.
03956 
03957     BdbHandle(BdbIntervalR) theIntervalH;
03958     BdbHandle(BdbIntervalR) theNextIntervalH;
03959 
03960     status = theDb.firstInterval( theIntervalH, theDb.containerName( ));
03961     if(( BdbcSuccess != status ) || ( BdbIsNull( theIntervalH ))) {
03962         ErrMsg(error) << errorString << endl
03963                       << "    Failed to locate the FIRST interval in the output container." << endmsg;
03964         return BdbcError;
03965     }
03966 
03967   // If the copy to local Db is required then we shall open/create
03968   // a container with a predefined name within the same interval database
03969   // and to use this container as a handle for the copied of Conditions objects.
03970   //
03971   //    NOTE_1: We allow to put data in different containers of the same
03972   //            database because of the addressing limitation of an individual
03973   //            container.
03974   //            A container is able to keep up to 64K pages. Currently the page
03975   //            size is set to 16KB. This would imply just 1GB limit onto the amount
03976   //            of data to be stored in a single container.
03977   //
03978   //    NOTE_2: In some future more sophisticated container handling logic could
03979   //            be implemented. For example, when specified container is full
03980   //            then anbother one with incremented suffix will be created.
03981   //
03982   //                _DATA_0
03983   //                _DATA_1
03984   //                _DATA_2
03985   //
03986   //            to increase the available space without
03987 
03988     BdbHandle(BdbContObj) theLocalContH;
03989 
03990     if( copyToLocalDb ) {
03991 
03992         if( theContName == (char*) 0 ) {
03993             ErrMsg(error) << errorString << endl
03994                           << "    Zero container name has been specified for the local container." << endl
03995                           << "    The local container is ment to keep local copies of Conditions data" << endl
03996                           << "    whihin the same interval database." << endmsg;
03997             return BdbcError;
03998         }
03999 
04000       // Try to locate if the container already exist.
04001 
04002         BdbHandle(BdbDBObj) theIntervalDBH;
04003         theDb.getIntervalDBH( theIntervalDBH );
04004 
04005         if( d_True == theLocalContH.exist( theIntervalDBH, theContName, BdbcNoOpen )) {
04006             status = theLocalContH.open( theIntervalDBH, theContName, BdbcUpdate );
04007             if(( BdbcSuccess != status ) || BdbIsNull(theLocalContH)) {
04008                 ErrMsg(error) << errorString << endl
04009                               << "    Failed to open existing container \"" << theContName << "\""<< endl
04010                               << "    in the output database in UPDATE mode." << endl
04011                               << "    The container is ment to keep local copies of Conditions objects." << endmsg;
04012                return BdbcError;
04013             }
04014         }
04015         if( BdbIsNull( theLocalContH )) {
04016 
04017           // Create a new container.
04018 
04019             theLocalContH = new( theContName, 1, 4, 10, theIntervalDBH ) BdbContObj( );
04020             if( BdbIsNull( theLocalContH )) {
04021                 ErrMsg(error) << errorString << endl
04022                               << "    Failed to create a container container \"" << theContName << "\""<< endl
04023                               << "    in the output database. The container is ment to keep local copies" << endl
04024                               << "    of Conditions objects." << endmsg;
04025                     return BdbcError;
04026             }
04027         }
04028     }
04029 
04030   // Process the container as a sequence of sub-trees growing
04031   // from baseline intervals.
04032 
04033     BdbCondCache<BdbRefAny>* theCache = new BdbCondTransientCache( );
04034 
04035     ooCheckVTablePointer( d_True );
04036 
04037     do {
04038 
04039         status = copyObjectsInSubTree( theIntervalH,
04040                                        copyToLocalDb,
04041                                        theLocalContH,
04042                                        theDb._myHint,
04043                                        theCache );
04044         if( BdbcSuccess != status ) {
04045             ErrMsg(error) << errorString << endl
04046                           << "    Failed to copy objects for the next sub-tree." << endmsg;
04047             delete theCache;
04048             return BdbcError;
04049         }
04050 
04051         theIntervalH->getBaselineNext( theNextIntervalH );
04052         theIntervalH = theNextIntervalH;
04053 
04054     } while( ! BdbIsNull( theIntervalH ));
04055 
04056     delete theCache;
04057 
04058     return BdbcSuccess;
04059 }
04060 
04061 BdbStatus
04062 BdbCondDatabaseMgr::copyObjectsInSubTree( BdbHandle(BdbInterval)&          theIntervalH,
04063                                           bool                             copyToLocalDb,
04064                                           const BdbHandle(BdbContObj)&     theLocalContH,
04065                                           BdbCondClusteringHint*           theHint,
04066                                           BdbCondCache<BdbRefAny>* theCache )
04067 {
04068     const char* errorString = "BdbCondDatabaseMgr::copyObjectsInSubTree() -- error.";
04069 
04070     BdbStatus status = BdbcError;
04071 
04072   // Copy object for current handle.
04073 
04074     BdbRef(BdbObject) theOldObjectR;
04075     BdbRef(BdbObject) theNewObjectR;
04076 
04077     theIntervalH->getObject( theOldObjectR );
04078     if( ! BdbIsNull( theOldObjectR )) {
04079 
04080       // Make a copy of the persistent object.
04081       //
04082       //     NOTE: We are passing a pointer to the cache object
04083       //           to the ::clone() method. So the object itself
04084       //           would be responsible for the cache maintainance.
04085       //
04086       //     NOTE: The following code may crash if the corresponding virtual
04087       //           table for the real persistent classes is not loaded.
04088 
04089         if( copyToLocalDb ) {
04090             theNewObjectR = theOldObjectR->clone( theLocalContH, theCache );
04091         } else {
04092             theNewObjectR = theOldObjectR->clone( theHint->updatedHint( ), theCache );
04093         }
04094 
04095       // Replace an object for the current interval.
04096 
04097         theIntervalH->setObject( theNewObjectR );
04098     }
04099 
04100   // Propagate along the branches (if any).
04101 
04102     BdbItr(BdbPersObj) theItr;
04103 
04104     if( theIntervalH->exist_geneObj( )) {
04105         theIntervalH->nextVers( theItr );
04106         while( theItr.next( )) {
04107             status = copyObjectsInSubTree((BdbHandle(BdbInterval)&) theItr,
04108                                            copyToLocalDb,
04109                                            theLocalContH,
04110                                            theHint,
04111                                            theCache );
04112             if( BdbcSuccess != status ) {
04113                 return status;
04114             }
04115         }
04116     }
04117 
04118     return BdbcSuccess;
04119 }
04120 
04121 void
04122 BdbCondDatabaseMgr::deleteIntervalsInSubTree( BdbHandle(BdbIntervalR)& theIntervalH,
04123                                               bool                     deleteGeneObject )
04124 {
04125   // First of all we propagate recursively along the branches (if any)
04126   // and delete intervals there.
04127 
04128     BdbItr(BdbPersObj) theItr;
04129 
04130     if( theIntervalH->exist_geneObj( )) {
04131         theIntervalH->nextVers( theItr );
04132         while( theItr.next( )) {
04133             deleteIntervalsInSubTree((BdbHandle(BdbIntervalR)&) theItr );
04134         }
04135     }
04136 
04137   // Then we delete the genealogy object if required.
04138 
04139     if( deleteGeneObject && theIntervalH->exist_geneObj( )) {
04140 
04141         BdbHandle(BdbIntervalGene) theGeneObjH;
04142         theGeneObjH = (const BdbHandle(BdbIntervalGene)&) theIntervalH->geneObj( );
04143 
04144         BdbDelete(theGeneObjH);
04145     }
04146 
04147   // And finally we delete current interval itself.
04148 
04149     BdbDelete( theIntervalH );
04150 
04151     return;
04152 }
04153 
04154 void
04155 BdbCondDatabaseMgr::deleteObjectsInSubTree( BdbHandle(BdbInterval)& theIntervalH )
04156 {
04157   // Delete object for current handle and delete it with NULL handle.
04158 
04159     BdbRef(BdbObject) theNullObjectRef;
04160     BdbRef(BdbObject) theObjectRef;
04161 
04162     theIntervalH->getObject( theObjectRef );
04163     if(( ! BdbIsNull( theObjectRef )) && theObjectRef.isValid( )) {
04164         BdbDelete( theObjectRef );
04165         theIntervalH->setObject( theNullObjectRef );
04166     }
04167 
04168   // Propagate along the branches (if any).
04169 
04170     BdbItr(BdbPersObj) theItr;
04171 
04172     if( theIntervalH->exist_geneObj( )) {
04173         theIntervalH->nextVers( theItr );
04174         while( theItr.next( )) {
04175             deleteObjectsInSubTree((BdbHandle(BdbInterval)&) theItr );
04176         }
04177     }
04178 
04179     return;
04180 }
04181 
04182 BdbStatus
04183 BdbCondDatabaseMgr::selectDetectors( vector<string>&       theFinalDetectorsList,
04184                                      const vector<string>& theDetectorsList,
04185                                      bool                                  theExcludeFlag )
04186 {
04187     const char* errorString = "BdbCondDatabaseMgr::selectDetectors() -- ERROR.";
04188 
04189   // Build the list of detectors to look into using either Authorization database
04190   // or a list of detectors supplied by a user, depending on whether the specified
04191   // list is empty or not.
04192   // If the list is not empty, but the  "exclude" flag was specified then we also
04193   // take a list of detectors from the Conditions domain of the Authorization database
04194   // and then will exclude these databases from the list.
04195 
04196     if( theDetectorsList.empty( ) || ( true == theExcludeFlag )) {
04197 
04198       // Obtain the list of all known detectors from the Authorization database.
04199 
04200         BdbAuthItr* itr = BdbAuth::instance( )->createGroupsItr( BdbDomain::Conditions );
04201         {
04202             if(( 0 == itr ) || !itr->isValid( )) {
04203 
04204                 ErrMsg(error) << errorString << endl
04205                               << "    Failed to obtain a list of detectors in Conditions domain." << endl
04206                               << "    See detailed error report from Authorization code." << endmsg;
04207 
04208                 delete itr;
04209 
04210                 return BdbcError;
04211             }
04212 
04213           // Browse the list and filter out special groups and those detectors
04214           // which were found in the user supplied list (if any).
04215 
04216             while( itr->next( )) {
04217 
04218               // Just skip this special group
04219 
04220                 if( 0 == strcmp( "Global", itr->current( ))) {
04221                     continue;
04222                 }
04223 
04224               // Then match for any user supplied detector name if required.
04225 
04226                 if( theExcludeFlag ) {
04227 
04228                     bool detectorWasFound = false;
04229 
04230                     int detectors = theDetectorsList.size( );
04231                     for( int detectorIndex = 0; detectorIndex < detectors; detectorIndex++ ) {
04232                         if( 0 == strcmp( theDetectorsList[detectorIndex].c_str(), itr->current( ))) {
04233                             detectorWasFound = true;
04234                             break;
04235                         }
04236                     }
04237                     if( ! detectorWasFound ) {
04238 
04239                       // The detector was not found - then just include this detector
04240                       // into the final list.
04241 
04242                         theFinalDetectorsList.push_back( itr->current( ));
04243                     }
04244 
04245                 } else {
04246 
04247                   // Just include the current group as is without verification.
04248 
04249                     theFinalDetectorsList.push_back( itr->current( ));
04250                 }
04251             }
04252         }
04253         delete itr;
04254 
04255     } else {
04256 
04257       // Just copy all of these groups into the final list.
04258       // It would be up to the user to provide the correct list.
04259 
04260         theFinalDetectorsList = theDetectorsList;
04261     }
04262 
04263     return BdbcSuccess;
04264 }
04265 
04266 BdbStatus
04267 BdbCondDatabaseMgr::scanContainer( map<string, BdbRef(ooDBObj)>& theDict,
04268                                    BdbObsoleteDatabase&                                      theDb,
04269                                    const char*                                       theContName )
04270 {
04271     const char* errorString = "BdbCondDatabaseMgr::scanContainer( ) -- ERROR.";
04272 
04273     BdbStatus status;
04274     BdbHandle(BdbInterval) theIntervalH;
04275     BdbHandle(BdbInterval) theNextIntervalH;
04276     BdbHandle(BdbObject)   theObjectH;
04277 
04278     char buf[255];
04279 
04280   // Extract the DBs from the objects (if they are non-zero)
04281   // and put them into the hash dictionary as pesistent references.
04282 
04283     status = theDb.firstInterval( theIntervalH, theContName );
04284     if(( BdbcSuccess != status ) || BdbIsNull(theIntervalH)) {
04285         ErrMsg(error) << errorString << endl
04286                       << "    Failed to obtain the FIRST interval from the container." << endl
04287                       << "        DETECTOR  -> " << theDb.subsystemTLA( ) << endl
04288                       << "        CONTAINER -> " << theContName << endmsg;
04289         return BdbcError;
04290     }
04291 
04292   // Take the version trees one-by-one starting from the very first interval.
04293   // Each next tree will be accessed following the "next TOPMOST"
04294   // link until NULLinterval is met.
04295 
04296   // Analyze the FIRST interval itself.
04297 
04298     theObjectH = theIntervalH->getObject( );
04299     if( ! BdbIsNull(theObjectH)) {
04300         ooId theId = theObjectH;
04301         int theDb = theId.get_DB( );
04302         sprintf( buf, "%d", theDb );
04303         theDict[string( buf )].set_DB( theDb );
04304     }
04305 
04306   // Then start working with trees.
04307 
04308     vector<BdbHandle(BdbInterval)> theTree;
04309     int numBranches;
04310 
04311     do {
04312 
04313       // Avoid a problem of "zero" [-oo,-oo] FIRST interval because the next
04314       // interval would also start from [-oo, *]. And this introduces some
04315       // ambiguity into the interval locating algorithm.
04316       // Check also the correct structure of the next interval.
04317 
04318         if( BdbTime::minusInfinity == theIntervalH->endTime( )) {
04319 
04320             theNextIntervalH = theIntervalH->next( );
04321             theIntervalH     = theNextIntervalH;
04322 
04323             if( theIntervalH->beginTime( ) == theIntervalH->endTime( )) {
04324                 ErrMsg(error) << errorString << endl
04325                               << "    The invalid interval found in the container." << endl
04326                               << "        BEGIN TIME -> " << theIntervalH->beginTime( ) << endl
04327                               << "        END TIME   -> " << theIntervalH->endTime( ) << endl
04328                               << "        DETECTOR   -> " << theDb.subsystemTLA( ) << endl
04329                               << "        CONTAINER  -> " << theContName << endmsg;
04330                 return BdbcError;
04331             }
04332             status = theDb.getTree( theTree, numBranches, theContName, theIntervalH->beginTime( ) + 1 );
04333         } else {
04334             status = theDb.getTree( theTree, numBranches, theContName, theIntervalH->beginTime( ));
04335         }
04336         if(( BdbcSuccess != status ) || ( numBranches <= 0 )) {
04337             ErrMsg(error) << errorString << endl
04338                           << "    Failed to obtain the version tree from the container." << endl
04339                           << "        BEGIN TIME -> " << theIntervalH->beginTime( ) << endl
04340                           << "        DETECTOR   -> " << theDb.subsystemTLA( ) << endl
04341                           << "        CONTAINER  -> " << theContName << endmsg;
04342             return BdbcError;
04343         }
04344 
04345         int entries = theTree.size( );
04346         for( int i = 0; i < entries; i++ ) {
04347 
04348           // Skip NULL delimiters.
04349 
04350             if( ! BdbIsNull(theTree[i])) {
04351 
04352                 theIntervalH = theTree[i];
04353 
04354                 theObjectH = theIntervalH->getObject( );
04355                 if( ! BdbIsNull(theObjectH)) {
04356                     ooId theId = theObjectH;
04357                     int theDb = theId.get_DB( );
04358                     sprintf( buf, "%d", theDb );
04359                     theDict[string( buf )].set_DB( theDb );
04360                 }
04361             }
04362         }
04363 
04364         theNextIntervalH = theIntervalH->next( );
04365         theIntervalH     = theNextIntervalH;
04366 
04367     } while( ! BdbIsNull(theIntervalH));
04368 
04369     return BdbcSuccess;
04370 }
04371 
04372 BdbStatus
04373 BdbCondDatabaseMgr::copySubSequenceOfBaselineIntervals( BdbObsoleteDatabase&                   theInDb,
04374                                                         const BdbHandle(BdbIntervalR)& theInBeginBaselineIntervalH,
04375                                                         const BdbHandle(BdbIntervalR)& theInEndBaselineIntervalH,
04376                                                         BdbObsoleteDatabase&                   theOutDb,
04377                                                         BdbHandle(BdbIntervalR)&       theOutBeginBaselineIntervalH,
04378                                                         BdbHandle(BdbIntervalR)&       theOutEndBaselineIntervalH )
04379 {
04380     const char* errorString = "BdbCondDatabaseMgr::copySubSequenceOfBaselineIntervals( ) -- ERROR.";
04381 
04382     BdbStatus status;
04383 
04384   // NOTES:
04385   //
04386   //    1. This procedure is not meant to copy the FIRST and LAST intervals.
04387   //    2. It's expected that the context of the "BdbObsoleteDatabase" objects has already
04388   //       been set.
04389   //    3. The algorithm may also work well if both the input and the output
04390   //       subsequences belong to the same interval container.
04391   //    4. This procedure does not connect the newly created leftmost and rightmost
04392   //       intervals correctly. It's being assumed a task of the caller.
04393   //    5. The topmost links for the new sub-sequence are not set. It's being assuming
04394   //       a prerogative of the caller.
04395 
04396   // These parameters will be set to correct values upon the completion
04397   // of the procedure.
04398 
04399     theOutBeginBaselineIntervalH = 0;
04400     theOutEndBaselineIntervalH   = 0;
04401 
04402   // Get handles of the output container and a baseline revision in it.
04403   // We are going to use these handles as a clustering hint for the newely
04404   // created objects and as their baseline revision respectivly.
04405 
04406     BdbHandle(BdbContObj)      theOutContH;
04407     BdbHandle(BdbCondRevision) theOutBaselineRevisionH;
04408 
04409     theOutDb.getIntervalContH( theOutContH );
04410     if ( BdbIsNull(theOutContH)) {
04411         ErrMsg(error) << errorString << endl
04412                       << "    Unable to obtain a handle for the output container." << endl
04413                       << "    The context of the transient BdbObsoleteDatabase object for this interval container" << endl
04414                       << "    has not been set properly before calling the procedure" << endmsg;
04415         return BdbcError;
04416     }
04417 
04418     theOutDb.getBaselineRevisionH( theOutBaselineRevisionH );
04419     if ( BdbIsNull(theOutBaselineRevisionH)) {
04420         ErrMsg(error) << errorString << endl
04421                       << "    Unable to obtain a handle for the baseline revision of the output container." << endl
04422                       << "    The context of the transient BdbObsoleteDatabase object for this interval container" << endl
04423                       << "    has not been set properly before calling the procedure" << endmsg;
04424         return BdbcError;
04425     }
04426 
04427   // Iterate over the input list of baseline intervals and copy these
04428   // intervals into an output baseline sub-sequence.
04429 
04430     BdbHandle(BdbIntervalR) theInNextBaselineIntervalH;
04431     BdbHandle(BdbIntervalR) theInBaselineIntervalH;
04432 
04433     BdbHandle(BdbIntervalR) theOutPreviousBaselineIntervalH;
04434     BdbHandle(BdbIntervalR) theOutBaselineIntervalH;
04435 
04436     theInNextBaselineIntervalH      = theInBeginBaselineIntervalH;
04437     theOutPreviousBaselineIntervalH = 0;
04438 
04439     do {
04440 
04441         theInBaselineIntervalH = theInNextBaselineIntervalH;
04442 
04443       // Make a copy of an input interval within the output container.
04444 
04445         theOutBaselineIntervalH = new(theOutContH) BdbIntervalR( theInBaselineIntervalH->getObject( ),
04446                                                                  theInBaselineIntervalH->getBeginTime( ),
04447                                                                  theInBaselineIntervalH->getEndTime( ),
04448                                                                  theInBaselineIntervalH->getTag( ));
04449 
04450         theOutBaselineIntervalH->setVersionTime( theInBaselineIntervalH->getVersionTime( ));
04451         theOutBaselineIntervalH->setRevision( theOutBaselineRevisionH );
04452 
04453       // Include this interval into the BASELINE list only.
04454 
04455         if ( ! BdbIsNull(theOutPreviousBaselineIntervalH))  {
04456             theOutPreviousBaselineIntervalH->setBaselineNext( theOutBaselineIntervalH );
04457         }
04458         theOutBaselineIntervalH->setBaselinePrevious( theOutPreviousBaselineIntervalH );
04459 
04460       // Advance pointers in both containers.
04461 
04462         theInBaselineIntervalH->getBaselineNext( theInNextBaselineIntervalH );
04463         theOutPreviousBaselineIntervalH = theOutBaselineIntervalH;
04464 
04465       // Set un-initialized output handle for the very first output interval
04466       // if it's not been set. This has been done for the very first handle
04467       // in the sub-sequence.
04468 
04469         if ( BdbIsNull(theOutBeginBaselineIntervalH)) {
04470             theOutBeginBaselineIntervalH = theOutBaselineIntervalH;
04471         }
04472 
04473     } while( theInBaselineIntervalH != theInEndBaselineIntervalH );
04474 
04475   // Set the un-initialized output handle for the very last output interval
04476   // using the most recently created handle.
04477 
04478     theOutEndBaselineIntervalH = theOutBaselineIntervalH;
04479 
04480     return BdbcSuccess;
04481 }
04482 
04483 BdbStatus
04484 BdbCondDatabaseMgr::copyTopIntervalsInSubTree( BdbObsoleteDatabase&                   theDb,
04485                                                const BdbHandle(BdbIntervalR)& theInBaseIntervalH,
04486                                                BdbHandle(BdbIntervalR)&       theOutBaseIntervalH,
04487                                                bool                           keepRevisedIntervals,
04488                                                d_ULong                        maxNumOfTopLayers,
04489                                                d_ULong                        maxNumOfLayersUnderRevisedInterval )
04490 {
04491     const char* errorString = "BdbCondDatabaseMgr::copyTopIntervalsInSubTree( ) -- ERROR.";
04492 
04493     BdbStatus status;
04494 
04495   // Just return if no Genealogy object exist for specified base interval.
04496   // This is a case when specified base interval is a baseline one without
04497   // any versions above.
04498 
04499     if ( ! theInBaseIntervalH->exist_geneObj( )) {
04500         return BdbcSuccess;
04501     }
04502 
04503   // Always set the versioning status of specified _output_ base interval as "multiple".
04504   // We will correct this later, when all the input versions are analysed and
04505   // sufficient output versions are created.
04506 
04507     theOutBaseIntervalH.setVersStatus( oocBranchVers );
04508 
04509   // Now we are about to run two iterations over the lists of child intervals
04510   // of the current baseline one.
04511   //
04512   // NOTE: We could optimize this part of code if we stored the results of
04513   //       the first iteration in a RW vector.
04514 
04515     BdbHandle(BdbIntervalR) theInIntervalH;
04516     BdbHandle(BdbIntervalR) theOutIntervalH;
04517     BdbRef(BdbCondRevision) theRevisionRef;
04518     BdbItr(BdbPersObj)      theInItr;
04519 
04520   // ITERATION I: (optional)
04521   //
04522   //    If the revisions must be kept then iterate over the list of versions of
04523   //    specified base interval and check if there is at least one explicitly revised
04524   //    interval. If so then all the children of the current base interval should
04525   //    be unconditionally copied.
04526   //
04527   //    NOTE: This algorithm works till the very first revised interval is met.
04528 
04529     bool copyAnyway = false;
04530 
04531     if ( keepRevisedIntervals ) {
04532 
04533         theInBaseIntervalH->nextVers( theInItr );
04534         while ( theInItr.next( )) {
04535 
04536             theInIntervalH = (BdbHandle(BdbIntervalR)&) theInItr;
04537             theRevisionRef = theInIntervalH->getRevision( );
04538             if ( ! BdbIsNull(theRevisionRef)) {
04539                 copyAnyway = true;
04540                 break;
04541             }
04542         }
04543     }
04544 
04545   // ITERATION II: (mandatory)
04546   //
04547   //    Now we've got all missing corrections before to proceed processing intervals
04548   //    at the current layer.
04549 
04550     theInBaseIntervalH->nextVers( theInItr );
04551     while ( theInItr.next( )) {
04552 
04553         theInIntervalH = (BdbHandle(BdbIntervalR)&) theInItr;
04554         theRevisionRef = theInIntervalH->getRevision( );
04555 
04556       // Check if any of the following conditions is true:
04557       //
04558       //    - the input interval version is meant to fill the "revision hole" ("copyAnyway");
04559       //    - the interval is explicitly connected to a revision (if this is required);
04560       //    - the interval is "close enough" to the revised interval (if required);
04561       //    - the interval is "close enough" to the top of the versioning tree.
04562 
04563         if ( copyAnyway ||
04564              ( keepRevisedIntervals && ( ! BdbIsNull(theRevisionRef))) ||
04565              ( keepRevisedIntervals && hasAnyRevisedIntervalAsCloaseAs( theInIntervalH, maxNumOfLayersUnderRevisedInterval )) ||
04566              hasAnyTopIntervalAsCloaseAs( theInIntervalH, maxNumOfTopLayers )) {
04567 
04568           // Since we have either an explicit revision for this interval (if this was required)
04569           // or we can see a top withing specified distance then we should
04570           // make a copy of this input interval and to attach it as a version
04571           // to the current output base.
04572 
04573             theDb.createVersion( theOutBaseIntervalH, theOutIntervalH );
04574             theDb.nameVersion( theOutBaseIntervalH, theOutIntervalH );
04575 
04576             theOutIntervalH->setObject(      theInIntervalH->getObject( ));
04577             theOutIntervalH->setBeginTime(   theInIntervalH->getBeginTime( ));
04578             theOutIntervalH->setEndTime(     theInIntervalH->getEndTime( ));
04579             theOutIntervalH->setVersionTime( theInIntervalH->getVersionTime( ));
04580             theOutIntervalH->setTag(         theInIntervalH->getTag( ));
04581             theOutIntervalH->setRevision(    theRevisionRef );
04582 
04583           // Proceed along the versioning tree with the new _output_ base.
04584 
04585             status = copyTopIntervalsInSubTree( theDb,
04586                                                 theInIntervalH,
04587                                                 theOutIntervalH,
04588                                                 keepRevisedIntervals,
04589                                                 maxNumOfTopLayers,
04590                                                 maxNumOfLayersUnderRevisedInterval );
04591             if ( BdbcSuccess != status ) return status;
04592 
04593         } else {
04594 
04595           // Just ignore this interval, because it's located too deep inside
04596           // the versioning tree and does not respresent any particular interesnt.
04597 
04598           // Proceed along the versioning tree with the current _output_ base.
04599 
04600             status = copyTopIntervalsInSubTree( theDb,
04601                                                 theInIntervalH,
04602                                                 theOutBaseIntervalH,
04603                                                 keepRevisedIntervals,
04604                                                 maxNumOfTopLayers,
04605                                                 maxNumOfLayersUnderRevisedInterval );
04606             if ( BdbcSuccess != status ) return status;
04607         }
04608     }
04609 
04610   // Count the number of versions of the _output_ base and set the branching
04611   // to a proper number.
04612 
04613     d_ULong numBranches = 0;
04614 
04615     BdbItr(BdbPersObj) theOutItr;
04616     theOutBaseIntervalH->nextVers( theOutItr );
04617 
04618     while ( theOutItr.next( )) {
04619         ++numBranches;
04620     }
04621 
04622     switch ( numBranches ) {
04623     case 0:
04624         theOutBaseIntervalH.setVersStatus( oocNoVers  );
04625         break;
04626     case 1:
04627         theOutBaseIntervalH.setVersStatus( oocLinearVers  );
04628         break;
04629     default:
04630         theOutBaseIntervalH.setVersStatus( oocBranchVers  );
04631         break;
04632     }
04633 
04634   // Ok. We've done it at this layer.
04635 
04636     return BdbcSuccess;
04637 }
04638 
04639 bool
04640 BdbCondDatabaseMgr::hasAnyTopIntervalAsCloaseAs( const BdbHandle(BdbIntervalR)& theIntervalH,
04641                                                  d_ULong                        maxNumOfTopLayers )
04642 {
04643   // This method is meant to check if specified interval itself is being the topmost one
04644   // or its vertical child versions are within specified range of muximum number of top layers.
04645   //
04646   // NOTE: If the specified number is 0 then we do not check anything at all
04647   //       If it's equal to 1 then we check the specified interval only.
04648   //       If it > 1 then we check specified interval, and its children (if any).
04649   //
04650   // IMPORTANT: We are assuming that the genealogy tree for this interval already
04651   //            exists, and that this method was not called against the baseline interval.
04652 
04653     BdbItr(BdbPersObj) theItr;
04654 
04655     switch( maxNumOfTopLayers ) {
04656 
04657     case 0:
04658 
04659         {
04660           // If the radius of visibility is zero then we don't even try
04661           // to continue further checks.
04662 
04663             return false;
04664         }
04665 
04666     case 1:
04667 
04668         {
04669             theIntervalH->nextVers( theItr );
04670             while( theItr.next( )) {
04671 
04672               // Oops. The current interval has at least one vertical version, which means
04673               //       that this interval is not the TOPMOST one.
04674 
04675                 return false;
04676             }
04677 
04678           // Ok. No versions. The current interval is the TOPMOST one.
04679 
04680             return true;
04681         }
04682 
04683     default:
04684 
04685         {
04686             d_ULong numVersions = 0;
04687 
04688             theIntervalH->nextVers( theItr );
04689             while( theItr.next( )) {
04690 
04691                 numVersions++;
04692 
04693                 if( hasAnyTopIntervalAsCloaseAs((BdbHandle(BdbIntervalR)&) theItr,
04694                                                  maxNumOfTopLayers - 1 )) {
04695 
04696                   // Ok. The TOPMOST layer is close enough and is seen by the child
04697                   //     interval within specified radius.
04698 
04699                     return true;
04700                 }
04701             }
04702 
04703             if( 0 == numVersions ) {
04704 
04705               // Ok. No versions. The current interval is the TOPMOST one.
04706 
04707                 return true;
04708             }
04709 
04710             break;
04711         }
04712     }
04713 
04714   // Oops. We are still too far from the top of the genealogy.
04715 
04716     return false;
04717 }
04718 
04719 bool
04720 BdbCondDatabaseMgr::hasAnyRevisedIntervalAsCloaseAs( const BdbHandle(BdbIntervalR)& theIntervalH,
04721                                                      d_ULong                        maxNumOfLayersUnderRevisedInterval )
04722 {
04723   // This method is meant to check if specified interval itself is being the revised one
04724   // or its vertical child versions are within specified range of muximum number of layers
04725   // to another revised interval.
04726   //
04727   // NOTE: If the specified number is 0 then we do not check anything at all
04728   //       If it's equal to 1 then we check the children of the specified interval only.
04729   //       If it > 1 then we check both the children of specified interval, and further.
04730   //
04731   // IMPORTANT: We are assuming that the genealogy tree for this interval already
04732   //            exists, and that this method was not called against the baseline interval.
04733 
04734     BdbHandle(BdbIntervalR) theNextIntervalH;
04735     BdbRef(BdbCondRevision) theRevisionRef;
04736 
04737     BdbItr(BdbPersObj) theItr;
04738 
04739     switch( maxNumOfLayersUnderRevisedInterval ) {
04740 
04741     case 0:
04742 
04743         {
04744           // If the radius of visibility is zero then we don't even try
04745           // to continue further checks.
04746 
04747             return false;
04748         }
04749 
04750     case 1:
04751 
04752         {
04753             theIntervalH->nextVers( theItr );
04754             while( theItr.next( )) {
04755 
04756                 theNextIntervalH = (BdbHandle(BdbIntervalR)&) theItr;
04757 
04758                 theRevisionRef = theNextIntervalH->getRevision( );
04759                 if ( ! BdbIsNull(theRevisionRef)) {
04760 
04761                   // Ok. The current interval has at least one revised child.
04762 
04763                     return true;
04764                 }
04765             }
04766 
04767           // Oops. No revised intervals among children.
04768 
04769             return false;
04770         }
04771 
04772     default:
04773 
04774         {
04775             theIntervalH->nextVers( theItr );
04776             while( theItr.next( )) {
04777 
04778                 theNextIntervalH = (BdbHandle(BdbIntervalR)&) theItr;
04779 
04780                 theRevisionRef = theNextIntervalH->getRevision( );
04781                 if ( ! BdbIsNull(theRevisionRef)) {
04782 
04783                   // Ok. The current interval has at least one revised child.
04784 
04785                     return true;
04786                 }
04787                 if( hasAnyRevisedIntervalAsCloaseAs( theNextIntervalH,
04788                                                      maxNumOfLayersUnderRevisedInterval - 1 )) {
04789 
04790                   // Ok. There is a revised interval which is close enough and is seen by the child
04791                   //     interval within specified radius.
04792 
04793                     return true;
04794                 }
04795             }
04796 
04797             break;
04798         }
04799     }
04800 
04801   // Oops. We are still too far from a revised interval in this sub-branch
04802   //       of the genealogy.
04803 
04804     return false;
04805 }
04806 
04807 bool
04808 BdbCondDatabaseMgr::hasRevisedIntervalInSubTree( const BdbHandle(BdbIntervalR)& theIntervalH )
04809 {
04810   // This method is meant to check if there is at least one revised interval
04811   // in the versioning tree.
04812   //
04813   // NOTE: This test does not count the baseline interval (since we are checking
04814   //       only the children of specified interval then the baseline interval would
04815   //       not be counted automatically).
04816 
04817     if ( theIntervalH->exist_geneObj( )) {
04818 
04819         BdbHandle(BdbIntervalR) theNextIntervalH;
04820         BdbRef(BdbCondRevision) theRevisionRef;
04821 
04822         BdbItr(BdbPersObj) theItr;
04823         theIntervalH->nextVers( theItr );
04824 
04825         while( theItr.next( )) {
04826 
04827             theNextIntervalH = (BdbHandle(BdbIntervalR)&) theItr;
04828 
04829             theRevisionRef = theNextIntervalH->getRevision( );
04830             if ( ! BdbIsNull(theRevisionRef)) {
04831                 return true;
04832             } else {
04833                 if( hasRevisedIntervalInSubTree( theNextIntervalH )) {
04834                     return true;
04835                 }
04836             }
04837         }
04838     }
04839 
04840     return false;
04841 }
04842 
04843 const char*
04844 BdbCondDatabaseMgr::getOID( const BdbHandle(BdbPersObj)& thePersObjH )
04845 {
04846     static char buf[255];
04847 
04848     ooId id = thePersObjH;
04849     
04850     int db   = id.get_DB();
04851     int cont = id.get_OC();
04852     int page = id.get_page();
04853     int slot = id.get_slot();
04854     
04855     sprintf( buf, "#%d-%d-%d-%d", db, cont, page, slot );
04856 
04857     return buf;
04858 }
04859 /////////////////
04860 // End Of File //
04861 /////////////////

 


BaBar Public Site | SLAC | News | Links | Who's Who | Contact Us

Page Owner: Jacek Becla
Last Update: October 04, 2002