![]() |
|
|
Bdb packages | Design docs | Source docs | Guidelines | Recent releases |
|
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