![]() |
|
|
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/BdbDatabase.cc
Go to the documentation of this file.00001 //----------------------------------------------------------------------------- 00002 // 00003 // File and Version Information: 00004 // $Id: BdbDatabase.cc,v 1.128 2002/07/07 18:27:10 gapon Exp $ 00005 // 00006 // Description: 00007 // Class BdbDatabase 00008 // 00009 // Environment: 00010 // Software developed for the BaBar Detector at the SLAC B-Factory. 00011 // 00012 // Author List: 00013 // J. Ohnemus Original Author 00014 // Igor A. Gaponenko Further modifications 00015 // 00016 // Copyright Information: 00017 // Copyright (C) 1994, 1995 Lawrence Berkeley Laboratory 00018 // 00019 //----------------------------------------------------------------------------- 00020 00021 // ------------------------- 00022 // -- This Class's Header -- 00023 // ------------------------- 00024 00025 #include "BdbCond/BdbDatabase.hh" 00026 00027 // ------------------------- 00028 // -- Objectivity Headers -- 00029 // ------------------------- 00030 00031 #include <ooIndex.h> 00032 00033 // --------------- 00034 // -- C Headers -- 00035 // --------------- 00036 00037 extern "C" { 00038 #include <assert.h> 00039 #include <ctype.h> 00040 #include <stddef.h> 00041 #include <stdio.h> 00042 #include <stdlib.h> 00043 #include <string.h> 00044 } 00045 00046 // ----------------- 00047 // -- C++ Headers -- 00048 // ----------------- 00049 00050 #include <iostream.h> 00051 #include <algorithm> 00052 #include <string> 00053 using std::string; 00054 #include <vector> 00055 using std::vector; 00056 00057 // --------------------------------- 00058 // -- Collaborating Class Headers -- 00059 // --------------------------------- 00060 00061 #include "BdbApplication/BdbCondSingleton.hh" 00062 #include "BdbApplication/BdbDomain.hh" 00063 #include "BdbApplication/BdbDebug.hh" 00064 #include "BdbAccess/BdbAuth.hh" 00065 #include "BdbClustering/BdbCondClusteringHint.hh" 00066 #include "BdbCond/BdbConditions.hh" 00067 #include "BdbCond/BdbCondErrors.hh" 00068 #include "BdbCond/BdbInterval.hh" 00069 #include "BdbCond/BdbIntervalGene.hh" 00070 #include "BdbCond/BdbObject.hh" 00071 #include "BdbCond/BdbString.hh" 00072 #include "BdbCond/BdbCondStoreTime.hh" 00073 #include "BdbCond/BdbCondStoreInterval.hh" 00074 #include "BdbCond/BdbCondDirectAccessor.hh" 00075 #include "BdbTime/BdbTime.hh" 00076 #include "ErrLogger/ErrLog.hh" 00077 00078 // -------------------------------------------------------------------------- 00079 // -- Local Macros, Typedefs, Structures, Unions, and Forward Declarations -- 00080 // -------------------------------------------------------------------------- 00081 00082 static const char rcsid[] = "$Id: BdbDatabase.cc,v 1.128 2002/07/07 18:27:10 gapon Exp $"; 00083 00084 static const char* Zero = "00000"; 00085 00086 bool 00087 BdbDatabase::_staticMembersAreInitialized = false; 00088 00089 BdbTime 00090 BdbDatabase::_truncateOverrideTime = BdbTime::plusInfinity; 00091 00092 BdbCondAccessor* 00093 BdbDatabase::_defaultAccessor = new BdbCondDirectAccessor( ); 00094 00095 BdbCondAccessor* 00096 BdbDatabase::_accessor = _defaultAccessor; 00097 00098 // -------------------- 00099 // -- Static methods -- 00100 // -------------------- 00101 00102 void 00103 BdbDatabase::intializeStaticMembers( ) 00104 { 00105 if ( _staticMembersAreInitialized ) return; 00106 _staticMembersAreInitialized = true; 00107 00108 _truncateOverrideTime = BdbTime::plusInfinity; 00109 } 00110 00111 BdbTime 00112 BdbDatabase::setTruncateOverrideTime( const BdbTime& theNewTruncateOverrideTime ) 00113 { 00114 const char* infoString = "BdbDatabase::setTruncateOverrideTime() -- INFO"; 00115 00116 intializeStaticMembers( ); 00117 00118 BdbTime theOldTruncateOverrideTime; 00119 00120 theOldTruncateOverrideTime = _truncateOverrideTime; 00121 _truncateOverrideTime = theNewTruncateOverrideTime; 00122 00123 ErrMsg(routine) << infoString << endl 00124 << " The new overload for the truncate time: " << theNewTruncateOverrideTime << endl 00125 << " The old one was: " << theOldTruncateOverrideTime << endmsg; 00126 00127 return theOldTruncateOverrideTime; 00128 } 00129 00130 BdbTime 00131 BdbDatabase::getTruncateOverrideTime( ) 00132 { 00133 intializeStaticMembers( ); 00134 return _truncateOverrideTime; 00135 } 00136 00137 const BdbCondAccessor* 00138 BdbDatabase::getAccessor( ) 00139 { 00140 // Return a (const) pointer to the current instance of the accessor 00141 // or just null pointer if this is the default accessor. 00142 // 00143 // NOTE: The basic idea is to protect the default accessor from being 00144 // accidentally deleted by clients' code. 00145 00146 if( _accessor == _defaultAccessor ) return 0; 00147 00148 return _accessor; 00149 } 00150 00151 BdbCondAccessor* 00152 BdbDatabase::setAccessor( BdbCondAccessor* theAccessor ) 00153 { 00154 // Remember the current accessor or just null pointer if this is 00155 // the default accessor. 00156 // 00157 // NOTE: The basic idea is to protect the default accessor from being 00158 // accidentally deleted by clients' code. 00159 00160 BdbCondAccessor* previousAccessor = 0; 00161 if( _accessor != _defaultAccessor ) previousAccessor = _accessor; 00162 00163 // Modifying the default accessor can be disabled if the corresponding 00164 // environment variable is set. 00165 00166 if( 0 == getenv( "BDBCOND_USE_DEFAULT_ACCESSOR" )) { 00167 00168 // Send "reset" signal to the current accessor before to change it 00169 // for the new one. This is done in order to clear the background context (if required) 00170 // associated with this accessor. 00171 00172 _accessor->reset( ); 00173 00174 // Replace the current accessor with the new one, or with the default on 00175 // if null value were passed as a parameter. 00176 00177 if( 0 == theAccessor ) _accessor = _defaultAccessor; 00178 else _accessor = theAccessor; 00179 } 00180 00181 return previousAccessor; 00182 } 00183 00184 BdbCondAccessor* 00185 BdbDatabase::setDefaultAccessor( ) 00186 { 00187 return setAccessor( _defaultAccessor ); 00188 } 00189 00190 // ------------------ 00191 // -- Constructors -- 00192 // ------------------ 00193 00194 BdbDatabase::BdbDatabase( ) : 00195 _myHint(0), 00196 BdbCondDatabaseBase( ), 00197 _authLevelIsSet(false), 00198 _intervalCacheH(0) 00199 { 00200 intializeStaticMembers( ); 00201 00202 // Set the internal data members which are not managed through 00203 // the internal cache. 00204 00205 // The following operation is deffered until a very first request for 00206 // for the "updated" hint is done. 00207 // 00208 // _myHint = new BdbCondClusteringHint( *(BdbConditions::instance( )), 0 ); 00209 00210 _revisionPath = BdbCondPath::instance( ); 00211 } 00212 00213 BdbDatabase::BdbDatabase( const char* theTLA ) : 00214 _myHint(0), 00215 BdbCondDatabaseBase( theTLA ), 00216 _authLevelIsSet(false), 00217 _intervalCacheH(0) 00218 { 00219 intializeStaticMembers( ); 00220 00221 // Set the internal data members which are not managed through 00222 // the internal cache. 00223 00224 // The following operation is deffered until a very first request for 00225 // for the "updated" hint is done. 00226 // 00227 // _myHint = new BdbCondClusteringHint( *(BdbConditions::instance( )), theTLA ); 00228 00229 _revisionPath = BdbCondPath::instance( ); 00230 } 00231 00232 // ---------------- 00233 // -- Destructor -- 00234 // ---------------- 00235 00236 BdbDatabase::~BdbDatabase( ) 00237 { 00238 delete _myHint; 00239 } 00240 00241 // --------------- 00242 // -- Operators -- 00243 // --------------- 00244 00245 BdbDatabase& 00246 BdbDatabase::operator = ( const BdbDatabase& theDB ) 00247 { 00248 if ( this == &theDB ) { 00249 return *this; 00250 } 00251 00252 // Invoke base class assignment operator 00253 00254 BdbCondDatabaseBase::operator = ( theDB ); 00255 00256 // Add assignment for derived class data members 00257 00258 _myHint = theDB._myHint; 00259 _authLevelIsSet = theDB._authLevelIsSet; 00260 _revisionPath = theDB._revisionPath; 00261 _intervalCacheH = theDB._intervalCacheH; 00262 00263 return *this; 00264 } 00265 00266 // ---------------------- 00267 // -- Member Functions -- 00268 // ---------------------- 00269 00270 BdbStatus 00271 BdbDatabase::store( const BdbHandle(BdbObject)& theObjectH, 00272 const char* theContainerName, 00273 const BdbTime& theBeginTime, 00274 d_ULong theTag ) 00275 { 00276 const char* errorString = "BdbDatabase::store() -- ERROR"; 00277 00278 BdbStatus status; 00279 00280 assert ( 0 != theContainerName ); 00281 00282 COUT1 << "CONDSTORE1: detector=" << subsystemTLA( ) << " container=" << theContainerName << " begin_time=" << theBeginTime << endl; 00283 00284 // Ensure the proper context to be set. 00285 00286 if ( ! verifyIndexMode( )) return BdbcError; 00287 if ( ! setAuthLevel( theContainerName )) return BdbcError; 00288 00289 // Try to locate this interval container. 00290 00291 BdbHandle(BdbContObj) intervalContH; 00292 if ( BdbcSuccess != findIntervalCont( intervalContH, theContainerName )) { 00293 00294 // Create new container and store the object in there. 00295 00296 return createIntervalCont( theContainerName, 00297 theObjectH, 00298 theBeginTime, 00299 BdbTime::plusInfinity, 00300 theTag ); 00301 00302 } 00303 00304 // Put a record into the History. We do this in advance, because creating 00305 // a new interval is not generally an atomic operations. If it fails 00306 // somewhere in the middle we would know what exactly we were trying 00307 // to do. 00308 00309 historyStore( rcsid, theObjectH, theBeginTime, BdbTime::plusInfinity, theTag ); 00310 00311 // Locate the FIRST and the LAST intervals. 00312 00313 BdbHandle(BdbIntervalR) firstIntervalH; 00314 BdbHandle(BdbIntervalR) lastIntervalH; 00315 00316 firstIntervalH.lookupObj( intervalContH, "FirstInterval", BdbcUpdate ); 00317 if ( BdbIsNull(firstIntervalH)) { 00318 ErrMsg(error) << errorString << endl 00319 << " Can not find FIRST interval." << endl 00320 << " The container may have incorrect internal structure." << endl 00321 << " DETECTOR -> " << subsystemTLA( ) << endl 00322 << " CONTAINER -> " << theContainerName << endmsg; 00323 return BdbcError; 00324 } 00325 00326 lastIntervalH.lookupObj( intervalContH, "LastInterval", BdbcUpdate ); 00327 if ( BdbIsNull(lastIntervalH)) { 00328 ErrMsg(error) << errorString << endl 00329 << " Can not find LAST interval." << endl 00330 << " The container may have incorrect internal structure." << endl 00331 << " DETECTOR -> " << subsystemTLA( ) << endl 00332 << " CONTAINER -> " << theContainerName << endmsg; 00333 return BdbcError; 00334 } 00335 00336 // Modify the FIRST interval 00337 00338 if ( theBeginTime < firstIntervalH->getEndTime( )) { 00339 00340 if ( theBeginTime == BdbTime::minusInfinity ) { 00341 00342 // Well. We have interval with both ends open: -oo..+oo 00343 // Update the first interval until its very end. 00344 00345 status = updateFirstInterval( theObjectH, 00346 firstIntervalH, 00347 firstIntervalH->getEndTime( ), 00348 theTag ); 00349 if ( BdbcSuccess != status ) { 00350 return status; 00351 } 00352 00353 } else { 00354 00355 // Cut the first interval until its very end. 00356 00357 status = cutFirstInterval( theObjectH, 00358 firstIntervalH, 00359 theBeginTime, 00360 firstIntervalH->getEndTime( ), 00361 theTag ); 00362 00363 if ( BdbcSuccess != status ) { 00364 return status; 00365 } 00366 00367 } 00368 00369 // Use recursive call to the current function to store 00370 // the rest of the interval 00371 00372 return store( theObjectH, 00373 theContainerName, 00374 firstIntervalH->getEndTime( ), 00375 theTag ); 00376 00377 } else { 00378 00379 // Modify the LAST interval. 00380 00381 if ( theBeginTime > lastIntervalH->getBeginTime( )) { 00382 00383 // append interval to end of list 00384 00385 return appendIntervalR( theObjectH, 00386 lastIntervalH, 00387 theBeginTime, 00388 theTag ); 00389 00390 } else if ( theBeginTime == lastIntervalH->getBeginTime( )) { 00391 00392 // update the last interval if it pointed out to a NULL calibration 00393 // object only 00394 00395 return updateLastInterval( theObjectH, 00396 lastIntervalH, 00397 theTag ); 00398 00399 } else { 00400 00401 // version an interval in the middle of the list 00402 00403 version( 0, 00404 theObjectH, 00405 theBeginTime, 00406 theTag ); 00407 } 00408 } 00409 00410 return BdbcSuccess; 00411 } 00412 00413 BdbStatus 00414 BdbDatabase::store( const BdbHandle(BdbObject)& theObjectH, 00415 const char* theContainerName, 00416 const BdbTime& theBeginTime, 00417 const BdbTime& theEndTime, 00418 d_ULong theTag ) 00419 { 00420 const char* errorString = "BdbDatabase::store() -- ERROR."; 00421 00422 // Check if we have an open ended interval on the right. 00423 00424 if ( BdbTime::plusInfinity == theEndTime ) { 00425 00426 return store( theObjectH, 00427 theContainerName, 00428 theBeginTime, 00429 theTag ); 00430 } 00431 00432 // Proceed with a regular procedure. 00433 00434 BdbStatus status; 00435 00436 assert ( 0 != theContainerName ); 00437 assert ( theBeginTime < theEndTime ); 00438 00439 COUT1 << "CONDSTORE2: detector=" << subsystemTLA( ) << " container=" << theContainerName << " begin_time=" << theBeginTime << " end_time=" << theEndTime << endl; 00440 00441 // Ensure the proper context to be set. 00442 00443 if ( ! verifyIndexMode( )) return BdbcError; 00444 if ( ! setAuthLevel( theContainerName )) return BdbcError; 00445 00446 // Try to locate this interval container. 00447 00448 BdbHandle(BdbContObj) intervalContH; 00449 if ( BdbcSuccess != findIntervalCont( intervalContH, theContainerName )) { 00450 00451 // Create new container and store the object in there. 00452 00453 return createIntervalCont( theContainerName, 00454 theObjectH, 00455 theBeginTime, 00456 theEndTime, 00457 theTag ); 00458 00459 } 00460 00461 // Put a record into the History. We do this in advance, because creating 00462 // a new interval is not generally an atomic operations. If it fails 00463 // somewhere in the middle we would know what exactly we were trying 00464 // to do. 00465 00466 historyStore( rcsid, theObjectH, theBeginTime, theEndTime, theTag ); 00467 00468 // Locate the FIRST and the LAST intervals. 00469 00470 BdbHandle(BdbIntervalR) firstIntervalH; 00471 BdbHandle(BdbIntervalR) lastIntervalH; 00472 00473 firstIntervalH.lookupObj( intervalContH, "FirstInterval", BdbcUpdate ); 00474 if ( BdbIsNull(firstIntervalH)) { 00475 ErrMsg(error) << errorString << endl 00476 << " Can not find FIRST interval." << endl 00477 << " The container may have incorrect internal structure." << endl 00478 << " DETECTOR -> " << subsystemTLA( ) << endl 00479 << " CONTAINER -> " << theContainerName << endmsg; 00480 return BdbcError; 00481 } 00482 00483 lastIntervalH.lookupObj( intervalContH, "LastInterval", BdbcUpdate ); 00484 if ( BdbIsNull(lastIntervalH)) { 00485 ErrMsg(error) << errorString << endl 00486 << " Can not find LAST interval." << endl 00487 << " The container may have incorrect internal structure." << endl 00488 << " DETECTOR -> " << subsystemTLA( ) << endl 00489 << " CONTAINER -> " << theContainerName << endmsg; 00490 return BdbcError; 00491 } 00492 00493 // Modify the FIRST interval 00494 00495 if ( theBeginTime < firstIntervalH->getEndTime( )) { 00496 00497 if ( theBeginTime == BdbTime::minusInfinity ) { 00498 00499 if ( theEndTime >= firstIntervalH->getEndTime( )) { 00500 00501 // Update the first interval until its very end. 00502 00503 status = updateFirstInterval( theObjectH, 00504 firstIntervalH, 00505 firstIntervalH->getEndTime( ), 00506 theTag ); 00507 00508 if ( BdbcSuccess != status ) { 00509 return status; 00510 } 00511 00512 } else { 00513 00514 // Update the first interval until the specified end time. 00515 // And then immediatelly return. 00516 00517 return updateFirstInterval( theObjectH, 00518 firstIntervalH, 00519 theEndTime, 00520 theTag ); 00521 } 00522 00523 } else { 00524 00525 if ( theEndTime >= firstIntervalH->getEndTime( )) { 00526 00527 // Cut the first interval until its very end. 00528 00529 status = cutFirstInterval( theObjectH, 00530 firstIntervalH, 00531 theBeginTime, 00532 firstIntervalH->getEndTime( ), 00533 theTag ); 00534 00535 if ( BdbcSuccess != status ) { 00536 return status; 00537 } 00538 00539 00540 } else { 00541 00542 // Cut the first interval until the specified end time. 00543 // And then immediatelly return. 00544 00545 return cutFirstInterval( theObjectH, 00546 firstIntervalH, 00547 theBeginTime, 00548 theEndTime, 00549 theTag ); 00550 } 00551 } 00552 00553 // Use recursive call to the current function to store 00554 // the rest of the interval if the original interval 00555 // goes beyong the first interval. 00556 00557 if ( theEndTime > firstIntervalH->getEndTime( )) { 00558 00559 return store( theObjectH, 00560 theContainerName, 00561 firstIntervalH->getEndTime( ), 00562 theEndTime, 00563 theTag ); 00564 } 00565 00566 } else { 00567 00568 // Modify the LAST interval. 00569 00570 if ( theBeginTime > lastIntervalH->getBeginTime( )) { 00571 00572 // append interval to end of list 00573 00574 return appendIntervalR( theObjectH, 00575 lastIntervalH, 00576 theBeginTime, 00577 theEndTime, 00578 theTag ); 00579 00580 } else if ( theBeginTime == lastIntervalH->getBeginTime( )) { 00581 00582 // Cut the last interval onto 2 interval: one with closed ends, another 00583 // - with open right end. Version the first interval if it has non-NULL 00584 // pointer to a calibration object. 00585 00586 return cutLastInterval( theObjectH, 00587 lastIntervalH, 00588 theBeginTime, 00589 theEndTime, 00590 theTag ); 00591 00592 } else { 00593 00594 // version an interval in the middle of the list 00595 00596 version( 0, 00597 theObjectH, 00598 theBeginTime, 00599 theEndTime, 00600 theTag ); 00601 } 00602 } 00603 00604 return BdbcSuccess; 00605 } 00606 00607 BdbStatus 00608 BdbDatabase::store( const BdbHandle(BdbObject)& theObjectH, 00609 const char* theContainerName, 00610 const BdbIntervalBase& theInterval, 00611 d_ULong theTag ) 00612 { 00613 BdbTime theBeginTime = theInterval.getBeginTime( ); 00614 BdbTime theEndTime = theInterval.getEndTime( ); 00615 00616 return store( theObjectH, theContainerName, theBeginTime, theEndTime, theTag ); 00617 } 00618 00619 BdbStatus 00620 BdbDatabase::storeAndTruncate( const BdbHandle(BdbObject)& theObjectH, 00621 const char* theContainerName, 00622 const BdbTime& theInsertTime, 00623 const BdbTime& theExplicitTruncateTime, 00624 d_ULong theTag ) 00625 { 00626 const char* errorString = "BdbDatabase::storeAndTruncate() -- ERROR."; 00627 const char* warningString = "BdbDatabase::storeAndTruncate() -- WARNINIG."; 00628 00629 // This is "tree points" interface, where the third point is ment 00630 // to be "plus infinity". 00631 00632 BdbStatus status; 00633 00634 assert ( 0 != theContainerName ); 00635 assert ( theInsertTime <= theExplicitTruncateTime ); 00636 assert ( theExplicitTruncateTime < BdbTime::plusInfinity ); 00637 00638 // Override the explicitly specified truncate time if the override time 00639 // is set (it's not equal to +oo). 00640 // Otherwise just use the explicit one. 00641 00642 BdbTime theTruncateTime = theExplicitTruncateTime; 00643 00644 if ( BdbTime::plusInfinity != _truncateOverrideTime ) { 00645 00646 // Perform more checks on the value of this time. 00647 00648 if ( _truncateOverrideTime < theInsertTime ) { 00649 ErrMsg(error) << errorString << endl 00650 << " This is an incorrect use of the storeAndTruncate() method" << endl 00651 << " because the overriden value for the truncation time is less" << endl 00652 << " than the store (insertion) time." << endl 00653 << " DETECTOR -> " << subsystemTLA( ) << endl 00654 << " CONTAINER -> " << theContainerName << endl 00655 << " INSERT TIME: " << theInsertTime << endl 00656 << " EXPLICIT TRUNCATE TIME: " << theExplicitTruncateTime << endl 00657 << " OVERRIDEN TRUNCATE TIME: " << _truncateOverrideTime << endmsg; 00658 return BdbcError; 00659 } 00660 if ( _truncateOverrideTime < theExplicitTruncateTime ) { 00661 ErrMsg(routine) << warningString << endl 00662 << " This is a suspicious use of the storeAndTruncate() method" << endl 00663 << " because the overriden value for the truncation time is less" << endl 00664 << " than explicitly specified truncate time." << endl 00665 << " DETECTOR -> " << subsystemTLA( ) << endl 00666 << " CONTAINER -> " << theContainerName << endl 00667 << " INSERT TIME: " << theInsertTime << endl 00668 << " EXPLICIT TRUNCATE TIME: " << theExplicitTruncateTime << endl 00669 << " OVERRIDEN TRUNCATE TIME: " << _truncateOverrideTime << endmsg; 00670 } 00671 00672 // And finally replace the truncate time by the the overriden value. 00673 // More check will be done later on. 00674 00675 theTruncateTime = _truncateOverrideTime; 00676 } 00677 00678 // If the insert time is equal to the truncate time 00679 // then we just proceed with the "regular" open-ended ::store(). 00680 00681 if( theInsertTime == theTruncateTime ) { 00682 00683 return store( theObjectH, 00684 theContainerName, 00685 theInsertTime, 00686 theTag ); 00687 } 00688 00689 COUT1 << "CONDSTOREANDTRUNCATE: detector=" << subsystemTLA( ) << " container=" << theContainerName << " store_time=" << theInsertTime << " explicit_truncate_time=" << theExplicitTruncateTime << " truncate_time=" << theTruncateTime << endl; 00690 00691 // Ensure the proper context to be set. 00692 00693 if ( ! verifyIndexMode( )) return BdbcError; 00694 if ( ! setAuthLevel( theContainerName )) return BdbcError; 00695 00696 // Try to locate this interval container. 00697 00698 BdbHandle(BdbContObj) intervalContH; 00699 if ( BdbcSuccess != findIntervalCont( intervalContH, theContainerName )) { 00700 00701 // Create new container and store the object in there. 00702 // 00703 // NOTE: Unlike in case of a regular close-ended store this function 00704 // would initialize the new interval container using the open-ended 00705 // pattern. This is becase for the "store & truncate" the new object 00706 // would last "forever". 00707 00708 return createIntervalCont( theContainerName, 00709 theObjectH, 00710 theInsertTime, 00711 BdbTime::plusInfinity, 00712 theTag ); 00713 00714 } 00715 00716 // Locate the FIRST and the LAST intervals. 00717 00718 BdbHandle(BdbIntervalR) firstIntervalH; 00719 BdbHandle(BdbIntervalR) lastIntervalH; 00720 00721 firstIntervalH.lookupObj( intervalContH, "FirstInterval", BdbcUpdate ); 00722 if ( BdbIsNull(firstIntervalH)) { 00723 ErrMsg(error) << errorString << endl 00724 << " Can not find FIRST interval." << endl 00725 << " The container may have incorrect internal structure." << endl 00726 << " DETECTOR -> " << subsystemTLA( ) << endl 00727 << " CONTAINER -> " << theContainerName << endmsg; 00728 return BdbcError; 00729 } 00730 00731 lastIntervalH.lookupObj( intervalContH, "LastInterval", BdbcUpdate ); 00732 if ( BdbIsNull(lastIntervalH)) { 00733 ErrMsg(error) << errorString << endl 00734 << " Can not find LAST interval." << endl 00735 << " The container may have incorrect internal structure." << endl 00736 << " DETECTOR -> " << subsystemTLA( ) << endl 00737 << " CONTAINER -> " << theContainerName << endmsg; 00738 return BdbcError; 00739 } 00740 00741 /************************ DISABLED CODE **************************** 00742 * * 00743 * The following check has been disabled in order to allow client * 00744 * to cross the border of the LAST interval when using the current * 00745 * method. * 00746 * * 00747 ******************************************************************* 00748 00749 // More check on the parameters. 00750 // They both must be either in a middle of intervals timeline or within 00751 // the last interval. 00752 // 00753 // NOTE: This checking is done only when a truncate time is strictly past 00754 // the beginning of the LAST interval. 00755 00756 if (( theInsertTime < lastIntervalH->beginTime( )) && 00757 ( theTruncateTime > lastIntervalH->beginTime( ))) { 00758 ErrMsg(error) << errorString << endl 00759 << " This is an incorrect use of the storeAndTruncate() method" << endl 00760 << " because both the store (insertion) and truncation (which is possibly overriden)" << endl 00761 << " times must be either inside or outside existing LAST interval." << endl 00762 << " DETECTOR -> " << subsystemTLA( ) << endl 00763 << " CONTAINER -> " << theContainerName << endl 00764 << " INSERT TIME: " << theInsertTime << endl 00765 << " EXPLICIT TRUNCATE TIME: " << theExplicitTruncateTime << endl 00766 << " OVERRIDEN TRUNCATE TIME: " << _truncateOverrideTime << endmsg; 00767 return BdbcError; 00768 } 00769 */ 00770 00771 // Put a record into the History. We do this in advance, because creating 00772 // a new interval is not generally an atomic operations. If it fails 00773 // somewhere in the middle we would know what exactly we were trying 00774 // to do. 00775 00776 historyTStore( rcsid, theObjectH, theInsertTime, theTruncateTime, theTag ); 00777 00778 // Modify the First interval 00779 00780 if ( theInsertTime < firstIntervalH->getEndTime( )) { 00781 00782 if ( theInsertTime == BdbTime::minusInfinity ) { 00783 00784 if ( theTruncateTime >= firstIntervalH->getEndTime( )) { 00785 00786 // Update the first interval until its very end. 00787 00788 status = updateFirstInterval( theObjectH, 00789 firstIntervalH, 00790 firstIntervalH->getEndTime( ), 00791 theTag ); 00792 00793 if ( BdbcSuccess != status ) { 00794 return status; 00795 } 00796 00797 } else { 00798 00799 // Update the first interval until the specified truncate time. 00800 // And then immediatelly return. 00801 00802 return updateFirstInterval( theObjectH, 00803 firstIntervalH, 00804 theTruncateTime, 00805 theTag ); 00806 } 00807 00808 } else { 00809 00810 if ( theTruncateTime >= firstIntervalH->getEndTime( )) { 00811 00812 // Cut the first interval until its very end. 00813 00814 status = cutFirstInterval( theObjectH, 00815 firstIntervalH, 00816 theInsertTime, 00817 firstIntervalH->getEndTime( ), 00818 theTag ); 00819 00820 if ( BdbcSuccess != status ) { 00821 return status; 00822 } 00823 00824 00825 } else { 00826 00827 // Cut the first interval until the specified truncate time. 00828 // And then immediatelly return. 00829 00830 return cutFirstInterval( theObjectH, 00831 firstIntervalH, 00832 theInsertTime, 00833 theTruncateTime, 00834 theTag ); 00835 } 00836 } 00837 00838 // Use recursive call to the current function to store 00839 // the rest of the interval if the original interval 00840 // goes beyong the first interval. 00841 00842 if ( theTruncateTime > firstIntervalH->getEndTime( )) { 00843 00844 return storeAndTruncate( theObjectH, 00845 theContainerName, 00846 firstIntervalH->getEndTime( ), 00847 theTruncateTime, 00848 theTag ); 00849 } 00850 00851 } else { 00852 00853 // Choose one of the possible scenarios depending on a place 00854 // where the new interval is going to. 00855 00856 if ( theInsertTime < lastIntervalH->getBeginTime( )) { 00857 00858 BdbTime theVersionTime = BdbTime( ); // This time would be common for all the objects 00859 // in the vectors. 00860 00861 if ( theTruncateTime <= lastIntervalH->getBeginTime( )) { 00862 00863 // version an interval in the middle of the list 00864 00865 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 00866 * The following code has been replaced by the call to the "::versionVector()" method 00867 * for the sake of efficency. 00868 * 00869 * version( 0, 00870 * theObjectH, 00871 * theInsertTime, 00872 * theTruncateTime, 00873 * theTag ); 00874 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 00875 */ 00876 return versionVector( theObjectH, 00877 theInsertTime, 00878 theTruncateTime, 00879 theVersionTime, 00880 theTag ); 00881 } else { 00882 00883 // version the first part of an interval in the middle of the list 00884 00885 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 00886 * The following code has been replaced by the call to the "::versionVector()" method 00887 * for the sake of efficency. 00888 * 00889 * version( 0, 00890 * theObjectH, 00891 * theInsertTime, 00892 * lastIntervalH->getBeginTime( ), 00893 * theTag ); 00894 */ 00895 status = versionVector( theObjectH, 00896 theInsertTime, 00897 lastIntervalH->getBeginTime( ), 00898 theVersionTime, 00899 theTag ); 00900 if ( BdbcSuccess != status ) return status; 00901 00902 // "regular" insert and truncate of the second part of specified 00903 // interval at the beginning of the last interval. 00904 00905 return truncateLastInterval( theObjectH, 00906 lastIntervalH, 00907 lastIntervalH->getBeginTime( ), 00908 theTruncateTime, 00909 theTag ); 00910 } 00911 00912 } else { 00913 00914 // "regular" insert and truncate of the whole interval in the middle 00915 // of the last interval. 00916 00917 return truncateLastInterval( theObjectH, 00918 lastIntervalH, 00919 theInsertTime, 00920 theTruncateTime, 00921 theTag ); 00922 } 00923 } 00924 00925 return BdbcSuccess; 00926 } 00927 00928 BdbStatus 00929 BdbDatabase::storeVector( const vector<BdbCondStoreTime>& theVector, 00930 const char* theContainerName ) 00931 { 00932 const char* errorString = "BdbDatabase::storeVector() -- ERROR."; 00933 00934 BdbStatus status; 00935 BdbTime theVersionTime = BdbTime( ); // This time would be common for all the objects 00936 // in the vector. 00937 BdbHandle(BdbObject) theObjectH; 00938 BdbRef(BdbObject) theObjectRef; 00939 00940 BdbTime theBeginTime; 00941 BdbTime theEndTime; 00942 00943 BdbIntervalBase theIntervalBase; 00944 00945 BdbHandle(BdbIntervalR) theIntervalH; 00946 BdbHandle(BdbIntervalR) theFirstIntervalH; 00947 BdbHandle(BdbIntervalR) theLastIntervalH; 00948 BdbHandle(BdbIntervalR) theOldIntervalH; 00949 BdbHandle(BdbIntervalR) theNewIntervalH; 00950 00951 BdbHandle(BdbCondRevision) baselineRevisionH; 00952 00953 assert( 0 != theContainerName ); 00954 00955 COUT1 << "CONDSTOREVECTOR: detector=" << subsystemTLA( ) << " container=" << theContainerName << " entries=" << theVector.size( ) << endl; 00956 00957 // Verify the contents of the specified vector. 00958 00959 status = verifyStoreVector( theVector ); 00960 if( BdbcSuccess != status ) { 00961 return status; 00962 } 00963 00964 // Ensure the proper context to be set. 00965 00966 if ( ! verifyIndexMode( )) return BdbcError; 00967 if ( ! setAuthLevel( theContainerName )) return BdbcError; 00968 00969 // Try to locate this interval container. 00970 00971 BdbHandle(BdbContObj) intervalContH; 00972 if( BdbcSuccess != findIntervalCont( intervalContH, theContainerName )) { 00973 00974 00975 // Create and initialize the interval container and store the whole vector as 00976 // a plain sequence of intervals. 00977 // 00978 // The algorithm: 00979 // 00980 // 1. Take the first two elements from the vector and use their limits 00981 // to initialize the container. 00982 // 00983 // NOTE: We assume that the first object is not equal to null. 00984 // 00985 // 2. Take the next elements one-by one and append them to the next interval 00986 // using the standard methods. 00987 00988 theObjectH = theVector[0].getObject( ); 00989 theBeginTime = theVector[0].getTime( ); 00990 theEndTime = theVector[1].getTime( ); 00991 00992 status = createIntervalCont( theContainerName, 00993 theObjectH, 00994 theBeginTime, 00995 theEndTime, 00996 0, 00997 theVersionTime ); 00998 if ( BdbcSuccess != status ) { 00999 return status; 01000 } 01001 01002 // Get the container handle and proceed loading elements of the vector 01003 // into there. 01004 01005 getIntervalContH( intervalContH ); 01006 01007 int entries = theVector.size( ); 01008 for( int i = 1; i < (entries - 1); i++ ) { 01009 01010 theObjectH = theVector[i].getObject( ); 01011 theBeginTime = theVector[i].getTime( ); 01012 theEndTime = theVector[i+1].getTime( ); 01013 01014 theLastIntervalH.lookupObj( intervalContH, "LastInterval", BdbcUpdate ); 01015 if( BdbIsNull(theLastIntervalH)) { 01016 ErrMsg(error) << errorString << endl 01017 << " Failed to locate the LAST interval." << endl 01018 << " The container may be inproperly created and/or initialized." << endl 01019 << " DETECTOR -> " << subsystemTLA( ) << endl 01020 << " CONTAINER -> " << theContainerName << endmsg; 01021 return BdbcError; 01022 } 01023 01024 // Cut last interval. 01025 // 01026 // NOTE: We always use "cutLastInterval", but not "appendIntervalR" 01027 // because each new interval starts from the very beginning 01028 // of the LAST one. 01029 01030 status = cutLastInterval( theObjectH, 01031 theLastIntervalH, 01032 theBeginTime, 01033 theEndTime, 01034 0, 01035 theVersionTime ); 01036 if( BdbcSuccess != status ) { 01037 ErrMsg(error) << errorString << endl 01038 << " Failed to cut the LAST interval." << endl 01039 << " DETECTOR -> " << subsystemTLA( ) << endl 01040 << " CONTAINER -> " << theContainerName << endl 01041 << " BEGIN_TIME -> " << theBeginTime << endl 01042 << " END_TIME -> " << theEndTime << endmsg; 01043 return status; 01044 } 01045 } 01046 01047 // Put a record into the History. 01048 01049 historyStoreVector( rcsid, theVector ); 01050 01051 return BdbcSuccess; 01052 } 01053 01054 // Get the current BASELINE revision. We would need this revision when creating new 01055 // intervals later. 01056 01057 getBaselineRevisionH( baselineRevisionH ); 01058 01059 // Put a record into the History. We do this in advance, because creating 01060 // a new interval is not generally an atomic operations. If it fails 01061 // somewhere in the middle we would know what exactly we were trying 01062 // to do. 01063 01064 historyStoreVector( rcsid, theVector ); 01065 01066 // Fetch an interval where the first time from the input 01067 // vector falls into. 01068 // 01069 // NOTE: If this is the first interval and if this interval has zero 01070 // length [-oo,-oo) then just skip this interval and proceed to 01071 // the next one. 01072 01073 theBeginTime = theVector[0].getTime( ); 01074 01075 findInterval( theIntervalH, theBeginTime, 0 ); 01076 if( BdbIsNull(theIntervalH)) { 01077 ErrMsg(error) << errorString << endl 01078 << " Failed to find a TOPMOST interval matching specified validity time." << endl 01079 << " DETECTOR -> " << subsystemTLA( ) << endl 01080 << " CONTAINER -> " << theContainerName << endl 01081 << " TIME -> " << theBeginTime << endmsg; 01082 return BdbcError; 01083 } 01084 if(( BdbTime::minusInfinity == theIntervalH->getBeginTime( )) && 01085 ( BdbTime::minusInfinity == theIntervalH->getEndTime( ))) { 01086 01087 theIntervalH->getTopNext( theIntervalH ); 01088 } 01089 01090 // Get the handle for the FIRST & LAST intervals. We will use these handles to verify 01091 // if a special processing is needed. 01092 01093 theFirstIntervalH.lookupObj( intervalContH, "FirstInterval", BdbcUpdate ); 01094 if( BdbIsNull(theFirstIntervalH)) { 01095 ErrMsg(error) << errorString << endl 01096 << " Failed to locate the FIRST interval." << endl 01097 << " The container may be inproperly created and/or initialized." << endl 01098 << " DETECTOR -> " << subsystemTLA( ) << endl 01099 << " CONTAINER -> " << theContainerName << endmsg; 01100 return BdbcError; 01101 } 01102 01103 theLastIntervalH.lookupObj( intervalContH, "LastInterval", BdbcUpdate ); 01104 if( BdbIsNull(theLastIntervalH)) { 01105 ErrMsg(error) << errorString << endl 01106 << " Failed to locate the LAST interval." << endl 01107 << " The container may be inproperly created and/or initialized." << endl 01108 << " DETECTOR -> " << subsystemTLA( ) << endl 01109 << " CONTAINER -> " << theContainerName << endmsg; 01110 return BdbcError; 01111 } 01112 01113 // Translate the input vector of times into a vector of intervals. The intervals 01114 // will be continious in the validity time. 01115 // The resulting intervals will be aligned to the borders of existing intervals. 01116 // 01117 // NOTE: The value of the starting interval handle could be modifyied 01118 // by this recursive algorithm. 01119 // 01120 // NOTE: The handles of both FIRST and LAST intervals may be used by 01121 // the building algorithm. 01122 01123 vector<BdbCondStoreInterval> theIntervalVector; 01124 01125 status = buildTopStoreVector( theVector, 01126 theFirstIntervalH, 01127 theLastIntervalH, 01128 theIntervalH, 01129 theIntervalVector ); 01130 if( BdbcSuccess != status ) { 01131 return status; 01132 } 01133 01134 // Process the resulting intervals vector, by taking each interval description from 01135 // there one-by-one and applying these intrervals to the existing structure. 01136 01137 int entries = theIntervalVector.size( ); 01138 for( int i = 0; i < entries; i++ ) { 01139 01140 theObjectH = theIntervalVector[i].getObject( ); 01141 theIntervalVector[i].getInterval( theIntervalBase ); 01142 theIntervalVector[i].getExistingInterval( theOldIntervalH ); 01143 01144 theBeginTime = theIntervalBase.getBeginTime( ); 01145 theEndTime = theIntervalBase.getEndTime( ); 01146 01147 // Check if we are trying to modify the FIRST interval. 01148 // In this case a new interval may not be aligned to the border 01149 // of the existing intervals. 01150 01151 if( theOldIntervalH == theFirstIntervalH ) { 01152 01153 // The further actions depend on where the new interval begins 01154 // and ends. 01155 01156 if( BdbTime::minusInfinity == theBeginTime ) { 01157 01158 // The new interval begins on -oo. 01159 01160 if( theFirstIntervalH->getEndTime( ) != theEndTime ) { 01161 01162 // The new interval covers just a part of the FIRST interval 01163 // starting from the very beginning. 01164 // Now we are going to create a new FIRST interval, update it 01165 // with new data. 01166 // This would leave the rest of the former FIRST interval as is 01167 // with the same OID, thus making the rest of the translated 01168 // interval vector valid. 01169 01170 theOldIntervalH->setBeginTime( theEndTime ); 01171 theNewIntervalH = new( intervalContH ) BdbIntervalR( theOldIntervalH->getObject( ), 01172 BdbTime::minusInfinity, 01173 theEndTime, 01174 0 ); 01175 theNewIntervalH->setVersionTime( theOldIntervalH->getVersionTime( )); 01176 theNewIntervalH->setRevision( baselineRevisionH ); 01177 01178 theNewIntervalH->setBaselineNext( theOldIntervalH ); 01179 theOldIntervalH->setBaselinePrevious( theNewIntervalH ); 01180 01181 theNewIntervalH->setTopNext( theOldIntervalH ); 01182 theOldIntervalH->setTopPrevious( theNewIntervalH ); 01183 01184 theOldIntervalH.unnameObj( intervalContH ); 01185 theNewIntervalH.nameObj( intervalContH, "FirstInterval" ); 01186 01187 // Now we will also modify the current value for the FIRST 01188 // interval handle which we used for comparision. 01189 01190 theFirstIntervalH = theNewIntervalH; 01191 01192 } 01193 01194 // New we are guarantied that the new interval completelly covers 01195 // the FIRST interval. 01196 // So now we are going just to update this interval. 01197 01198 updateFirstInterval( theObjectH, theFirstIntervalH, theEndTime, 0, theVersionTime ); 01199 01200 } else { 01201 01202 // The new interval does not begin in -oo. 01203 01204 // Cut the first interval right here where the new one begins. 01205 // This would create a new FIRST interval with different OID, 01206 // thus leaving all existing definitions in the interval vector 01207 // to be valid. 01208 01209 theOldIntervalH->setBeginTime( theBeginTime ); 01210 theNewIntervalH = new( intervalContH ) BdbIntervalR( theOldIntervalH->getObject( ), 01211 BdbTime::minusInfinity, 01212 theBeginTime, 01213 0 ); 01214 theNewIntervalH->setVersionTime( theOldIntervalH->getVersionTime( )); 01215 theNewIntervalH->setRevision( baselineRevisionH ); 01216 01217 theNewIntervalH->setBaselineNext( theOldIntervalH ); 01218 theOldIntervalH->setBaselinePrevious( theNewIntervalH ); 01219 01220 theNewIntervalH->setTopNext( theOldIntervalH ); 01221 theOldIntervalH->setTopPrevious( theNewIntervalH ); 01222 01223 theOldIntervalH.unnameObj( intervalContH ); 01224 theNewIntervalH.nameObj( intervalContH, "FirstInterval" ); 01225 01226 // Now we will also modify the current value for the FIRST 01227 // interval handle which we used for comparision. 01228 01229 theFirstIntervalH = theNewIntervalH; 01230 01231 // And finally - add the version to the ex-FIRST interval, 01232 // which is now the second one. 01233 // 01234 // NOTE: This operation is safe since we are guarantied that 01235 // the end time of the new version to be added will never 01236 // fall into the last interval and will never span the end 01237 // border of existing interval to be versioned. 01238 01239 addVectorVersion( theOldIntervalH, theObjectH, theBeginTime, theEndTime, theVersionTime ); 01240 01241 } 01242 01243 } else if( theOldIntervalH == theLastIntervalH ) { 01244 01245 // The new interval falls into existing LAST interval. In this case 01246 // we jsut follow the same scenario we were using when initializing a newly 01247 // created interval container with a vector of values. 01248 // This means that each new interval will be trivially "updated" or "cutted" 01249 // (depending on when the new interval ends). 01250 // 01251 // Replace the object in the existing last interval 01252 // if the new one ends in +oo. 01253 01254 for( int j = i; j < entries; j++ ) { 01255 01256 theObjectH = theIntervalVector[j].getObject( ); 01257 theIntervalVector[j].getInterval( theIntervalBase ); 01258 theIntervalVector[j].getExistingInterval( theOldIntervalH ); 01259 01260 theBeginTime = theIntervalBase.getBeginTime( ); 01261 theEndTime = theIntervalBase.getEndTime( ); 01262 01263 // Update the reference to the LAST interval. 01264 01265 theLastIntervalH.lookupObj( intervalContH, "LastInterval", BdbcUpdate ); 01266 if( BdbIsNull(theLastIntervalH)) { 01267 ErrMsg(error) << errorString << endl 01268 << " Failed to locate the LAST interval." << endl 01269 << " The container may be inproperly created and/or initialized." << endl 01270 << " DETECTOR -> " << subsystemTLA( ) << endl 01271 << " CONTAINER -> " << theContainerName << endmsg; 01272 return BdbcError; 01273 } 01274 01275 // Use the object reference from the last interval if the new one 01276 // is equal to zero. 01277 01278 if( BdbIsNull(theObjectH)) { 01279 theLastIntervalH->getObject( theObjectRef ); 01280 theObjectH = theObjectRef; 01281 } 01282 01283 // Cut/append last interval. 01284 01285 if ( theBeginTime == theLastIntervalH->getBeginTime( )) { 01286 01287 status = cutLastInterval( theObjectH, 01288 theLastIntervalH, 01289 theBeginTime, 01290 theEndTime, 01291 0, 01292 theVersionTime ); 01293 } else { 01294 01295 status = appendIntervalR( theObjectH, 01296 theLastIntervalH, 01297 theBeginTime, 01298 theEndTime, 01299 0, 01300 theVersionTime ); 01301 } 01302 if( BdbcSuccess != status ) { 01303 ErrMsg(error) << errorString << endl 01304 << " Failed to cut/append LAST interval." << endl 01305 << " DETECTOR -> " << subsystemTLA( ) << endl 01306 << " CONTAINER -> " << theContainerName << endl 01307 << " BEGIN_TIME -> " << theBeginTime << endl 01308 << " END_TIME -> " << theEndTime << endmsg; 01309 return BdbcError; 01310 } 01311 } 01312 01313 // Just break the outer loop since we've processed 01314 // the remaining elements from the list. 01315 01316 break; 01317 01318 } else { 01319 01320 // Now we are adding an interval somewhere in the middle of the list. This procedure 01321 // is quite routine given the prepared contents of the vector. 01322 01323 addVectorVersion( theOldIntervalH, theObjectH, theBeginTime, theEndTime, theVersionTime ); 01324 } 01325 } 01326 01327 return BdbcSuccess; 01328 } 01329 01330 BdbStatus 01331 BdbDatabase::verifyStoreVector( const vector<BdbCondStoreTime>& theVector ) 01332 { 01333 const char* errorString = "BdbDatabase::verifyStoreVector() -- ERROR."; 01334 01335 // The vector must have at least 2 elements. 01336 01337 int entries = theVector.size( ); 01338 01339 if( entries < 2 ) { 01340 ErrMsg(error) << errorString << endl 01341 << " The vector containes less than 2 elements." << endmsg; 01342 return BdbcError; 01343 } 01344 01345 // The first element must NOT contain the NULL reference. 01346 01347 BdbRef(BdbObject) theObjectRef; 01348 01349 theObjectRef = theVector[0].getObject( ); 01350 if( BdbIsNull(theObjectRef)) { 01351 ErrMsg(error) << errorString << endl 01352 << " The first element of the vector must NOT contain a NULL reference." << endmsg; 01353 return BdbcError; 01354 } 01355 01356 // The last element must contain the NULL reference. 01357 01358 theObjectRef = theVector[entries-1].getObject( ); 01359 if( ! BdbIsNull(theObjectRef)) { 01360 ErrMsg(error) << errorString << endl 01361 << " The last element of the vector must contain a NULL reference." << endmsg; 01362 return BdbcError; 01363 } 01364 01365 // The should be no NULL gaps between the elements 01366 01367 for( int i = 0; i < entries; i++ ) { 01368 if( i > 0 ) { 01369 if( theVector[i].getTime( ) <= theVector[i-1].getTime( )) { 01370 ErrMsg(error) << errorString << endl 01371 << " The NULL gaps in the validity time are not allowed" << endl 01372 << " in the vector." << endl 01373 << " This rule is broken for the element #" << i << endmsg; 01374 return BdbcError; 01375 } 01376 } 01377 } 01378 01379 return BdbcSuccess; 01380 } 01381 01382 BdbStatus 01383 BdbDatabase::buildTopStoreVector( const vector<BdbCondStoreTime>& theVectorIn, 01384 const BdbHandle(BdbIntervalR)& theFirstIntervalH, 01385 const BdbHandle(BdbIntervalR)& theLastIntervalH, 01386 const BdbHandle(BdbIntervalR)& theStartIntervalH, 01387 vector<BdbCondStoreInterval>& theVectorOut ) 01388 { 01389 const char* errorString = "BdbDatabase::buildTopStoreVector() -- ERROR."; 01390 01391 BdbRef(BdbObject) theObjectRef; 01392 BdbTime theBeginTime; 01393 BdbTime theEndTime; 01394 BdbHandle(BdbIntervalR) theIntervalH; 01395 BdbHandle(BdbIntervalR) thePreviousIntervalH; 01396 01397 theIntervalH = theStartIntervalH; 01398 01399 theVectorOut.clear( ); 01400 01401 // Optional alignment in the beginning. 01402 // 01403 // NOTE: The FIRST & LAST intervals are always excluded. 01404 01405 theBeginTime = theVectorIn[0].getTime( ); 01406 theEndTime = theVectorIn[1].getTime( ); 01407 01408 if(( theIntervalH != theFirstIntervalH ) && 01409 ( theIntervalH != theLastIntervalH ) && 01410 ( theBeginTime > theIntervalH->getBeginTime( ))) { 01411 01412 // Insert a "pad" interval at the very beginning if the new interval begins 01413 // later then the existing one. 01414 // 01415 // +----------------- theIntervalH->getBeginTime( ) 01416 // | 01417 // | theBeginTime 01418 // V v 01419 // +........+-------- 01420 // : pad : new 01421 // +========+======== 01422 // : existing 01423 // +================= 01424 // 01425 // NOTE: we are padding the interval with NULL reference. 01426 // 01427 01428 theVectorOut.push_back( BdbCondStoreInterval( BdbIntervalBase( theIntervalH->getBeginTime( ), 01429 theBeginTime ), 01430 theIntervalH, 01431 0 )); 01432 } 01433 01434 // Continue processing the rest of the vector (including the very first interval). 01435 01436 int entries = theVectorIn.size( ); 01437 for( int i = 0; i < ( entries - 1 ); i++ ) { 01438 01439 theObjectRef = theVectorIn[i].getObject( ); 01440 theBeginTime = theVectorIn[i].getTime( ); 01441 theEndTime = theVectorIn[i+1].getTime( ); 01442 01443 if( theEndTime < theIntervalH->getEndTime( )) { 01444 01445 // Introduce the regular interval ending with the end of 01446 // of the new interval. 01447 // 01448 // theBeginTime 01449 // | 01450 // | theEndTime 01451 // v v 01452 // +---------+ 01453 // : new : 01454 // =======+=========+====== 01455 // existing 01456 // ======================== 01457 01458 theVectorOut.push_back( BdbCondStoreInterval( BdbIntervalBase( theBeginTime, 01459 theEndTime ), 01460 theIntervalH, 01461 theObjectRef )); 01462 } else { 01463 01464 // Introduce the regular interval ending with the end of 01465 // of the existing interval. 01466 // 01467 // theBeginTime 01468 // v 01469 // +-------------- 01470 // : new 01471 // =======+=========+==== 01472 // existing : 01473 // =================+==== 01474 // ^ 01475 // | 01476 // +------- theIntervalH->getEndTime( ) 01477 01478 theVectorOut.push_back( BdbCondStoreInterval( BdbIntervalBase( theBeginTime, 01479 theIntervalH->getEndTime( )), 01480 theIntervalH, 01481 theObjectRef )); 01482 01483 // Advance a pointer to the next existing interval. 01484 // 01485 // NOTE: The previous interval is saved in a special variable. 01486 01487 thePreviousIntervalH = theIntervalH; 01488 thePreviousIntervalH->getTopNext( theIntervalH ); 01489 01490 if(( ! BdbIsNull(theIntervalH)) && 01491 ( theEndTime >= theIntervalH->getEndTime( ))) { 01492 01493 // The new interval lasts after the end of the existing interval. 01494 01495 // Include all the "internal" existing intervals into an outout vector. 01496 // These interval lay completelly inside the new input interval. 01497 01498 while(( ! BdbIsNull(theIntervalH)) && 01499 ( theEndTime >= theIntervalH->getEndTime( ))) { 01500 01501 // Introduce the whole existing interval. 01502 // 01503 // -------------------- 01504 // new 01505 // ====+==========+==== 01506 // : existing : 01507 // ====+==========+==== 01508 // ^ ^ 01509 // | | 01510 // | +------- theIntervalH->getEndTime( ) 01511 // | 01512 // +----- theIntervalH->getBeginTime( ) 01513 01514 theVectorOut.push_back( BdbCondStoreInterval( BdbIntervalBase( theIntervalH->getBeginTime( ), 01515 theIntervalH->getEndTime( )), 01516 theIntervalH, 01517 theObjectRef )); 01518 thePreviousIntervalH = theIntervalH; 01519 thePreviousIntervalH->getTopNext( theIntervalH ); 01520 } 01521 } 01522 01523 // Check if the rest of the current existing interval was not 01524 // completelly covered by the new one. 01525 // If so then just complete it. 01526 01527 if(( ! BdbIsNull(theIntervalH)) && 01528 ( theEndTime > theIntervalH->getBeginTime( )) && 01529 ( theEndTime < theIntervalH->getEndTime( ))) { 01530 01531 // Introduce the beginning of the existing interval. 01532 // 01533 // theEndTime 01534 // v 01535 // ---------------+ 01536 // new : 01537 // ====+=============== 01538 // : existing 01539 // ====+=============== 01540 // ^ 01541 // | 01542 // | 01543 // | 01544 // +----- theIntervalH->getBeginTime( ) 01545 01546 theVectorOut.push_back( BdbCondStoreInterval( BdbIntervalBase( theIntervalH->getBeginTime( ), 01547 theEndTime ), 01548 theIntervalH, 01549 theObjectRef )); 01550 } 01551 } 01552 } 01553 01554 // Optional alignment in the end. 01555 // 01556 // NOTE: The LAST interval is always excluded. 01557 01558 if(( ! BdbIsNull(theIntervalH)) && 01559 ( theIntervalH != theLastIntervalH )) { 01560 01561 theEndTime = theVectorIn[entries-1].getTime( ); 01562 01563 if(( theEndTime > theIntervalH->getBeginTime( )) && 01564 ( theEndTime < theIntervalH->getEndTime( ))) { 01565 01566 // Introduce the "pad" interval on the right side of the last 01567 // new interval. 01568 // 01569 // +------- theIntervalH->getEndTime( ) 01570 // theEndTime | 01571 // v v 01572 // ---------+.......+ 01573 // new : pad : 01574 // =========+=======+ 01575 // existing : 01576 // =================+ 01577 // 01578 // NOTE: we are padding the interval with NULL reference. 01579 // 01580 01581 01582 theVectorOut.push_back( BdbCondStoreInterval( BdbIntervalBase( theEndTime, 01583 theIntervalH->getEndTime( )), 01584 theIntervalH, 01585 0 )); 01586 } 01587 } 01588 01589 return BdbcSuccess; 01590 } 01591 01592 void 01593 BdbDatabase::addVectorVersion( BdbHandle(BdbIntervalR)& theOldIntervalH, 01594 const BdbHandle(BdbObject)& theObjectH, 01595 const BdbTime& theBeginTime, 01596 const BdbTime& theEndTime, 01597 const BdbTime& theVersionTime, 01598 d_ULong theTag ) 01599 { 01600 BdbHandle(BdbIntervalR) theNewIntervalH; 01601 BdbHandle(BdbIntervalR) thePreviousIntervalH; 01602 BdbHandle(BdbIntervalR) theNextIntervalH; 01603 01604 // The further operation depends both on the previous context of 01605 // the operation (whether we are are starting creating new versions 01606 // or we are just continuing this) and on the number of versions 01607 // for specified interval. 01608 01609 if( theOldIntervalH->getBeginTime( ) == theBeginTime ) { 01610 01611 // We are about to begin creating versions of the interval. 01612 01613 if( theOldIntervalH->getEndTime( ) == theEndTime ) { 01614 01615 // The only version. 01616 01617 theOldIntervalH.setVersStatus( oocLinearVers ); 01618 createRevisedTopVersion( theOldIntervalH, theNewIntervalH ); 01619 theOldIntervalH.setVersStatus( oocNoVers ); 01620 01621 // Tune the TOPMOST links 01622 01623 theOldIntervalH->getTopPrevious( thePreviousIntervalH ); 01624 theOldIntervalH->getTopNext( theNextIntervalH ); 01625 theOldIntervalH->setTopPrevious( 0 ); 01626 theOldIntervalH->setTopNext( 0 ); 01627 01628 } else { 01629 01630 // The first version. 01631 01632 theOldIntervalH.setVersStatus( oocBranchVers ); 01633 createRevisedTopVersion( theOldIntervalH, theNewIntervalH ); 01634 01635 // Modify the TOPMOST links. Since this is the first interval 01636 // in a sequence of (at least two) versions then we will store 01637 // the reference to the newely created version in the existing 01638 // interval. 01639 01640 theOldIntervalH->getTopPrevious( thePreviousIntervalH ); 01641 theOldIntervalH->getTopNext( theNextIntervalH ); 01642 theOldIntervalH->setTopPrevious( 0 ); 01643 theOldIntervalH->setTopNext( theNewIntervalH ); // Will use this to create next version. 01644 } 01645 01646 } else { 01647 01648 // We continue creating the versions. 01649 01650 if( theOldIntervalH->getEndTime( ) == theEndTime ) { 01651 01652 // The last version. 01653 01654 createRevisedTopVersion( theOldIntervalH, theNewIntervalH ); 01655 theOldIntervalH.setVersStatus( oocNoVers ); 01656 01657 // Modify the TOPMOST links. Now we take the previous & next links 01658 // from the previously created version of the existing interval. 01659 // The handle of the previous version is located through the next link 01660 // of the exising interval. 01661 // Then we just reset this "back" link to zero since we are not 01662 // going to use it anymore. 01663 01664 theOldIntervalH->getTopNext( thePreviousIntervalH ); 01665 theOldIntervalH->setTopNext( 0 ); // This is not needed anymore. 01666 thePreviousIntervalH->getTopNext( theNextIntervalH ); 01667 01668 } else { 01669 01670 // The intermediate version. 01671 01672 createRevisedTopVersion( theOldIntervalH, theNewIntervalH ); 01673 01674 // Modify the TOPMOST links. Now we take the previous & next links 01675 // from the previously created version of the existing interval. 01676 // The handle of the previous version is located through the next link 01677 // of the exising interval. 01678 // Then we just replace the value of this "back" link with the value 01679 // of the newly created interval (version). 01680 01681 theOldIntervalH->getTopNext( thePreviousIntervalH ); 01682 theOldIntervalH->setTopNext( theNewIntervalH ); // Will use this to create next version. 01683 thePreviousIntervalH->getTopNext( theNextIntervalH ); 01684 01685 } 01686 } 01687 01688 // Now we known the previous and next intervals in the TOPMOST chain. So we can 01689 // modify these links as needed. This procedure is irrelevant to the position 01690 // of the nexly created version. 01691 01692 thePreviousIntervalH->setTopNext( theNewIntervalH ); 01693 theNewIntervalH->setTopPrevious( thePreviousIntervalH ); 01694 theNewIntervalH->setTopNext( theNextIntervalH ); 01695 theNextIntervalH->setTopPrevious( theNewIntervalH ); 01696 01697 // Set the validity limits of the new interval. 01698 01699 theNewIntervalH->setBeginTime( theBeginTime ); 01700 theNewIntervalH->setEndTime( theEndTime ); 01701 01702 // Set the proper object, version time and tag into a new interval. 01703 // 01704 // NOTE: We use an object handle, the version time and the tag from the existing 01705 // interval if the NULL handle is being passed as a parameter. 01706 01707 if( BdbIsNull(theObjectH)) { 01708 01709 BdbHandle(BdbObject) theOldObjectH; 01710 BdbRef(BdbObject) theOldObjectRef; 01711 01712 theOldIntervalH->getObject( theOldObjectRef ); 01713 theOldObjectH = theOldObjectRef; 01714 01715 theNewIntervalH->setObject( theOldObjectH ); 01716 theNewIntervalH->setVersionTime( theOldIntervalH->getVersionTime( )); 01717 theNewIntervalH->setTag( theOldIntervalH->getTag( )); 01718 } else { 01719 theNewIntervalH->setObject( theObjectH ); 01720 theNewIntervalH->setVersionTime( theVersionTime ); 01721 theNewIntervalH->setTag( theTag ); 01722 } 01723 01724 /********************************************************************************** 01725 ** THIS CODE IS DISABLED FOR TWO REASONS: 01726 ** 01727 ** 1. It's just not required any more given the current implementation 01728 ** of the low-level interval creation procedures: 01729 ** 01730 ** createVersion() 01731 ** createRevisedTopVersion() 01732 ** 01733 ** 2. It may reset the "reviseAfterStore" revision connection of the newely 01734 ** created version if this feature is turned on for this particular 01735 ** interval container. 01736 ** 01737 ** // Explicitly set the NULL revision id in order to avoid 01738 ** // duplicating this ID from the existing interval (this is how the used here 01739 ** // intervals creation technique works). 01740 ** 01741 ** theNewIntervalH->setRevision( 0 ); 01742 ** 01743 ********************************************************************************** 01744 **/ 01745 01746 // Name new interval in the genealogy tree. 01747 01748 nameVersion( theOldIntervalH, theNewIntervalH ); 01749 } 01750 01751 BdbStatus 01752 BdbDatabase::fetch( BdbHandle(BdbObject)& theObjectH, 01753 const char* theContainerName, 01754 const BdbTime& theTime, 01755 d_ULong theTag ) 01756 { 01757 COUT1 << "CONDFETCH1: detector=" << subsystemTLA( ) << " container=" << theContainerName << " fetch_time=" << theTime << endl; 01758 01759 return findObject( theObjectH, theContainerName, theTime, theTag ); 01760 } 01761 01762 BdbStatus 01763 BdbDatabase::fetch( BdbHandle(BdbObject)& theObjectH, 01764 BdbIntervalBase& theValidityInterval, 01765 const char* theContainerName, 01766 const BdbTime& theTime, 01767 d_ULong theTag ) 01768 { 01769 assert( 0 != theContainerName ); 01770 01771 COUT1 << "CONDFETCH2: detector=" << subsystemTLA( ) << " container=" << theContainerName << " fetch_time=" << theTime << endl; 01772 01773 // Ask accessor to find specified object. 01774 // 01775 // NOTE: This way to get a condition differs from the regular "fetch" since 01776 // it's directly talking to the accessor. 01777 // Nevertheless the correct class cache is set by the accessor. 01778 01779 BdbTime theVersionTime; // We're not using this, but the acccessor's method requires 01780 // a parameter of this type to be passed in. 01781 01782 return _accessor->findObject( this, 01783 theObjectH, 01784 theValidityInterval, 01785 theVersionTime, 01786 theContainerName, 01787 theTime ); 01788 } 01789 01790 BdbStatus 01791 BdbDatabase::fetch( BdbHandle(BdbObject)& theObjectH, 01792 BdbIntervalBase& theValidityInterval, 01793 BdbTime& theVersionTime, 01794 const char* theContainerName, 01795 const BdbTime& theTime, 01796 d_ULong theTag ) 01797 { 01798 assert( 0 != theContainerName ); 01799 01800 COUT1 << "CONDFETCH3: detector=" << subsystemTLA( ) << " container=" << theContainerName << " fetch_time=" << theTime << endl; 01801 01802 // Ask accessor to find specified object. 01803 // 01804 // NOTE: This way to get a condition differs from the regular "fetch" since 01805 // it's directly talking to the accessor. 01806 // Nevertheless the correct class cache is set by the accessor. 01807 01808 return _accessor->findObject( this, 01809 theObjectH, 01810 theValidityInterval, 01811 theVersionTime, 01812 theContainerName, 01813 theTime ); 01814 } 01815 01816 BdbStatus 01817 BdbDatabase::remove( const char* theContainerName, 01818 const BdbTime& theTime ) 01819 { 01820 const char* errorString = "BdbDatabase::remove() -- ERROR."; 01821 01822 assert( 0 != theContainerName ); 01823 01824 COUT1 << "CONDREMOVE: detector=" << subsystemTLA( ) << " container=" << theContainerName << " remove_time=" << theTime << endl; 01825 01826 ErrMsg(error) << errorString << endl 01827 << " Not implemented yet." << endmsg; 01828 return BdbcError; 01829 } 01830 01831 BdbStatus 01832 BdbDatabase::split( const char* theContainerName, 01833 const BdbTime& theTime ) 01834 { 01835 const char* errorString = "BdbDatabase::split() -- ERROR."; 01836 01837 BdbStatus status = BdbcError; 01838 01839 assert ( 0 != theContainerName ); 01840 assert ( BdbTime::minusInfinity != theTime); 01841 assert ( BdbTime::plusInfinity != theTime); 01842 01843 COUT1 << "CONDSPLIT: detector=" << subsystemTLA( ) << " container=" << theContainerName << " split_time=" << theTime << endl; 01844 01845 // Ensure the proper context to be set. 01846 01847 if ( ! verifyIndexMode( )) return BdbcError; 01848 if ( ! setAuthLevel( theContainerName )) return BdbcError; 01849 01850 // Find the baseline interval corresponding to specified time. 01851 01852 BdbHandle(BdbIntervalR) theOldIntervalH; 01853 01854 status = getBaselineInterval( theOldIntervalH, theContainerName, theTime ); 01855 if (( BdbcSuccess != status ) || BdbIsNull(theOldIntervalH)) { 01856 ErrMsg(error) << errorString << endl 01857 << " Failed to locate a baseline interval corresponding to specified time: " << theTime << endl 01858 << " DETECTOR -> " << subsystemTLA( ) << endl 01859 << " CONTSINRE -> " << theContainerName << endmsg; 01860 return BdbcError; 01861 } 01862 01863 // Check if the split time is not equal to the borders of the interval. 01864 // If so then we just return OK. 01865 01866 if (( theOldIntervalH->getBeginTime( ) == theTime ) || 01867 ( theOldIntervalH->getEndTime( ) == theTime )) { 01868 return BdbcSuccess; 01869 } 01870 01871 // Now we decide on a particular split method. Depending on the complexity 01872 // of intervals structure at the split point we have two options: 01873 // 01874 // 1. Split a baseline interval only (including the FIRST and LAST intervals). 01875 // This is actually the most simple case. 01876 // 2. Split a whole vertical tree of intervals (this would exclude "by definition" 01877 // both the FIRST and LAST intervals). 01878 // 01879 // NOTE: Although these two operations have something in common (splitting a baseline 01880 // interval) we still do them separatevly in order to make algorithm more clear. 01881 01882 if ( theOldIntervalH->exist_geneObj( )) { 01883 01884 status = splitIntervalsTree( theContainerName, 01885 theOldIntervalH, 01886 theTime ); 01887 } else { 01888 01889 status = splitBaselineInterval( theOldIntervalH, 01890 theTime ); 01891 } 01892 01893 // Put a record into the History even if the result of splitting was 01894 // not successfull. 01895 01896 historySplit( rcsid, theTime, 0 ); 01897 01898 return status; 01899 } 01900 01901 BdbStatus 01902 BdbDatabase::findObject( BdbHandle(BdbObject)& theObjectH, 01903 const char* theContainerName, 01904 const BdbTime& theTime, 01905 d_ULong theTag ) 01906 { 01907 // NOTE: This operation is deffered to the accessor object. 01908 // 01909 // Hoever the cache will still be corrcetly updated. 01910 01911 BdbStatus status; 01912 01913 assert( 0 != theContainerName ); 01914 01915 COUT1 << "CONDFINDOBJECT: detector=" << subsystemTLA( ) << " container=" << theContainerName << " find_time=" << theTime << endl; 01916 01917 // Ask accessor to locate specified interval. 01918 01919 return _accessor->findObject( this, 01920 theObjectH, 01921 theContainerName, 01922 theTime ); 01923 } 01924 01925 BdbStatus 01926 BdbDatabase::findInterval( BdbHandle(BdbInterval)& theBdbIntervalH, 01927 const char* theContainerName, 01928 const BdbTime& theTime, 01929 d_ULong theTag ) 01930 { 01931 // NOTE: This operation can either be ended up in this call (if 01932 // the cache is OK) or be further deffered to the accessor object. 01933 // 01934 // In the recent case the cache is updated by the result 01935 // obtained from the accessor. 01936 01937 BdbStatus status; 01938 01939 assert( 0 != theContainerName ); 01940 01941 COUT1 << "CONDFINDINTERVAL: detector=" << subsystemTLA( ) << " container=" << theContainerName << " find_time=" << theTime << endl; 01942 01943 theBdbIntervalH = 0; 01944 01945 // Try I: Check if the current cache has what we want. 01946 01947 if ( isValidCacheForContainer( theContainerName ) && 01948 ( ! BdbIsNull(_intervalCacheH)) && 01949 _intervalCacheH->inInterval( theTime )) { 01950 01951 // Return cached interval 01952 01953 theBdbIntervalH = _intervalCacheH; 01954 01955 return BdbcSuccess; 01956 } 01957 01958 // Try II: Ask accessor to locate specified interval. 01959 01960 status = _accessor->findInterval( this, 01961 theBdbIntervalH, 01962 theContainerName, 01963 theTime ); 01964 if ( BdbcSuccess == status ) { 01965 _intervalCacheH = theBdbIntervalH; // Update the cached interval. 01966 } 01967 01968 return status; 01969 } 01970 01971 BdbStatus 01972 BdbDatabase::firstInterval( BdbHandle(BdbInterval)& theIntervalH, 01973 const char* theContainerName ) 01974 { 01975 // NOTE: This operation is deffered to the accessor object. 01976 // 01977 // The internal cache is not considered as a source of the result 01978 // at all. However it is updated by the result obtained from 01979 // the accessor. 01980 01981 BdbStatus status; 01982 01983 // Ask accessor to locate specified interval. 01984 01985 status = _accessor->firstInterval( this, 01986 theIntervalH, 01987 theContainerName ); 01988 if ( BdbcSuccess == status ) { 01989 _intervalCacheH = theIntervalH; // Update the cached interval. 01990 } 01991 01992 return status; 01993 } 01994 01995 BdbStatus 01996 BdbDatabase::lastInterval( BdbHandle(BdbInterval)& theIntervalH, 01997 const char* theContainerName ) 01998 { 01999 // NOTE: This operation is deffered to the accessor object. 02000 // 02001 // The internal cache is not considered as a source of the result 02002 // at all. However it is updated by the result obtained from 02003 // the accessor. 02004 02005 BdbStatus status; 02006 02007 // Ask accessor to locate specified interval. 02008 02009 status = _accessor->lastInterval( this, 02010 theIntervalH, 02011 theContainerName ); 02012 if ( BdbcSuccess == status ) { 02013 _intervalCacheH = theIntervalH; // Update the cached interval. 02014 } 02015 02016 return status; 02017 } 02018 02019 /*** In the old implementation of the algorithm there was 02020 *** the different semantics of the "version time" which ment 02021 *** the time when the interval was actually created (default constructor 02022 *** of BdbTime()). 02023 *** 02024 *** The new implementation is assuming that the "version time" 02025 *** is the property of the BdbObject(), or to be more precise, 02026 *** the time when the object was passed through ::store() 02027 *** interface. 02028 *** 02029 *** Therefore the new algorithm does not use the version time at all. 02030 *** This is less efficient, but it's compensated by a fact that 02031 *** this particular algorithm will be used less frequently then 02032 *** the "regular" revision-aware algorithm. 02033 ***/ 02034 02035 BdbStatus 02036 BdbDatabase::findTopInterval( BdbHandle(BdbInterval)& theBdbIntervalH, 02037 BdbItr(BdbInterval)& theIntervalItr ) 02038 { 02039 const char* errorString = "BdbDatabase::findTopInterval() -- ERROR."; 02040 02041 // Return the topmost interval using genealogy links 02042 // between intervals in a vertical tree. 02043 02044 theBdbIntervalH = NULL; 02045 02046 while ( theIntervalItr.next( )) { 02047 02048 if ( BdbIsNull(theBdbIntervalH)) { 02049 theBdbIntervalH = theIntervalItr; 02050 } else { 02051 02052 int compareResult = verticalCompare( theIntervalItr, theBdbIntervalH ); 02053 02054 switch ( compareResult ) { 02055 02056 case -1: 02057 02058 // The next interval pointed out through the iterator 02059 // sits lower then the current one. So we just ignore it. 02060 02061 break; 02062 02063 case 0: 02064 02065 // The next interval pointed out through the iterator 02066 // is equal to the current one. So we just ignore it. 02067 02068 break; 02069 02070 case 1: 02071 02072 // Replace the current interval with the new one 02073 02074 theBdbIntervalH = theIntervalItr; 02075 02076 break; 02077 02078 default: 02079 02080 ErrMsg(error) << errorString << endl 02081 << " The inconsistent contents of the interval container was found" << endl 02082 << " DETECTOR -> " << subsystemTLA( ) << endl 02083 << " CONTAINER -> " << containerName( ) << endmsg; 02084 return BdbcError; 02085 02086 } 02087 } 02088 } 02089 02090 _intervalCacheH = theBdbIntervalH; 02091 02092 return BdbcSuccess; 02093 } 02094 02095 BdbStatus 02096 BdbDatabase::findRevisedInterval( BdbHandle(BdbInterval)& theIntervalH, 02097 BdbItr(BdbInterval)& theIntervalItr, 02098 d_ULong theRevisionId ) 02099 { 02100 const char* errorString = "BdbDatabase::findRevisedInterval() -- error."; 02101 02102 // This algorithm is not as efficient as it could be. 02103 // The first improvement could be to put a chain/stack of base revisions 02104 // for a specified revision into a cache. 02105 02106 BdbStatus status = BdbcError; 02107 BdbHandle(BdbIntervalR) theNextIntervalH; 02108 BdbHandle(BdbCondRevision) theRevisionH; 02109 vector<BdbHandle(BdbInterval)> intervals; 02110 vector<d_ULong> intervals_revisions; 02111 vector<d_ULong> revisions; 02112 d_ULong intervals_size; 02113 d_ULong revisions_size; 02114 02115 // Build an array of non-revised intervals 02116 02117 while ( theIntervalItr.next()) { 02118 02119 theNextIntervalH = (BdbHandle(BdbIntervalR)&) theIntervalItr; 02120 theNextIntervalH->getRevision( theRevisionH ); 02121 02122 if ( ! BdbIsNull(theRevisionH)) { 02123 intervals.push_back( theIntervalItr ); 02124 intervals_revisions.push_back( theRevisionH->id( )); 02125 } 02126 } 02127 intervals_size = intervals.size( ); 02128 if ( 0 == intervals_size ) { 02129 ErrMsg(error) << errorString << endl 02130 << " Inconsistent contents of the interval container was detected." << endl 02131 << " Baseline interval probably does not exist." << endl 02132 << " DETECTOR -> " << subsystemTLA( ) << endl 02133 << " CONTAINER -> " << containerName( ) << endmsg; 02134 return BdbcError; 02135 } 02136 02137 // Obtain a stack of underlying revisions for a specific revision ID. 02138 02139 status = getRevisionStack( revisions, theRevisionId ); 02140 if ( BdbcSuccess != status ) { 02141 ErrMsg(error) << errorString << endl 02142 << " Failed to get a stack of revisions in the container." << endl 02143 << " The container may have incorrect internal structure." << endl 02144 << " DETECTOR -> " << subsystemTLA( ) << endl 02145 << " CONTAINER -> " << containerName( ) << endmsg; 02146 return status; 02147 } 02148 revisions_size = revisions.size( ); 02149 if ( 0 == revisions_size) { 02150 ErrMsg(error) << errorString << endl 02151 << " A stack of revisions is empty for a revision: " << theRevisionId << endl 02152 << " The container may have incorrect internal structure." << endl 02153 << " DETECTOR -> " << subsystemTLA( ) << endl 02154 << " CONTAINER -> " << containerName( ) << endmsg; 02155 return BdbcError; 02156 } 02157 02158 // Iterate through the lists of both intervals and revisions 02159 // and locate the "best" interval match for a specified revision. 02160 // 02161 // NOTE: We must be able to match at least baseline 02162 // revision. 02163 02164 for ( d_ULong i = 0; i < revisions_size; i++ ) { 02165 for ( d_ULong j = 0; j < intervals_size; j++ ) { 02166 if ( revisions[i] == intervals_revisions[j] ) { 02167 theIntervalH = intervals[j]; 02168 return BdbcSuccess; 02169 } 02170 } 02171 } 02172 02173 ErrMsg(error) << errorString << endl 02174 << " An interval matching revision: " << theRevisionId << " was not found in the containert." << endl 02175 << " The container may have incorrect internal structure." << endl 02176 << " DETECTOR -> " << subsystemTLA( ) << endl 02177 << " CONTAINER -> " << containerName( ) << endmsg; 02178 02179 return BdbcError; 02180 } 02181 02182 BdbRefAny 02183 BdbDatabase::updatedHint( ) 02184 { 02185 // Instantiate the clustering hint object at a very first call 02186 // for the hint. Then obtain the hint itself. 02187 02188 if ( 0 == _myHint ) { 02189 _myHint = new BdbCondClusteringHint( *(BdbConditions::instance( )), subsystemTLA( )); 02190 } 02191 return _myHint->updatedHint( ); 02192 } 02193 02194 //////////////////////// 02195 // Revision interface // 02196 //////////////////////// 02197 02198 // ----------------------------------------------------------------------- 02199 // *********************************************************************** 02200 // 02201 // ::getUnassignedList() 02202 // 02203 // DESCRIPTION: 02204 // 02205 // This function returns a sorted list of intervals 02206 // being in the stack for specified BdbTime or BdbIntervalBase. 02207 // This functions provides a subset of ::getList() intervals 02208 // which do not belong to any revision. 02209 // 02210 // The intervals are sorted according to their version. 02211 // The first interval has a lowest version. 02212 // 02213 // PARAMETERS: 02214 // 02215 // theList a list of intervals to be returned. 02216 // 02217 // theContainerName no comments. 02218 // 02219 // theTime no comments. 02220 // 02221 // theInterval an alternative way to specify theTime. 02222 // The interval beginning time is used only. 02223 // 02224 // RETURN: 02225 // 02226 // BdbcSuccess means success. 02227 // 02228 // BdbcError means any error. 02229 // 02230 // *********************************************************************** 02231 // ----------------------------------------------------------------------- 02232 02233 02234 BdbStatus 02235 BdbDatabase::getUnassignedList( vector<BdbHandle(BdbInterval)>& theList, 02236 const char* theContainerName, 02237 const BdbTime& theTime ) 02238 { 02239 BdbStatus status = BdbcError; 02240 02241 assert( 0 != theContainerName ); 02242 02243 vector<BdbHandle(BdbInterval)> theTmpList; 02244 02245 // Get the complete sorted list. 02246 02247 status = getList( theTmpList, theContainerName, theTime ); 02248 if( BdbcSuccess != status ) return status; 02249 02250 // Exclude intervals which already belong to any revision. 02251 02252 BdbHandle(BdbIntervalR) theIntervalH; 02253 BdbHandle(BdbCondRevision) theRevisionH; 02254 02255 theList.clear( ); 02256 02257 int entries = theTmpList.size( ); 02258 02259 for( int i = 0; i < entries; i++ ) { 02260 02261 theIntervalH = (BdbHandle(BdbIntervalR)&) theTmpList[i]; 02262 theIntervalH->getRevision( theRevisionH ); 02263 02264 if( BdbIsNull(theRevisionH)) { 02265 theList.push_back( theIntervalH ); 02266 } 02267 } 02268 02269 return BdbcSuccess; 02270 } 02271 02272 // ----------------------------------------------------------------------- 02273 // *********************************************************************** 02274 // 02275 // ::getList() 02276 // 02277 // DESCRIPTION: 02278 // 02279 // This function returns a sorted list of all intervals 02280 // being in the stack for specified BdbTime or BdbIntervalBase. 02281 // 02282 // The intervals are sorted according to their version. 02283 // The first interval should have the lowest version, 02284 // corresponding to the BASELINE revision. 02285 // 02286 // PARAMETERS: 02287 // 02288 // theList a list of intervals to be returned. 02289 // 02290 // theContainerName no comments. 02291 // 02292 // theTime no comments. 02293 // 02294 // theInterval an alternative way to specify theTime. 02295 // The interval beginning time is used only. 02296 // 02297 // RETURN: 02298 // 02299 // BdbcSuccess means success. 02300 // 02301 // BdbcError means any error. 02302 // 02303 // *********************************************************************** 02304 // ----------------------------------------------------------------------- 02305 02306 02307 BdbStatus 02308 BdbDatabase::getList( vector<BdbHandle(BdbInterval)>& theList, 02309 const char* theContainerName, 02310 const BdbTime& theTime ) 02311 { 02312 const char* errorString = "BdbDatabase::getList() -- ERROR."; 02313 02314 BdbStatus status; 02315 02316 assert( 0 != theContainerName ); 02317 02318 // Reset the previous contents of the list (if any) 02319 02320 theList.clear( ); 02321 02322 // Find specified container. Reload cache if nessesary. 02323 02324 BdbHandle(BdbContObj) intervalContainerH; 02325 02326 status = findIntervalCont( intervalContainerH, theContainerName ); 02327 if (( BdbcSuccess != status ) || BdbIsNull(intervalContainerH)) { 02328 ErrMsg(error) << errorString << endl 02329 << " Failed to locate specified interval container." << endl 02330 << " DETECTOR -> " << subsystemTLA( ) << endl 02331 << " CONTAINER -> " << theContainerName << endmsg; 02332 return status; 02333 } 02334 02335 // check the first interval 02336 02337 BdbHandle(BdbInterval) theFirstIntervalH; 02338 02339 status = firstInterval( theFirstIntervalH, theContainerName ); 02340 if ( BdbcSuccess != status ) return status; 02341 if ( theFirstIntervalH->inInterval( theTime )) { 02342 theList.push_back( theFirstIntervalH ); 02343 return BdbcSuccess; 02344 } 02345 02346 // check the last interval 02347 02348 BdbHandle(BdbInterval) theLastIntervalH; 02349 02350 status = lastInterval( theLastIntervalH, theContainerName ); 02351 02352 if ( BdbcSuccess != status ) return status; 02353 if ( theLastIntervalH->inInterval( theTime )) { 02354 theList.push_back( theLastIntervalH ); 02355 return BdbcSuccess; 02356 } 02357 02358 // look up the interval 02359 02360 d_ULong gmtTheTime = theTime.getGmtSec( ); 02361 02362 ooLookupKey lookupKey( ooTypeN(BdbInterval), 2 ); 02363 02364 ooLessThanEqualLookupField lessThanEqual( ooTypeN(BdbInterval), 02365 "_beginTime._gmtSec", 02366 & gmtTheTime ); 02367 lookupKey.addField( lessThanEqual ); 02368 02369 ooGreaterThanLookupField greaterThan( ooTypeN(BdbInterval), 02370 "_endTime._gmtSec", 02371 & gmtTheTime ); 02372 lookupKey.addField( greaterThan ); 02373 02374 BdbItr(BdbInterval) BdbIntervalItr; 02375 BdbIntervalItr.scan( intervalContainerH, lookupKey, BdbcRead ); 02376 02377 // Copy all found intervals into the array. 02378 // 02379 // NOTE: The order of intervals in the array is upredictable. 02380 // They do not nessesarily go in a chronological order. 02381 02382 while ( BdbIntervalItr.next( )) { 02383 theList.push_back( BdbIntervalItr ); 02384 } 02385 02386 // Sort intervals in the list in order to make a BASELINE interval 02387 // to go first, and an interval with the highest version -- last. 02388 02389 status = sortIntervalsList( theList ); 02390 if( BdbcSuccess != status ) return status; 02391 02392 return BdbcSuccess; 02393 } 02394 02395 // ----------------------------------------------------------------------- 02396 // *********************************************************************** 02397 // 02398 // ::getUnassignedList() 02399 // 02400 // DESCRIPTION: 02401 // 02402 // This function returns a list of unassigned intervals 02403 // being withing specified borders of validity and versioning 02404 // time limits. 02405 // 02406 // The intervals to be returned in the list are to be completelly 02407 // within the specified validity range. 02408 // 02409 // The intervals are guaranteed not to be in the same stack 02410 // of a same version tree. If so happens then a special conflict 02411 // resolving parameter is used. 02412 // 02413 // Two strategies are now supperted: 02414 // 02415 // RECENT provides the most recent (in version time) 02416 // interval will go into the output list. 02417 // 02418 // EARLIEST the most earliest (in version time) 02419 // interval will go into the output list. 02420 // 02421 // PARAMETERS: 02422 // 02423 // theOutputList a list of intervals to be returned. 02424 // 02425 // theContainerName no comments. 02426 // 02427 // theBeginValidityTime no comments. 02428 // 02429 // theEndValidityTime no comments. 02430 // 02431 // theBeginVersionTime no comments. 02432 // 02433 // theEndVersionTime no comments (not including this time) 02434 // 02435 // theValidityInterval an alternative way to specify 02436 // the validity interval limits. 02437 // 02438 // theVersionInterval an alternative way to specify 02439 // the version interval limits. 02440 // 02441 // theStrategy this is a conflict resolution parameter. 02442 // It's used when two or more intervals 02443 // being within the same version tree 02444 // are met. 02445 // 02446 // RETURN: 02447 // 02448 // BdbcSuccess means success. 02449 // 02450 // BdbcError means any error. 02451 // 02452 // *********************************************************************** 02453 // ----------------------------------------------------------------------- 02454 02455 BdbStatus 02456 BdbDatabase::getUnassignedList( vector<BdbHandle(BdbInterval)>& theOutputList, 02457 const char* theContainerName, 02458 const BdbTime& theBeginValidityTime, 02459 const BdbTime& theEndValidityTime, 02460 const BdbTime& theBeginVersionTime, 02461 const BdbTime& theEndVersionTime, 02462 const SelectionStrategyType theStrategy ) 02463 { 02464 const char* errorString = "BdbDatabase::getUnassignedList() -- ERROR."; 02465 02466 BdbStatus status; 02467 02468 assert( 0 != theContainerName ); 02469 assert( theBeginValidityTime < theEndValidityTime ); 02470 assert( theBeginVersionTime < theEndVersionTime ); 02471 02472 // Reset the previous contents of the list (if any) 02473 02474 theOutputList.clear( ); 02475 02476 // Find specified container. Reload cache if nessesary. 02477 02478 BdbHandle(BdbContObj) intervalContainerH; 02479 02480 status = findIntervalCont( intervalContainerH, theContainerName ); 02481 if (( BdbcSuccess != status ) || BdbIsNull(intervalContainerH)) { 02482 ErrMsg(error) << errorString << endl 02483 << " Failed to locate specified interval container." << endl 02484 << " DETECTOR -> " << subsystemTLA( ) << endl 02485 << " CONTAINER -> " << theContainerName << endmsg; 02486 return status; 02487 } 02488 02489 // Get the baseline intervals for the begin and end validity times. 02490 // 02491 // NOTE: If the end time is "+Infinity" then we set the last baseline 02492 // interval to null value. This will be used later to determine 02493 // the end of the loop condition. 02494 02495 BdbHandle(BdbIntervalR) theBeginBaselineH; 02496 02497 status = getBaselineInterval( theBeginBaselineH, 02498 theContainerName, 02499 theBeginValidityTime ); 02500 if ( BdbcSuccess != status ) { 02501 ErrMsg(error) << errorString << endl 02502 << " Failed to locate baseline interval for: " << theBeginValidityTime << endl 02503 << " DETECTOR -> " << subsystemTLA( ) << endl 02504 << " CONTAINER -> " << theContainerName << endmsg; 02505 return status; 02506 } 02507 02508 BdbHandle(BdbIntervalR) theEndBaselineH; 02509 02510 if( BdbTime::plusInfinity == theEndValidityTime ) { 02511 theEndBaselineH = 0; 02512 } else { 02513 status = getBaselineInterval( theEndBaselineH, 02514 theContainerName, 02515 theEndValidityTime ); 02516 if ( BdbcSuccess != status ) { 02517 ErrMsg(error) << errorString << endl 02518 << " Failed to locate baseline interval for: " << theEndValidityTime << endl 02519 << " DETECTOR -> " << subsystemTLA( ) << endl 02520 << " CONTAINER -> " << theContainerName << endmsg; 02521 return status; 02522 } 02523 } 02524 02525 // Get a baseline interval which is "next" to the end baseline interval. 02526 // This interval will be used as a delimiter in the gorizontal search. 02527 // 02528 // NOTE: we just set this value to null value if the previous search for 02529 // the last baseline interval gave us null value. 02530 02531 BdbHandle(BdbIntervalR) theEndBaselineNextH; 02532 02533 if( BdbIsNull(theEndBaselineH)) { 02534 theEndBaselineNextH = 0; 02535 } else { 02536 theEndBaselineH->getBaselineNext( theEndBaselineNextH ); 02537 } 02538 02539 // Traverse the baseline intervals horizontally from the begin baseline 02540 // interval to the end baseline interval and locate all the unassigned 02541 // intervals within specified range of the version time. 02542 02543 vector<BdbHandle(BdbInterval)> theList; 02544 vector<BdbHandle(BdbInterval)> theTmpList; 02545 02546 int numTmpBranches; 02547 02548 BdbHandle(BdbIntervalR) theBaselineNextH; 02549 BdbHandle(BdbIntervalR) theBaselineH; 02550 BdbHandle(BdbIntervalR) theIntervalH; 02551 02552 theBaselineH = theBeginBaselineH; 02553 02554 do { 02555 02556 // Get a versioning tree of unassigned intervals 02557 // growing from the current baseline interval. 02558 02559 status = getUnassignedTree( theTmpList, 02560 numTmpBranches, 02561 theContainerName, 02562 theBaselineH->getBeginTime( )); 02563 if ( BdbcSuccess != status ) { 02564 ErrMsg(error) << errorString << endl 02565 << " Failed to get a tree of intervals for: " << theBaselineH->getBeginTime( ) << endl 02566 << " DETECTOR -> " << subsystemTLA( ) << endl 02567 << " CONTAINER -> " << theContainerName << endmsg; 02568 return status; 02569 } 02570 02571 // Process the tree. Just skip this step over 02572 // if the tree was empty. 02573 02574 int firstElement = theList.size( ); 02575 int numTmpEntries = theTmpList.size( ); 02576 02577 for ( int i = 0; i < numTmpEntries; i++ ) { 02578 02579 // Check for the a branch delimiter (NULL handle). 02580 02581 if ( BdbIsNull(theTmpList[i])) { 02582 continue; 02583 } 02584 02585 // Check if the interval is completelly withing the required 02586 // validity limits. 02587 02588 if ( ! ((( theBeginValidityTime <= theTmpList[i]->getBeginTime( )) && 02589 ( theEndValidityTime >= theTmpList[i]->getEndTime( ))))) { 02590 continue; 02591 } 02592 02593 // Check if the interval is completelly withing the required 02594 // validity limits. 02595 02596 if ( ! ((( theBeginVersionTime <= theTmpList[i]->getVersionTime( )) && 02597 ( theEndVersionTime > theTmpList[i]->getVersionTime( ))))) { 02598 continue; 02599 } 02600 02601 // Check a list of already existing intervals if there is one 02602 // which is in the same vertical stack. Then leave an interval 02603 // which complies to the specified selection policy. 02604 // Replacing elements are substituted by a NULL handle. 02605 // Later these handles will be removed from the list. 02606 02607 02608 bool overlappingWasNotDetected = true; 02609 bool appendOverlappedInterval = false; 02610 02611 int numEntries = theList.size( ); 02612 02613 for ( int j = firstElement; j < numEntries; j++ ) { 02614 02615 // Just ignore any NULL handles which could appear here 02616 // from the previous checking. 02617 02618 if ( BdbIsNull(theList[j])) { 02619 continue; 02620 } 02621 02622 // Ignore input interval if it's already in the output list. 02623 02624 if( theTmpList[i] == theList[j] ) { 02625 continue; 02626 } 02627 02628 // Check if the intervals are on the vertical stack. 02629 02630 if ( theTmpList[i]->inInterval( *(theList[j])) || 02631 theList[j]->inInterval( *(theTmpList[i]))) { 02632 02633 // Well. Now we have two overlapping intervals. We have to leave 02634 // just one of them. 02635 02636 overlappingWasNotDetected = false; 02637 02638 // The method is generally defined by the specified strategy 02639 // and is based on the value of the version time. 02640 // 02641 // In case If both of them have the same version time 02642 // the ambiguity is being resolved in the following way: an interval 02643 // which is on the top or on the bottom (depending on the required strategy) 02644 // will be chosen. 02645 // 02646 // NOTE: The checking method is sligtly optimized. 02647 // First it tries to use the validity borders. 02648 // And later if the ambiguity is still unresolved 02649 // (because the itervals have the same validity width) 02650 // then the genealogy information is involved into 02651 // the process. 02652 02653 switch ( theStrategy ) { 02654 02655 case EARLIEST: 02656 02657 if ( theTmpList[i]->getVersionTime() < theList[j]->getVersionTime( )) { 02658 02659 // Existing element is more recent. 02660 02661 theList[j] = NULL; 02662 appendOverlappedInterval = true; 02663 02664 } else if( theTmpList[i]->getVersionTime() == theList[j]->getVersionTime( )) { 02665 02666 // Ambiguity. 02667 02668 if ( theTmpList[i]->inInterval( *(theList[j]))) { 02669 02670 if ( theList[j]->inInterval( *(theTmpList[i]))) { 02671 02672 // The worst case of ambiguity -- we have two 02673 // intervals with the same version time and the width. 02674 // The only way to resolve this would be to use 02675 // genealogy information. 02676 02677 int comparisonResult = verticalCompare( theList[j], theTmpList[i] ); 02678 02679 switch ( comparisonResult ) { 02680 02681 case 1: 02682 02683 theList[j] = NULL; 02684 appendOverlappedInterval = true; 02685 02686 break; 02687 02688 case -1: 02689 02690 break; 02691 02692 default: 02693 02694 ErrMsg(error) << errorString << endl 02695 << " Unexpected internal error #1." << endl 02696 << " DETECTOR -> " << subsystemTLA( ) << endl 02697 << " CONTAINER -> " << theContainerName << endmsg; 02698 return BdbcError; 02699 } 02700 02701 } else { 02702 02703 // Existing interval is more narrow in width then the new one. 02704 02705 theList[j] = NULL; 02706 appendOverlappedInterval = true; 02707 02708 } 02709 } 02710 } 02711 02712 break; 02713 02714 case RECENT: 02715 02716 if ( theTmpList[i]->getVersionTime() > theList[j]->getVersionTime( )) { 02717 02718 // Existing element is earlier. 02719 02720 theList[j] = NULL; 02721 appendOverlappedInterval = true; 02722 02723 } else if( theTmpList[i]->getVersionTime() == theList[j]->getVersionTime( )) { 02724 02725 // Ambiguity. 02726 02727 if ( theList[j]->inInterval( *(theTmpList[i]))) { 02728 02729 if ( theTmpList[i]->inInterval( *(theList[j]))) { 02730 02731 // The worst case of ambiguity -- we have two 02732 // intervals with the same version time and the width. 02733 // The only way to resolve this would be to use 02734 // genealogy information. 02735 02736 int comparisonResult = verticalCompare( theList[j], theTmpList[i] ); 02737 02738 switch ( comparisonResult ) { 02739 02740 case 1: 02741 02742 break; 02743 02744 case -1: 02745 02746 theList[j] = NULL; 02747 appendOverlappedInterval = true; 02748 02749 break; 02750 02751 default: 02752 02753 ErrMsg(error) << errorString << endl 02754 << " Unexpected internal error #2." << endl 02755 << " DETECTOR -> " << subsystemTLA( ) << endl 02756 << " CONTAINER -> " << theContainerName << endmsg; 02757 return BdbcError; 02758 } 02759 02760 } else { 02761 02762 // Existing interval is more narrow in width then the new one. 02763 02764 theList[j] = NULL; 02765 appendOverlappedInterval = true; 02766 02767 } 02768 } 02769 } 02770 02771 break; 02772 } 02773 } 02774 } 02775 02776 // Check if found that we need to append the new interval by 02777 // the end of the output list. 02778 02779 if ( overlappingWasNotDetected || appendOverlappedInterval ) { 02780 theList.push_back( theTmpList[i] ); 02781 } 02782 } 02783 02784 // Advance the current baseline handle to the next 02785 // baseline interval. 02786 02787 theBaselineH->getBaselineNext( theBaselineNextH ); 02788 theBaselineH = theBaselineNextH; 02789 02790 // Repeat if the previously processed interval was not the "lastInterval" 02791 // and if we've not reached the "wall" (an interval which is out of current 02792 // validity scope). 02793 02794 } while (( ! BdbIsNull(theBaselineH)) && ( theBaselineH != theEndBaselineNextH )); 02795 02796 // Copy non-NULL handles from the temporary list into 02797 // the output one. 02798 02799 int entries = theList.size( ); 02800 02801 for ( int i = 0; i < entries; i++ ) { 02802 if ( ! BdbIsNull(theList[i])) { 02803 theOutputList.push_back( theList[i] ); 02804 } 02805 } 02806 02807 return BdbcSuccess; 02808 } 02809 02810 // ----------------------------------------------------------------------- 02811 // *********************************************************************** 02812 // 02813 // ::getRevisionList() 02814 // 02815 // DESCRIPTION: 02816 // 02817 // This function returns a sequential list of all intervals 02818 // covering the specified revision withing specified time limits. 02819 // 02820 // The list includes intervals which cover the revision 02821 // either directly or indirectly (through a concept 02822 // of "base" revision). 02823 // 02824 // If the container does not contain any revision information 02825 // (so called "old" persistent schema) then the "topmost" 02826 // intervals are only included into the list. 02827 // 02828 // The limits are included into the list. 02829 // If the limits are not specified -- the list starts from 02830 // the "FirstInterval" and ends up with the "LastInterval". 02831 // 02832 // PARAMETERS: 02833 // 02834 // theList a list of intervals to be returned. 02835 // 02836 // theContainerName no comments. 02837 // 02838 // theBeginTime no comments 02839 // 02840 // theEndTime no comments 02841 // 02842 // theInterval an alternative way to specify theTime. 02843 // The interval beginning time is used only. 02844 // 02845 // theRevisionId no comments. 02846 // 02847 // RETURN: 02848 // 02849 // BdbcSuccess means success. 02850 // 02851 // BdbcError means any error. 02852 // 02853 // *********************************************************************** 02854 // ----------------------------------------------------------------------- 02855 02856 02857 BdbStatus 02858 BdbDatabase::getRevisionList( vector<BdbHandle(BdbInterval)>& theList, 02859 const char* theContainerName, 02860 const BdbTime& theBeginTime, 02861 const BdbTime& theEndTime, 02862 d_ULong theRevisionId ) 02863 { 02864 const char* errorString = "BdbDatabase::getRevisionList() -- ERROR."; 02865 02866 BdbStatus status; 02867 02868 // Currently this procedure is implemented for the baseline 02869 // revision only 02870 02871 assert( BdbCondRevision::BASELINE == theRevisionId ); 02872 assert( 0 != theContainerName ); 02873 02874 // Reset the previous contents of the list (if any) 02875 02876 theList.clear( ); 02877 02878 // Find specified container. Reload cache if nessesary. 02879 02880 BdbHandle(BdbContObj) intervalContH; 02881 02882 status = findIntervalCont( intervalContH, theContainerName ); 02883 if (( BdbcSuccess != status ) || BdbIsNull(intervalContH)) { 02884 ErrMsg(error) << errorString << endl 02885 << " Failed to locate specified interval container." << endl 02886 << " DETECTOR -> " << subsystemTLA( ) << endl 02887 << " CONTAINER -> " << theContainerName << endmsg; 02888 return status; 02889 } 02890 02891 // check the first interval in the list 02892 02893 BdbHandle(BdbInterval) theFirstIntervalH; 02894 02895 if ( theBeginTime == BdbTime::minusInfinity ) { 02896 02897 status = firstInterval( theFirstIntervalH, 02898 theContainerName ); 02899 02900 } else { 02901 02902 status = getBaselineInterval( theFirstIntervalH, 02903 theContainerName, 02904 theBeginTime ); 02905 } 02906 02907 if (( BdbcSuccess != status ) || BdbIsNull(theFirstIntervalH)) { 02908 ErrMsg(error) << errorString << endl 02909 << " Failed to locate an interval corresponding to beginTime = " << theBeginTime << endl 02910 << " DETECTOR -> " << subsystemTLA( ) << endl 02911 << " CONTAINER -> " << theContainerName << endmsg; 02912 return BdbcError; 02913 } 02914 02915 // check the last interval in the list 02916 02917 BdbHandle(BdbInterval) theLastIntervalH; 02918 02919 if ( theEndTime == BdbTime::plusInfinity ) { 02920 02921 status = lastInterval( theLastIntervalH, 02922 theContainerName ); 02923 02924 } else { 02925 02926 status = getBaselineInterval( theLastIntervalH, 02927 theContainerName, 02928 theEndTime ); 02929 } 02930 02931 if ( ( BdbcSuccess != status ) || BdbIsNull(theLastIntervalH)) { 02932 ErrMsg(error) << errorString << endl 02933 << " Failed to locate an interval corresponding to beginTime = " << theEndTime << endl 02934 << " DETECTOR -> " << subsystemTLA( ) << endl 02935 << " CONTAINER -> " << theContainerName << endmsg; 02936 return BdbcError; 02937 } 02938 02939 // Go through baseline list from the FirstInterval 02940 // until the LastInterval. 02941 02942 theList.push_back( theFirstIntervalH ); 02943 02944 BdbHandle(BdbIntervalR) theIntervalH; 02945 BdbHandle(BdbIntervalR) theNextIntervalH; 02946 02947 ((BdbHandle(BdbIntervalR)&) theFirstIntervalH)->getBaselineNext( theNextIntervalH ); 02948 02949 while ( theNextIntervalH != theLastIntervalH ) { 02950 02951 theList.push_back( theNextIntervalH ); 02952 02953 ((BdbHandle(BdbIntervalR)&) theNextIntervalH)->getBaselineNext( theIntervalH ); 02954 02955 if ( BdbIsNull(theIntervalH)) { 02956 ErrMsg(error) << errorString << endl 02957 << " Unexpected end of linked list of intervals was met." << endl 02958 << " DETECTOR -> " << subsystemTLA( ) << endl 02959 << " CONTAINER -> " << theContainerName << endmsg; 02960 return BdbcError; 02961 } 02962 theNextIntervalH = theIntervalH; 02963 } 02964 02965 theList.push_back( theLastIntervalH ); 02966 02967 return BdbcSuccess; 02968 } 02969 02970 // ----------------------------------------------------------------------- 02971 // *********************************************************************** 02972 // 02973 // ::getTree() 02974 // 02975 // DESCRIPTION: 02976 // 02977 // This function returns a list of all intervals 02978 // being in the vertical version tree for specified BdbTime 02979 // or BdbIntervalBase. 02980 // 02981 // The version tree is presented as a sequnce of sub-list 02982 // separated by NULL persistent handle (positivly checked 02983 // with BdbIsNull() macro. 02984 // 02985 // Each sub-list in the tree is a unique vertical stack 02986 // or a branch of intervals going from the BASELINE interval 02987 // up to the end node in the end node in the branch. 02988 // 02989 // 02990 // The sub-lists go in the following order: they always start from 02991 // left-side intervals (the begin time of the baseline interval) 02992 // and end at the right-side intervals (the end time of the baseline 02993 // interval). 02994 // 02995 // NOTE: 02996 // 02997 // The algorithm implemented in this function makes use 02998 // a stack based, recursive algorithm to locate all posible paths 02999 // in the tree. 03000 // 03001 // PARAMETERS: 03002 // 03003 // theList a list of intervals to be returned. 03004 // 03005 // theContainerName no comments. 03006 // 03007 // theTime no comments. 03008 // 03009 // theInterval an alternative way to specify theTime. 03010 // The interval beginning time is used only. 03011 // 03012 // RETURN: 03013 // 03014 // BdbcSuccess means success. 03015 // 03016 // BdbcError means any error. 03017 // 03018 // *********************************************************************** 03019 // ----------------------------------------------------------------------- 03020 03021 BdbStatus 03022 BdbDatabase::getTree( vector<BdbHandle(BdbInterval)>& theList, 03023 int& numBranches, 03024 const char* theContainerName, 03025 const BdbTime& theTime ) 03026 { 03027 BdbStatus status; 03028 03029 assert( 0 != theContainerName ); 03030 03031 // Locate a baseline interval to begin with. 03032 03033 BdbHandle(BdbInterval) theBaselineIntervalH; 03034 03035 status = getBaselineInterval( theBaselineIntervalH, 03036 theContainerName, 03037 theTime ); 03038 if ( BdbcSuccess != status ) return status; 03039 03040 // The following vector is used as a current stack. 03041 // The stack is built by traversing the version tree. 03042 // Each time the last node in the tree is reached -- the complete stack 03043 // contents is copied into ouput vector. 03044 03045 vector<BdbHandle(BdbInterval)> theStack; 03046 03047 // Start traversing the vertical pathes gough "through" the baseline 03048 // intervals to the end nodes. 03049 // Put a baseline interval into the stack. 03050 03051 theList.clear( ); 03052 numBranches = 0; 03053 03054 theStack.push_back( theBaselineIntervalH ); 03055 03056 nextTreeNode( theList, 03057 theStack, 03058 numBranches ); 03059 03060 return BdbcSuccess; 03061 } 03062 03063 void 03064 BdbDatabase::nextTreeNode( vector<BdbHandle(BdbInterval)>& theList, 03065 vector<BdbHandle(BdbInterval)>& theStack, 03066 int& numBranches ) 03067 { 03068 BdbItr(BdbPersObj) theIntervalItr; 03069 BdbHandle(BdbInterval) theIntervalH; 03070 BdbHandle(BdbInterval) theNextIntervalH; 03071 03072 int numElements = theStack.size( ); 03073 03074 // Locate the current element == the last element in the stack. 03075 03076 theIntervalH = theStack[numElements-1]; 03077 theIntervalH->nextVers( theIntervalItr ); 03078 03079 int numSubBranches = 0; 03080 03081 while ( theIntervalItr.next( )) { 03082 03083 theNextIntervalH = (BdbHandle(BdbInterval)&) theIntervalItr; 03084 theStack.push_back( theNextIntervalH ); 03085 03086 nextTreeNode( theList, 03087 theStack, 03088 numBranches ); 03089 03090 //Why do we need the & here????? ryd 03091 theStack.erase( &theNextIntervalH ); 03092 03093 numSubBranches++; 03094 } 03095 03096 // If there were no any "next" intervals -- the current node was 03097 // was the last one. 03098 // Therefore -- we copy the whole stack contents into output vector. 03099 // If this is not the first branch in the tree -- insert a NULL 03100 // handle at the beginning. 03101 03102 if ( ! numSubBranches ) { 03103 03104 if ( numBranches ) { 03105 theList.push_back( NULL ); 03106 } 03107 03108 for ( int i = 0; i < numElements; i++ ) { 03109 theList.push_back( theStack[i] ); 03110 } 03111 03112 numBranches++; 03113 } 03114 03115 return; 03116 } 03117 03118 // ----------------------------------------------------------------------- 03119 // *********************************************************************** 03120 // 03121 // ::getUnassignedTree() 03122 // 03123 // DESCRIPTION: 03124 // 03125 // This function does the same as :getTree() function does 03126 // except that all returned intervals are to be unassigned. 03127 // 03128 // All the "empty" btanches are reduced. 03129 // So that the actual number of branches returned corresponds 03130 // to the non-empty branches. 03131 // 03132 // PARAMETERS: 03133 // 03134 // theList a list of intervals to be returned. 03135 // 03136 // theContainerName no comments. 03137 // 03138 // theTime no comments. 03139 // 03140 // theInterval an alternative way to specify theTime. 03141 // The interval beginning time is used only. 03142 // 03143 // RETURN: 03144 // 03145 // BdbcSuccess means success. 03146 // 03147 // BdbcError means any error. 03148 // 03149 // *********************************************************************** 03150 // ----------------------------------------------------------------------- 03151 03152 BdbStatus 03153 BdbDatabase::getUnassignedTree( vector<BdbHandle(BdbInterval)>& theList, 03154 int& numBranches, 03155 const char* theContainerName, 03156 const BdbTime& theTime ) 03157 { 03158 BdbStatus status; 03159 03160 assert( 0 != theContainerName ); 03161 03162 // First we get an original tree into a temporary vector. 03163 03164 vector<BdbHandle(BdbInterval)> theTmpList; 03165 int numTmpBranches; 03166 03167 status = getTree( theTmpList, 03168 numTmpBranches, 03169 theContainerName, 03170 theTime ); 03171 if ( BdbcSuccess != status ) { 03172 return status; 03173 } 03174 03175 // Reduce the tree by detecting and copying just unassigned elements 03176 // into the output list. 03177 03178 BdbHandle(BdbCondRevision) theRevisionH; 03179 03180 theList.clear( ); 03181 numBranches = 0; 03182 03183 int numCollected = 0; 03184 int numEntries = theTmpList.size( ); 03185 03186 for ( int i = 0; i < numEntries; i++ ) { 03187 03188 if ( ! BdbIsNull(theTmpList[i])) { 03189 03190 ((BdbHandle(BdbIntervalR)&) theTmpList[i])->getRevision( theRevisionH ); 03191 03192 if ( BdbIsNull(theRevisionH)) { 03193 03194 // Well. This is what we are hunting for. 03195 03196 theList.push_back( theTmpList[i] ); 03197 03198 if ( 0 == numCollected ) { 03199 ++numBranches; 03200 } 03201 ++numCollected; 03202 } 03203 03204 } else { 03205 03206 // Append a NULL object by the end of each completed branch 03207 // even if this is the last (or only) branch in the reduced tree. 03208 // Later we will eliminate this object if needed. 03209 03210 if ( 0 != numCollected ) { 03211 numCollected = 0; 03212 theList.push_back( NULL ); 03213 } 03214 } 03215 } 03216 03217 // Eliminate the last NULL object in output list if any. 03218 03219 numEntries = theList.size( ); 03220 03221 if (( numEntries > 0 ) && ( BdbIsNull(theList[numEntries-1]))) { 03222 //why do we need the & here??? ryd 03223 theList.erase( &theList.back() ); 03224 } 03225 03226 return BdbcSuccess; 03227 } 03228 03229 // ----------------------------------------------------------------------- 03230 // *********************************************************************** 03231 // 03232 // ::getBaselineInterval() 03233 // 03234 // DESCRIPTION: 03235 // 03236 // This function locates a bottom-most (baseline) interval 03237 // for specified BdbTime or BdbIntervalBase. 03238 // 03239 // PARAMETERS: 03240 // 03241 // theIntervalH no comments. 03242 // 03243 // theContainerName no comments. 03244 // 03245 // theTime no comments. 03246 // 03247 // RETURN: 03248 // 03249 // BdbcSuccess means success. 03250 // 03251 // BdbcError means any error. 03252 // 03253 // *********************************************************************** 03254 // ----------------------------------------------------------------------- 03255 03256 03257 BdbStatus 03258 BdbDatabase::getBaselineInterval( BdbHandle(BdbInterval)& theIntervalH, 03259 const char* theContainerName, 03260 const BdbTime& theTime ) 03261 { 03262 const char* errorString = "BdbDatabase::getBaselineInterval() -- ERROR."; 03263 03264 BdbStatus status; 03265 03266 assert( 0 != theContainerName ); 03267 03268 theIntervalH = 0; 03269 03270 // Trivial optimization: check the FIRST or the LAST intervals. 03271 // This optimization will also properly initialize internal cache. 03272 03273 status = firstInterval( theIntervalH, theContainerName ); 03274 if ( BdbcSuccess != status ) return status; 03275 if ( theIntervalH->inInterval( theTime )) return BdbcSuccess; 03276 03277 status = lastInterval( theIntervalH, theContainerName ); 03278 if ( BdbcSuccess != status ) return status; 03279 if ( theIntervalH->inInterval( theTime )) return BdbcSuccess; 03280 03281 // Get a sorted stack of intervals for a specified time. 03282 03283 vector<BdbHandle(BdbInterval)> theList; 03284 03285 status = getList( theList, 03286 theContainerName, 03287 theTime ); 03288 if ( BdbcSuccess != status ) return status; 03289 03290 // Check the contents of the returned list. 03291 // The first element of the list must be a baseline one. 03292 03293 if ( 0 == theList.size( )) { 03294 ErrMsg(error) << errorString << endl 03295 << " There is no intervals for specified BdbTime:" << theTime << endl 03296 << " The container is probably corrupted." << endl 03297 << " DETECTOR -> " << subsystemTLA( ) << endl 03298 << " CONTAINER -> " << theContainerName << endmsg; 03299 return BdbcError; 03300 } 03301 theIntervalH = theList[0]; 03302 03303 BdbHandle(BdbCondRevision) theRevisionH; 03304 ((BdbHandle(BdbIntervalR)&) theIntervalH)->getRevision( theRevisionH ); 03305 03306 if ( BdbIsNull(theRevisionH)) { 03307 ErrMsg(error) << errorString << endl 03308 << " Failed to obtain a revision for a baseline interval." << endl 03309 << " The container is probably corrupted." << endl 03310 << " DETECTOR -> " << subsystemTLA( ) << endl 03311 << " CONTAINER -> " << theContainerName << endmsg; 03312 return BdbcError; 03313 } 03314 03315 if ( BdbCondRevision::BASELINE != theRevisionH->id( )) { 03316 ErrMsg(error) << errorString << endl 03317 << " The topmost element of the version stack" << endl 03318 << " has wrong revision ID: " << theRevisionH->id( ) << endl 03319 << " The container is probably corrupted." << endl 03320 << " DETECTOR -> " << subsystemTLA( ) << endl 03321 << " CONTAINER -> " << theContainerName << endmsg; 03322 return BdbcError; 03323 } 03324 03325 return BdbcSuccess; 03326 } 03327 03328 // ----------------------------------------------------------------------- 03329 // *********************************************************************** 03330 // 03331 // ::getTopmostInterval() 03332 // 03333 // DESCRIPTION: 03334 // 03335 // This function locates a topmost interval 03336 // for specified BdbTime or BdbIntervalBase. 03337 // 03338 // PARAMETERS: 03339 // 03340 // theIntervalH no comments. 03341 // 03342 // theContainerName no comments. 03343 // 03344 // theTime no comments. 03345 // 03346 // RETURN: 03347 // 03348 // BdbcSuccess means success. 03349 // 03350 // BdbcError means any error. 03351 // 03352 // *********************************************************************** 03353 // ----------------------------------------------------------------------- 03354 03355 BdbStatus 03356 BdbDatabase::getTopmostInterval( BdbHandle(BdbInterval)& theIntervalH, 03357 const char* theContainerName, 03358 const BdbTime& theTime ) 03359 { 03360 const char* errorString = "BdbDatabase::getTopmostInterval() -- ERROR."; 03361 03362 BdbStatus status; 03363 03364 assert( 0 != theContainerName ); 03365 03366 theIntervalH = 0; 03367 03368 // Trivial optimization: check the FIRST or the LAST intervals. 03369 // This optimization will also properly initialize internal cache. 03370 03371 status = firstInterval( theIntervalH, theContainerName ); 03372 if ( BdbcSuccess != status ) return status; 03373 if ( theIntervalH->inInterval( theTime )) return BdbcSuccess; 03374 03375 status = lastInterval( theIntervalH, theContainerName ); 03376 if ( BdbcSuccess != status ) return status; 03377 if ( theIntervalH->inInterval( theTime )) return BdbcSuccess; 03378 03379 // Get a handle to the interval container 03380 03381 BdbHandle(BdbContObj) intervalContainerH; 03382 getIntervalContH( intervalContainerH ); 03383 03384 // Initialize the iterator for a vertical stack of intervals. 03385 03386 d_ULong gmtTheTime = theTime.getGmtSec( ); 03387 03388 ooLookupKey lookupKey( ooTypeN(BdbInterval), 2 ); 03389 03390 ooLessThanEqualLookupField lessThanEqual( ooTypeN(BdbInterval), 03391 "_beginTime._gmtSec", 03392 & gmtTheTime ); 03393 lookupKey.addField( lessThanEqual ); 03394 03395 ooGreaterThanLookupField greaterThan( ooTypeN(BdbInterval), 03396 "_endTime._gmtSec", 03397 & gmtTheTime ); 03398 lookupKey.addField( greaterThan ); 03399 03400 BdbItr(BdbInterval) theIntervalItr; 03401 theIntervalItr.scan( intervalContainerH, lookupKey, BdbcRead ); 03402 03403 // Ignore any revision informationand locate the TOPMOST interval 03404 // in the stack. 03405 03406 return findTopInterval( theIntervalH, 03407 theIntervalItr ); 03408 } 03409 03410 // ----------------------------------------------------------------------- 03411 // *********************************************************************** 03412 // 03413 // ::getRevisedInterval() 03414 // 03415 // DESCRIPTION: 03416 // 03417 // This function locates an interval 03418 // for specified BdbTime and revision ID. 03419 // 03420 // If there is not an interval with specified revision ID 03421 // in a vertical stack then an interval with direct or indirect 03422 // base revision ID is taken. 03423 // 03424 // PARAMETERS: 03425 // 03426 // theIntervalH no comments. 03427 // 03428 // theContainerName no comments. 03429 // 03430 // theTime no comments. 03431 // 03432 // theRevisionId no comments. 03433 // 03434 // RETURN: 03435 // 03436 // BdbcSuccess means success. 03437 // 03438 // BdbcError means any error. 03439 // 03440 // *********************************************************************** 03441 // ----------------------------------------------------------------------- 03442 03443 BdbStatus 03444 BdbDatabase::getRevisedInterval( BdbHandle(BdbInterval)& theIntervalH, 03445 const char* theContainerName, 03446 const BdbTime& theTime, 03447 d_ULong theRevisionId ) 03448 { 03449 const char* errorString = "BdbDatabase::getRevisedInterval() -- ERROR."; 03450 03451 BdbStatus status; 03452 03453 assert( 0 != theContainerName ); 03454 03455 theIntervalH = 0; 03456 03457 // A small optimization for BASELINE revision. 03458 03459 if( BdbCondRevision::BASELINE == theRevisionId ) { 03460 03461 return getBaselineInterval( theIntervalH, 03462 theContainerName, 03463 theTime ); 03464 } 03465 03466 // The following operation are executed within an exception-like loop. 03467 03468 bool theLoopFailed = true; 03469 03470 while ( true ) { 03471 03472 // get a handle to the interval container 03473 03474 BdbHandle(BdbContObj) intervalContH; 03475 03476 status = findIntervalCont( intervalContH, theContainerName ); 03477 if (( BdbcSuccess != status ) || BdbIsNull(intervalContH)) { 03478 ErrMsg(error) << errorString << endl 03479 << " Failed to locate the interval container." << endl 03480 << " DETECTOR -> " << subsystemTLA( ) << endl 03481 << " CONTAINER -> " << theContainerName << endmsg; 03482 return BdbcError; 03483 } 03484 03485 // Trivial optimization for the FIRST and the LAST intervals. It will also 03486 // initialize the internal cache. 03487 03488 status = firstInterval( theIntervalH, theContainerName ); 03489 if ( BdbcSuccess != status ) return status; 03490 if ( theIntervalH->inInterval( theTime )) return BdbcSuccess; 03491 03492 status = lastInterval( theIntervalH, theContainerName ); 03493 if ( BdbcSuccess != status ) return status; 03494 if ( theIntervalH->inInterval( theTime )) return BdbcSuccess; 03495 03496 // Get the cached registry. 03497 03498 BdbHandle(BdbCondRegistry) registryH; 03499 getRegistryH( registryH ); 03500 03501 // Get a stack of revisions for specified revision (including 03502 // this revision itself. 03503 03504 vector<d_ULong> theRevisionStack; 03505 03506 BdbHandle(BdbCondRevision) theRevisionH; 03507 BdbHandle(BdbCondRevision) theBaseRevisionH; 03508 03509 registryH->getRevision( theRevisionH, theRevisionId ); 03510 if ( BdbIsNull( theRevisionH )) { 03511 ErrMsg(error) << errorString << endl 03512 << " Specified revision does not exist." << endmsg; 03513 break; 03514 } 03515 03516 do { 03517 theRevisionStack.push_back( theRevisionH->id( )); 03518 theRevisionH->getBaseRevision( theBaseRevisionH ); 03519 theRevisionH = theBaseRevisionH; 03520 } while ( ! BdbIsNull( theRevisionH )); 03521 03522 // Check the contents of the revision stack. It must contain 03523 // at list 2 elements (the revision itself and the BASELINE revision's ID. 03524 // The first element of the stack must be the revision itself. 03525 // The last element in the stack must be the BASELINE revision. 03526 03527 int entriesInRevisionStack = theRevisionStack.size( ); 03528 03529 if (( entriesInRevisionStack < 2 ) || 03530 ( theRevisionId != theRevisionStack[0] ) || 03531 ( BdbCondRevision::BASELINE != theRevisionStack[entriesInRevisionStack-1] )) { 03532 ErrMsg(error) << errorString << endl 03533 << " The wrong base revision for a specified revision." << endl 03534 << " The interval contaioner may have incorrect internal structure." << endmsg; 03535 break; 03536 } 03537 03538 // Get a vertical stack of intervals for a specified time. 03539 // 03540 // NOTE: We assume that the list is sorted, and the first 03541 // interval in the list is a BASELINE one. 03542 03543 vector<BdbHandle(BdbInterval)> theList; 03544 03545 status = getList( theList, theContainerName, theTime ); 03546 if (( BdbcSuccess != status ) || ( 0 == theList.size( ))) { 03547 ErrMsg(error) << errorString << endl 03548 << " Failed to get vertical stack of intervals for BdbTime = " << theTime << endmsg; 03549 break; 03550 } 03551 03552 int entriesInIntervalsList = theList.size( ); 03553 03554 // Locate the best candidate in the list starting from the beginning 03555 // of the revisions stack. The first element in this stack should be 03556 // the revision passed as a parameter to this procedure, the last element 03557 // should be BASELINE revision. 03558 // 03559 // NOTE: The "best" candidate is defined as an interval which is either directly 03560 // connected to the specified revision or has the biggest revision ID 03561 // in between this revision ID and BASELINE revision ID (=0). 03562 03563 theIntervalH = NULL; 03564 03565 for ( int i = 0; i < entriesInRevisionStack; i++ ) { 03566 03567 for ( int j = (entriesInIntervalsList-1); j >= 0; j-- ) { 03568 03569 ((BdbHandle(BdbIntervalR)&) theList[j])->getRevision( theRevisionH ); 03570 03571 if ( ! BdbIsNull( theRevisionH )) { 03572 03573 if ( theRevisionH->id( ) == theRevisionStack[i] ) { 03574 theIntervalH = theList[j]; 03575 break; 03576 } 03577 } 03578 } 03579 if ( ! BdbIsNull(theIntervalH)) break; 03580 } 03581 03582 if ( BdbIsNull(theIntervalH)) { 03583 ErrMsg(error) << errorString << endl 03584 << " No match has been found between a stack of intervals and a stack of revisions." << endl 03585 << " The interval container may have inconsistent or corrupted structure." << endmsg; 03586 break; 03587 } 03588 03589 theLoopFailed = false; 03590 break; 03591 } 03592 if ( theLoopFailed ) { 03593 03594 ErrMsg(error) << " DETECTOR -> " << subsystemTLA( ) << endl 03595 << " CONTAINER -> " << theContainerName << endl 03596 << " REVISION ID -> " << theRevisionId << endmsg; 03597 03598 return BdbcError; 03599 } 03600 03601 return BdbcSuccess; 03602 } 03603 03604 // ----------------------------------------------------------------------- 03605 // *********************************************************************** 03606 // 03607 // ::createRevision() 03608 // ::updateRevision() 03609 // 03610 // DESCRIPTION: 03611 // 03612 // These functions take a list of the specified intervals 03613 // and put them into a specified (by ID) revision. 03614 // 03615 // The difference between them is that ::createRevision() 03616 // allocates a new revision ID each time it's called. 03617 // 03618 // The intervals from the input list are checked to satisfy 03619 // several requirements. 03620 // 03621 // When all of the requirements are met -- then, and only then, 03622 // a new revision is being allocated and created or updated 03623 // dpending on which method was called. 03624 // 03625 // The ::createRevision() returns a created revision ID. 03626 // 03627 // This algorithm checks if specified interval is or is already 03628 // a member of an existing revision: 03629 // 03630 // - if it's the same revision as specified one -- then there 03631 // nothing to do with this interval. 03632 // - if the interval belongs to another revision -- then a copy 03633 // revision -- then nothing to do. 03634 // 03635 // PARAMETERS: 03636 // 03637 // theList a list of intervals to be included into 03638 // specified revision. 03639 // The order of entries in the list does 03640 // not play any role. 03641 // 03642 // theContainerName no comments. 03643 // 03644 // theRevisionId a revision ID to use or return. The meaning 03645 // and the direction of this parameter depends 03646 // on which specific method is called. 03647 // 03648 // theBaseRevisionId a base revision ID which is used when 03649 // a specified above revision is created. 03650 // Is ignored if the revision already exist. 03651 // 03652 // theSite an optional argument specifying a site 03653 // where the revision is originated. 03654 // Is ignored if the revision already exist. 03655 // 03656 // theDescription an optional argument dscribing specified 03657 // revision. 03658 // Is ignored if the revision already exist. 03659 // 03660 // RETURN: 03661 // 03662 // BdbcSuccess means success. 03663 // 03664 // BdbcError means any error. 03665 // 03666 // *********************************************************************** 03667 // ----------------------------------------------------------------------- 03668 03669 BdbStatus 03670 BdbDatabase::createRevision( vector<BdbHandle(BdbInterval)>& theList, 03671 const char* theContainerName, 03672 d_ULong& theRevisionId, 03673 d_ULong theBaseRevisionId, 03674 const char* theSite, 03675 const char* theDescr ) 03676 { 03677 const char* errorString = "BdbDatabase::createRevision() -- ERROR."; 03678 03679 BdbStatus status; 03680 03681 assert ( 0 != theContainerName ); 03682 03683 // Ensure the proper context to be set. 03684 03685 if ( ! verifyIndexMode( )) return BdbcError; 03686 if ( ! setAuthLevel( theContainerName )) return BdbcError; 03687 03688 // Perform the following operation in the exception-like loop. 03689 03690 bool theLoopFailed = true; 03691 03692 while ( true ) { 03693 03694 // Allocate the new revision ID. 03695 // This would also initialize the internal cache. 03696 03697 theRevisionId = getNextAvailableRevisionId( theContainerName ); 03698 if ( BdbCondRevision::ILLEGAL == theRevisionId ) { 03699 ErrMsg(error) << errorString << endl 03700 << " Failed to allocate a new revision ID" << endmsg; 03701 break; 03702 } 03703 03704 // Get the cached registry. 03705 03706 BdbHandle(BdbCondRegistry) registryH; 03707 getRegistryH( registryH ); 03708 03709 // The revision should not exist. 03710 03711 BdbHandle(BdbCondRevision) theRevisionH; 03712 registryH->getRevision( theRevisionH, theRevisionId ); 03713 if( ! BdbIsNull( theRevisionH )) { 03714 ErrMsg(error) << errorString << endl 03715 << " Specified revision ID = " << theRevisionId << " already exist." << endmsg; 03716 break; 03717 } 03718 03719 // The base revision should already exist. 03720 03721 BdbHandle(BdbCondRevision) theBaseRevisionH; 03722 registryH->getRevision( theBaseRevisionH, theBaseRevisionId ); 03723 if( BdbIsNull( theBaseRevisionH )) { 03724 ErrMsg(error) << errorString << endl 03725 << " Specified base revision ID = " << theBaseRevisionId << " does not exist." << endmsg; 03726 break; 03727 } 03728 03729 // Verify the list of intervals. 03730 03731 status = verifyIntervals( theList, theContainerName, theRevisionId ); 03732 if ( BdbcSuccess != status ) { 03733 ErrMsg(error) << errorString << endl 03734 << " Failed to verify the quality of passed intervals." << endmsg; 03735 break; 03736 } 03737 03738 // Get the cached container handle. 03739 03740 BdbHandle(BdbContObj) intervalContH; 03741 getIntervalContH( intervalContH ); 03742 03743 // Create a revision. 03744 // Set a base revision for it. 03745 // Add new revision to the registry. 03746 03747 const char* theCreationSite = theSite; 03748 if( theCreationSite == (char*) 0 ) { 03749 theCreationSite = getenv( "BFSITE" ); 03750 if( theCreationSite == (char*) 0 ) { 03751 theCreationSite = "unknown"; 03752 } 03753 } 03754 03755 theRevisionH = new( intervalContH ) BdbCondRevision( theRevisionId, 03756 BdbTime( ), 03757 theCreationSite, 03758 theDescr ); 03759 status = theRevisionH->setBaseRevision( theBaseRevisionH ); 03760 if( BdbcSuccess != status ) { 03761 ErrMsg(error) << errorString << endl 03762 << " Failed to set a base revision for a newly created revision." << endmsg; 03763 break; 03764 } 03765 03766 registryH->addRevision( theRevisionH ); 03767 03768 // Put a record into the History. 03769 03770 historyRCreate( rcsid, 03771 theList, 03772 theBaseRevisionId, 03773 theRevisionId, 03774 theCreationSite, 03775 theDescr ); 03776 03777 // Include the intervals into revision. 03778 03779 includeIntoRevision( theList, theRevisionH ); 03780 03781 theLoopFailed = false; 03782 break; 03783 } 03784 if ( theLoopFailed ) { 03785 03786 ErrMsg(error) << " DETECTOR -> " << subsystemTLA( ) << endl 03787 << " CONTAINER -> " << theContainerName << endmsg; 03788 return BdbcError; 03789 } 03790 03791 return BdbcSuccess; 03792 } 03793 03794 BdbStatus 03795 BdbDatabase::updateRevision( vector<BdbHandle(BdbInterval)>& theList, 03796 const char* theContainerName, 03797 d_ULong theRevisionId ) 03798 { 03799 const char* errorString = "BdbDatabase::updateRevision() -- ERROR."; 03800 03801 BdbStatus status; 03802 03803 assert ( 0 != theContainerName ); 03804 assert ( theRevisionId > BdbCondRevision::BASELINE ); 03805 03806 // Ensure the proper context to be set. 03807 03808 if ( ! verifyIndexMode( )) return BdbcError; 03809 if ( ! setAuthLevel( theContainerName )) return BdbcError; 03810 03811 // Perform the following operation in the exception-like loop. 03812 03813 bool theLoopFailed = true; 03814 03815 while ( true ) { 03816 03817 // Verify the list of intervals. 03818 // This will also initialize the cache. 03819 03820 status = verifyIntervals( theList, theContainerName, theRevisionId ); 03821 if ( BdbcSuccess != status ) { 03822 ErrMsg(error) << errorString << endl 03823 << " Failed to verify the quality of passed intervals." << endmsg; 03824 break; 03825 } 03826 03827 // Get the cached registry. 03828 03829 BdbHandle(BdbCondRegistry) registryH; 03830 getRegistryH( registryH ); 03831 03832 // The revision should already exist. 03833 03834 BdbHandle(BdbCondRevision) theRevisionH; 03835 03836 registryH->getRevision( theRevisionH, theRevisionId ); 03837 if( BdbIsNull( theRevisionH )) { 03838 ErrMsg(error) << errorString << endl 03839 << " Specified revision ID = " << theRevisionId << " does not exist." << endmsg; 03840 break; 03841 } 03842 03843 // Put a record into the History. 03844 03845 historyRUpdate( rcsid, 03846 theList, 03847 theRevisionId ); 03848 03849 // Include the intervals into revision. 03850 03851 includeIntoRevision( theList, theRevisionH ); 03852 03853 theLoopFailed = false; 03854 break; 03855 } 03856 if ( theLoopFailed ) { 03857 03858 ErrMsg(error) << " DETECTOR -> " << subsystemTLA( ) << endl 03859 << " CONTAINER -> " << theContainerName << endmsg; 03860 return BdbcError; 03861 } 03862 03863 return BdbcSuccess; 03864 } 03865 03866 // ----------------------------------------------------------------------- 03867 // *********************************************************************** 03868 // 03869 // ::deleteRevision() 03870 // 03871 // DESCRIPTION: 03872 // 03873 // These function deletes the specified (by ID) revision from 03874 // a container. 03875 // 03876 // The revision can be deleted when all of the followinig 03877 // requrements are met: 03878 // 03879 // - a user poseses a group privelege to write into containers 03880 // of a detector where the specified containers belongs to; 03881 // 03882 // - it's not the BASELINE revision (ID = 0); 03883 // 03884 // - the specified revision does not have dependent (or "child") 03885 // revisions using it as their base. 03886 // 03887 // When the operation is finished then the revision description object 03888 // is removed from the interval container and all the directly 03889 // connected intervals become "unassigned" ones (i.e. being disconnected 03890 // from any particular revision). 03891 // 03892 // No record is placed into the History of the container. 03893 // 03894 // PARAMETERS: 03895 // 03896 // theContainerName no comments. 03897 // 03898 // theRevisionId a revision ID. 03899 // 03900 // RETURN: 03901 // 03902 // BdbcSuccess means success. 03903 // 03904 // BdbcError means any error. 03905 // 03906 // *********************************************************************** 03907 // ----------------------------------------------------------------------- 03908 03909 BdbStatus 03910 BdbDatabase::deleteRevision( const char* theContainerName, 03911 d_ULong& theRevisionId ) 03912 { 03913 const char* errorString = "BdbDatabase::deleteRevision() -- ERROR."; 03914 03915 BdbStatus status; 03916 03917 assert ( 0 != theContainerName ); 03918 03919 // Ensure the proper context to be set. 03920 03921 if ( ! verifyIndexMode( )) return BdbcError; 03922 if ( ! setAuthLevel( theContainerName )) return BdbcError; 03923 03924 // Perform the following operation in the exception-like loop. 03925 03926 bool theLoopFailed = true; 03927 03928 while ( true ) { 03929 03930 // The BASELINE revision can't be deleted in this way. 03931 03932 if( BdbCondRevision::BASELINE == theRevisionId ) { 03933 ErrMsg(error) << errorString << endl 03934 << " An attempt to delete the BASELINE revision has been detected." << endl 03935 << " This revision can never be deleted." << endmsg; 03936 break; 03937 } 03938 03939 // Locate the registry for specified revision 03940 03941 BdbHandle(BdbCondRegistry) theRegistryH; 03942 03943 status = findRegistry( theRegistryH, theContainerName ); 03944 if(( BdbcSuccess != status ) || BdbIsNull(theRegistryH)) { 03945 ErrMsg(error) << errorString << endl 03946 << " Failed to locate Registry n the container." << endmsg; 03947 break; 03948 } 03949 03950 // The revision should exist. 03951 03952 BdbHandle(BdbCondRevision) theRevisionH; 03953 03954 theRegistryH->getRevision( theRevisionH, theRevisionId ); 03955 if( BdbIsNull(theRevisionH)) { 03956 ErrMsg(error) << errorString << endl 03957 << " Specified revision does not exist." << endmsg; 03958 break; 03959 } 03960 03961 // The revision should not have any dependent revisions using it as 03962 // their base revision. 03963 03964 BdbItr(BdbCondRevision) theItr; 03965 03966 theRevisionH->setDependentItr( theItr ); 03967 while( theItr.next( )) { 03968 ErrMsg(error) << errorString << endl 03969 << " The revision can't be deleted since it's being used as base revision" << endl 03970 << " by other revisions. Removing this revision would make the internal" << endl 03971 << " structure of the container inconsistent." << endmsg; 03972 break; 03973 } 03974 03975 // Put a record into the History. 03976 03977 historyRDelete( rcsid, 03978 theRevisionId ); 03979 03980 // Delete revision object. 03981 03982 BdbDelete(theRevisionH); 03983 03984 theLoopFailed = false; 03985 break; 03986 } 03987 if ( theLoopFailed ) { 03988 03989 ErrMsg(error) << " DETECTOR -> " << subsystemTLA( ) << endl 03990 << " CONTAINER -> " << theContainerName << endl 03991 << " REVISION ID -> " << theRevisionId <<endmsg; 03992 return BdbcError; 03993 } 03994 03995 return BdbcSuccess; 03996 } 03997 03998 d_ULong 03999 BdbDatabase::getMostRecentRevisionId( const char* theContainerName ) 04000 { 04001 d_ULong result = BdbCondRevision::ILLEGAL; 04002 04003 const char* errorString = "BdbDatabase::getMostRecentRevisionId() -- ERROR."; 04004 04005 BdbStatus status; 04006 04007 assert ( 0 != theContainerName ); 04008 04009 // Continue the sequence of operations within a exception-like loop. 04010 04011 bool theLoopFailed = true; 04012 04013 while( true ) { 04014 04015 // Find Registry 04016 04017 BdbHandle(BdbCondRegistry) theRegistry; 04018 status = findRegistry( theRegistry, theContainerName ); 04019 if ( BdbcSuccess != status ) { 04020 ErrMsg(error) << errorString << endl 04021 << " Failed to locate Registry in this container." << endmsg; 04022 break; 04023 } 04024 04025 // Iterate through the list of revisions and locate the one with 04026 // biggest number. 04027 // Later we will increment this number by one and return to a caller. 04028 04029 BdbItr(BdbCondRevision) theItr; 04030 theRegistry->setRevisionItr( theItr ); 04031 04032 result = BdbCondRevision::BASELINE; 04033 04034 while ( theItr.next( )) { 04035 04036 int id = theItr->id( ); 04037 if( id > result ) { 04038 result = id; 04039 } 04040 } 04041 04042 theLoopFailed = false; 04043 break; 04044 } 04045 if ( theLoopFailed ) { 04046 04047 ErrMsg(error) << " DETECTOR -> " << subsystemTLA( ) << endl 04048 << " CONTAINER -> " << theContainerName << endmsg; 04049 return BdbCondRevision::ILLEGAL; 04050 04051 } 04052 04053 return result; 04054 } 04055 04056 d_ULong 04057 BdbDatabase::getNextAvailableRevisionId( const char* theContainerName ) 04058 { 04059 d_ULong result; 04060 04061 const char* errorString = "BdbDatabase::getNextAvailableRevisionId() -- ERROR."; 04062 04063 assert ( 0 != theContainerName ); 04064 04065 result = getMostRecentRevisionId( theContainerName ); 04066 if( BdbCondRevision::ILLEGAL == result ) { 04067 ErrMsg(error) << errorString << endl 04068 << " Failed to get the most recent revision ID." << endl 04069 << " DETECTOR -> " << subsystemTLA( ) << endl 04070 << " CONTAINER -> " << theContainerName << endmsg; 04071 return result; 04072 } else { 04073 result++; 04074 } 04075 04076 return result; 04077 } 04078 04079 bool 04080 BdbDatabase::setAuthLevel( const char* theContainerName ) 04081 { 04082 BdbStatus status; 04083 04084 // Check if the previous context is going to change. 04085 04086 if( ! isValidCacheForContainer( theContainerName )) { 04087 _authLevelIsSet = false; 04088 } 04089 04090 // Switch the Authorization context. 04091 04092 if( ! _authLevelIsSet ) { 04093 04094 // First of all we are trying to check if the Authorization system 04095 // would allow us to write into a detector area of specified 04096 // interval container (which may be different from the one used 04097 // during database opening if the USER AREA is used from specified 04098 // interval conatiner). 04099 04100 if ( ! verifyAuthLevelOnly( theContainerName )) return false; 04101 04102 // Check if current container is WRITE-locked. The base class 04103 // should have this information. 04104 04105 if ( isWriteLocked( theContainerName )) { 04106 ErrMsg(error) << "BdbDatabase::setAuthLevel() -- ERROR." << endl 04107 << " The container is WRITE-locked for current federation." << endl 04108 << " DETECTOR -> " << subsystemTLA( ) << endl 04109 << " CONTAINER -> " << theContainerName << endmsg; 04110 return false; 04111 } 04112 04113 _authLevelIsSet = true; 04114 } 04115 04116 return true; 04117 } 04118 04119 bool 04120 BdbDatabase::verifyAuthLevelOnly( const char* theContainerName ) 04121 { 04122 BdbStatus status; 04123 04124 // Check with the Authorization system if this detector is available 04125 // for modifications to current user. 04126 // 04127 // NOTE: We are using a translated detector name because, depending on 04128 // the contents of the REVISION PATH, this particular container 04129 // may be located in the USER AREA, which is in different detector. 04130 04131 string theCorrectedSubsystemName = correctedSubsystemName( theContainerName ); 04132 04133 BdbConditions* theApp = BdbConditions::instance( ); 04134 status = theApp->setAuthLevel( BdbDomain::Group, 04135 theCorrectedSubsystemName.c_str() ); 04136 if( BdbcSuccess != status ) { 04137 ErrMsg(error) << "BdbDatabase::verifyAuthLevelOnly() -- ERROR." << endl 04138 << " Failed to set the Authorization level." << endl 04139 << " DETECTOR -> " << subsystemTLA( ) << endl 04140 << " CONTAINER -> " << theContainerName << endmsg; 04141 return false; 04142 } 04143 04144 return true; 04145 } 04146 04147 bool 04148 BdbDatabase::verifyIndexMode( ) 04149 { 04150 if( oocSensitive != BdbApplicationOrDomain::activeInstance( )->indexMode( )) { 04151 ErrMsg(error) << "BdbDatabase::verifyIndexMode() -- error." << endl 04152 << " Wrong transaction mode was detected." << endl 04153 << " This will prevent the correct versioning of the BdbInterval objects." << endl 04154 << " Please, check if the following environment variable: OO_INDEX_MODE" << endl 04155 << " is set to 1 before to run your application." << endmsg; 04156 return false; 04157 } 04158 04159 return true; 04160 } 04161 04162 /*** The old algorithm has been replaced due to changed semantics 04163 *** of the "version time". Now this time is bound to the time, 04164 *** when BdbObject passed through the ::store() interface, 04165 *** rather then a version of an interval is created. 04166 *** 04167 *** Here is the modified algorithm using the genealogy 04168 *** information in order to locate the tompost interval. 04169 ***/ 04170 04171 BdbStatus 04172 BdbDatabase::findInterval( BdbHandle(BdbIntervalR)& theBdbIntervalH, 04173 const BdbTime& theTime, 04174 d_ULong theTag ) 04175 { 04176 // Get the cached container handle. 04177 04178 BdbHandle(BdbContObj) intervalContH; 04179 getIntervalContH( intervalContH ); 04180 04181 // Setup the vertical iterator. 04182 04183 d_ULong gmtTheTime = theTime.getGmtSec( ); 04184 04185 ooLookupKey lookupKey( ooTypeN(BdbInterval), 2 ); 04186 04187 ooLessThanEqualLookupField lessThanEqual( ooTypeN(BdbInterval), 04188 "_beginTime._gmtSec", 04189 & gmtTheTime ); 04190 lookupKey.addField( lessThanEqual ); 04191 04192 ooGreaterThanLookupField greaterThan( ooTypeN(BdbInterval), 04193 "_endTime._gmtSec", 04194 & gmtTheTime ); 04195 lookupKey.addField( greaterThan ); 04196 04197 BdbItr(BdbInterval) BdbIntervalItr; 04198 BdbIntervalItr.scan( intervalContH, lookupKey, BdbcRead ); 04199 04200 // return the topmost interval using genealogy information 04201 04202 return findTopInterval( theBdbIntervalH, 04203 BdbIntervalItr ); 04204 } 04205 04206 BdbStatus 04207 BdbDatabase::versionVector( const BdbHandle(BdbObject)& theNewObjectH, 04208 const BdbTime& theBeginVectorTime, 04209 const BdbTime& theEndVectorTime, 04210 const BdbTime& theVersionTime, 04211 d_ULong theTag ) 04212 { 04213 const char* errorString = "BdbDatabase::versionVector() -- ERROR."; 04214 04215 BdbStatus status; 04216 04217 // Build a vector of two elements only. 04218 04219 vector<BdbCondStoreTime> theVector; 04220 04221 theVector.push_back( BdbCondStoreTime( theBeginVectorTime, theNewObjectH )); 04222 theVector.push_back( BdbCondStoreTime( theEndVectorTime, 0 )); 04223 04224 std::sort(theVector.begin(),theVector.end()); 04225 04226 // Fetch an interval where the first time falls into. 04227 // 04228 // NOTE: If this is the first interval and if this interval has zero 04229 // length [-oo,-oo) then just skip this interval and proceed to 04230 // the next one. 04231 04232 BdbHandle(BdbIntervalR) theIntervalH; 04233 findInterval( theIntervalH, theBeginVectorTime, 0 ); 04234 if( BdbIsNull(theIntervalH)) { 04235 ErrMsg(error) << errorString << endl 04236 << " Failed to find a TOPMOST interval matching specified validity time." << endl 04237 << " DETECTOR -> " << subsystemTLA( ) << endl 04238 << " CONTAINER -> " << containerName( ) << endl 04239 << " TIME -> " << theBeginVectorTime << endmsg; 04240 return BdbcError; 04241 } 04242 if(( BdbTime::minusInfinity == theIntervalH->getBeginTime( )) && 04243 ( BdbTime::minusInfinity == theIntervalH->getEndTime( ))) { 04244 04245 theIntervalH->getTopNext( theIntervalH ); 04246 } 04247 04248 // Get the handle for the FIRST & LAST intervals. We will use these handles to verify 04249 // if a special processing is needed. 04250 04251 BdbHandle(BdbContObj) theIntervalContH; 04252 getIntervalContH( theIntervalContH ); 04253 04254 BdbHandle(BdbIntervalR) theFirstIntervalH; 04255 theFirstIntervalH.lookupObj( theIntervalContH, "FirstInterval", BdbcUpdate ); 04256 if( BdbIsNull(theFirstIntervalH)) { 04257 ErrMsg(error) << errorString << endl 04258 << " Failed to locate the FIRST interval." << endl 04259 << " The container may be inproperly created and/or initialized." << endl 04260 << " DETECTOR -> " << subsystemTLA( ) << endl 04261 << " CONTAINER -> " << containerName( ) << endmsg; 04262 return BdbcError; 04263 } 04264 04265 BdbHandle(BdbIntervalR) theLastIntervalH; 04266 theLastIntervalH.lookupObj( theIntervalContH, "LastInterval", BdbcUpdate ); 04267 if( BdbIsNull(theLastIntervalH)) { 04268 ErrMsg(error) << errorString << endl 04269 << " Failed to locate the LAST interval." << endl 04270 << " The container may be inproperly created and/or initialized." << endl 04271 << " DETECTOR -> " << subsystemTLA( ) << endl 04272 << " CONTAINER -> " << containerName( ) << endmsg; 04273 return BdbcError; 04274 } 04275 04276 // Translate the input vector of times into a vector of intervals. The intervals 04277 // will be continious in the validity time. 04278 // The resulting intervals will be aligned to the borders of existing intervals. 04279 // 04280 // NOTE: The value of the starting interval handle could be modifyied 04281 // by this recursive algorithm. 04282 // 04283 // NOTE: The handles of both FIRST and LAST intervals may be used by 04284 // the building algorithm. 04285 04286 vector<BdbCondStoreInterval> theIntervalVector; 04287 04288 status = buildTopStoreVector( theVector, 04289 theFirstIntervalH, 04290 theLastIntervalH, 04291 theIntervalH, 04292 theIntervalVector ); 04293 if( BdbcSuccess != status ) { 04294 return status; 04295 } 04296 04297 // Process the resulting intervals vector, by taking each interval description from 04298 // there one-by-one and applying these intrervals to the existing structure. 04299 // NOTE: This algoeithm assumes that we are processing 04300 04301 BdbHandle(BdbIntervalR) theOldIntervalH; 04302 BdbHandle(BdbObject) theObjectH; 04303 04304 BdbIntervalBase theIntervalBase; 04305 04306 BdbTime theBeginTime; 04307 BdbTime theEndTime; 04308 04309 int entries = theIntervalVector.size( ); 04310 for( int i = 0; i < entries; i++ ) { 04311 04312 theObjectH = theIntervalVector[i].getObject( ); 04313 theIntervalVector[i].getInterval( theIntervalBase ); 04314 theIntervalVector[i].getExistingInterval( theOldIntervalH ); 04315 04316 theBeginTime = theIntervalBase.getBeginTime( ); 04317 theEndTime = theIntervalBase.getEndTime( ); 04318 04319 // Check if we are trying to modify the FIRST interval. 04320 // In this case a new interval may not be aligned to the border 04321 // of the existing intervals. 04322 04323 if(( theOldIntervalH == theFirstIntervalH ) || 04324 ( theOldIntervalH == theLastIntervalH )) { 04325 04326 ErrMsg(error) << errorString << endl 04327 << " The inproper use of this method. Neither the FIRST nor the LAST" << endl 04328 << " interval can not be included into the operation." << endl 04329 << " DETECTOR -> " << subsystemTLA( ) << endl 04330 << " CONTAINER -> " << containerName( ) << endl 04331 << " BEGIN TIME -> " << theBeginVectorTime << endl 04332 << " END TIME -> " << theEndVectorTime << endmsg; 04333 return BdbcError; 04334 04335 } 04336 04337 // Now we are adding an interval somewhere in the middle of the list. This procedure 04338 // is quite routine given the prepared contents of the vector. 04339 04340 addVectorVersion( theOldIntervalH, 04341 theObjectH, 04342 theBeginTime, 04343 theEndTime, 04344 theVersionTime, 04345 theTag ); 04346 } 04347 04348 return BdbcSuccess; 04349 } 04350 04351 void 04352 BdbDatabase::version( const BdbHandle(BdbCondRevision)& theRevisionH, 04353 const BdbHandle(BdbObject)& theNewObjectH, 04354 const BdbTime& theBeginTime, 04355 d_ULong theTag ) 04356 { 04357 BdbHandle(BdbIntervalR) theIntervalH; 04358 04359 theIntervalH = 0; 04360 04361 // Get the cached container handle. 04362 04363 BdbHandle(BdbContObj) intervalContH; 04364 getIntervalContH( intervalContH ); 04365 04366 // Find the TOPMOST interval. 04367 04368 if ( BdbcSuccess != findInterval( theIntervalH, theBeginTime, theTag )) return; 04369 04370 // chose linear or branch versioning for this interval 04371 04372 if ( theBeginTime == theIntervalH->getBeginTime( )) { 04373 04374 // create one linear version 04375 04376 version1( theRevisionH, 04377 theIntervalH, 04378 theNewObjectH, 04379 theTag ); 04380 04381 } else { 04382 04383 // create two branch versions, the right interval gets the new object 04384 04385 version2R( theRevisionH, 04386 theIntervalH, 04387 theNewObjectH, 04388 theBeginTime, 04389 theTag ); 04390 } 04391 04392 BdbHandle(BdbIntervalR) lastIntervalH; 04393 lastIntervalH.lookupObj( intervalContH, "LastInterval" ); 04394 04395 // Find the topmost interval again, coz' the previous one is below and 04396 // has NULL topmost pointers. 04397 04398 findInterval( theIntervalH, theBeginTime, theTag ); 04399 theIntervalH->getTopNext( theIntervalH ); 04400 04401 while ( ! BdbIsNull(theIntervalH)) { 04402 04403 if ( theIntervalH == lastIntervalH ) { 04404 04405 updateLastInterval( theNewObjectH, 04406 lastIntervalH, 04407 theTag ); 04408 break; 04409 04410 } else { 04411 04412 // 1 : 1 linear version 04413 04414 version1( theRevisionH, 04415 theIntervalH, 04416 theNewObjectH, 04417 theTag ); 04418 04419 // Find the topmost interval again, coz' the previous one is below and 04420 // has NULL topmost pointers. 04421 // This is the only case when we continue traversing the topmost list. 04422 04423 findInterval( theIntervalH, theIntervalH->getBeginTime( ), theTag ); 04424 theIntervalH->getTopNext( theIntervalH ); 04425 } 04426 } 04427 } 04428 04429 04430 void 04431 BdbDatabase::version( const BdbHandle(BdbCondRevision)& theRevisionH, 04432 const BdbHandle(BdbObject)& theNewObjectH, 04433 const BdbTime& theBeginTime, 04434 const BdbTime& theEndTime, 04435 d_ULong theTag, 04436 const BdbTime& theVersionTime ) 04437 { 04438 BdbHandle(BdbIntervalR) theIntervalH; 04439 04440 theIntervalH = 0; 04441 04442 // Get the cached container handle. 04443 04444 BdbHandle(BdbContObj) intervalContH; 04445 getIntervalContH( intervalContH ); 04446 04447 // Find the TOPMOST interval. 04448 04449 if ( BdbcSuccess != findInterval( theIntervalH, theBeginTime, theTag )) return; 04450 04451 if ( theEndTime < theIntervalH->getEndTime( )) { 04452 04453 if ( theBeginTime == theIntervalH->getBeginTime( )) { 04454 04455 // 2L : 2 branch versions, left branch has new calibration object 04456 04457 version2L( theRevisionH, 04458 theIntervalH, 04459 theNewObjectH, 04460 theEndTime, 04461 theTag, 04462 theVersionTime ); 04463 04464 } else { 04465 04466 // 3M : 3 branch versions, middle branch has new calibration object 04467 04468 version3M( theRevisionH, 04469 theIntervalH, 04470 theNewObjectH, 04471 theBeginTime, 04472 theEndTime, 04473 theTag, 04474 theVersionTime ); 04475 } 04476 04477 } else { 04478 04479 if ( theBeginTime == theIntervalH->getBeginTime( )) { 04480 04481 // 1 : 1 linear version 04482 04483 version1( theRevisionH, 04484 theIntervalH, 04485 theNewObjectH, 04486 theTag, 04487 theVersionTime ); 04488 04489 } else { 04490 04491 // 2R : 2 branch versions, right branch has new calibration object 04492 04493 version2R( theRevisionH, 04494 theIntervalH, 04495 theNewObjectH, 04496 theBeginTime, 04497 theTag, 04498 theVersionTime ); 04499 } 04500 04501 BdbHandle(BdbIntervalR) lastIntervalH; 04502 lastIntervalH.lookupObj( intervalContH, "LastInterval" ); 04503 04504 // Find the topmost interval again, coz' the previous one is below and 04505 // has NULL topmost pointers. 04506 04507 findInterval( theIntervalH, theBeginTime, theTag ); 04508 theIntervalH->getTopNext( theIntervalH ); 04509 04510 while (( ! BdbIsNull( theIntervalH )) && ( theEndTime > theIntervalH->getBeginTime( ))) { 04511 04512 if ( theEndTime < theIntervalH->getEndTime( )) { 04513 04514 if ( theIntervalH == lastIntervalH ) { 04515 04516 cutLastInterval( theNewObjectH, 04517 lastIntervalH, 04518 theBeginTime, 04519 theEndTime, 04520 theTag ); 04521 04522 } else { 04523 04524 // 2L : 2 branch versions, left branch has new calibration object 04525 04526 version2L( theRevisionH, 04527 theIntervalH, 04528 theNewObjectH, 04529 theEndTime, 04530 theTag, 04531 theVersionTime); 04532 } 04533 break; 04534 04535 } else { 04536 04537 if ( theIntervalH == lastIntervalH ) { 04538 04539 updateLastInterval( theNewObjectH, 04540 lastIntervalH, 04541 theTag ); 04542 break; 04543 04544 } else { 04545 04546 // 1 : 1 linear version 04547 04548 version1( theRevisionH, 04549 theIntervalH, 04550 theNewObjectH, 04551 theTag, 04552 theVersionTime ); 04553 04554 if ( theEndTime == theIntervalH->getEndTime( )) { 04555 04556 break; 04557 04558 } else { 04559 04560 // Find the topmost interval again, coz' the previous one is below and 04561 // has NULL topmost pointers. 04562 // This is the only case when we continue traversing the topmost list. 04563 04564 findInterval( theIntervalH, theIntervalH->getBeginTime( ), theTag ); 04565 theIntervalH->getTopNext( theIntervalH ); 04566 } 04567 } 04568 } 04569 } 04570 } 04571 } 04572 04573 04574 void 04575 BdbDatabase::version1( const BdbHandle(BdbCondRevision)& theRevisionH, 04576 const BdbHandle(BdbIntervalR)& theIntervalH, 04577 const BdbHandle(BdbObject)& theNewObjectH, 04578 d_ULong theTag, 04579 const BdbTime& theVersionTime ) 04580 { 04581 //--------------------------------------------------------------------------- 04582 // Create one linear version of the interval object, 04583 // put the new calibration object into the versioned interval. 04584 // 04585 // theBeginTime and theEndTime are equal to the begin and end times of theIntervalH 04586 //--------------------------------------------------------------------------- 04587 04588 // create a new linear version of the interval object 04589 04590 BdbHandle(BdbIntervalR) newIntervalH; 04591 04592 theIntervalH.setVersStatus( oocLinearVers ); 04593 createRevisedTopVersion( theIntervalH, newIntervalH ); 04594 theIntervalH.setVersStatus( oocNoVers ); 04595 04596 // insert the new versioned interval into the doubly linked list 04597 04598 // get the next and previous intervals in the doubly linked list 04599 04600 BdbHandle(BdbIntervalR) theNextIntervalH; 04601 theIntervalH->getTopNext( theNextIntervalH ); 04602 04603 BdbHandle(BdbIntervalR) thePreviousIntervalH; 04604 theIntervalH->getTopPrevious( thePreviousIntervalH ); 04605 04606 if ( thePreviousIntervalH != NULL ) { 04607 thePreviousIntervalH->setTopNext( newIntervalH ); 04608 } 04609 04610 newIntervalH->setTopPrevious( thePreviousIntervalH ); 04611 newIntervalH->setTopNext( theNextIntervalH ); 04612 04613 if ( theNextIntervalH != NULL ) { 04614 theNextIntervalH->setTopPrevious( newIntervalH ); 04615 } 04616 04617 // Nullify the next and previous links of the interval which is below 04618 // the new one now, since it's not on the top anymore. 04619 04620 theIntervalH->setTopPrevious( NULL ); 04621 theIntervalH->setTopNext( NULL ); 04622 04623 // put the new calibration object into the versioned interval 04624 04625 newIntervalH->setObject( theNewObjectH ); 04626 newIntervalH->setTag( theTag ); 04627 04628 // set version time for the TOP interval 04629 04630 if ( theVersionTime == BdbTime::minusInfinity ) { 04631 newIntervalH->setVersionTime( BdbTime( )); 04632 } else { 04633 newIntervalH->setVersionTime( theVersionTime ); 04634 } 04635 04636 // connect interval to specified revision if required 04637 04638 if ( ! BdbIsNull(theRevisionH)) { 04639 newIntervalH->setRevision( theRevisionH ); 04640 } 04641 04642 // name the interval objects 04643 04644 nameVersion( theIntervalH, newIntervalH ); 04645 } 04646 04647 04648 void 04649 BdbDatabase::version2L( const BdbHandle(BdbCondRevision)& theRevisionH, 04650 const BdbHandle(BdbIntervalR)& theIntervalH, 04651 const BdbHandle(BdbObject)& theNewObjectH, 04652 const BdbTime& theEndTime, 04653 d_ULong theTag, 04654 const BdbTime& theVersionTime ) 04655 { 04656 04657 //--------------------------------------------------------------------------- 04658 // Create two branch versions, 04659 // put the new calibration object into the left interval, 04660 // copy the original calibration object into the right interval. 04661 // 04662 // theBeginTime equals the begin time of theIntervalH 04663 //--------------------------------------------------------------------------- 04664 04665 // create 2 branch versions 04666 04667 BdbHandle(BdbIntervalR) leftIntervalH; 04668 BdbHandle(BdbIntervalR) rightIntervalH; 04669 04670 theIntervalH.setVersStatus( oocBranchVers ); 04671 createRevisedTopVersion( theIntervalH, leftIntervalH ); 04672 createRevisedTopVersion( theIntervalH, rightIntervalH ); 04673 theIntervalH.setVersStatus( oocNoVers ); 04674 04675 // insert the two versioned intervals into the doubly linked list 04676 04677 // get the next and previous intervals in the doubly linked list 04678 04679 BdbHandle(BdbIntervalR) theNextIntervalH; 04680 theIntervalH->getTopNext( theNextIntervalH ); 04681 04682 BdbHandle(BdbIntervalR) thePreviousIntervalH; 04683 theIntervalH->getTopPrevious( thePreviousIntervalH ); 04684 04685 if ( thePreviousIntervalH != NULL ) { 04686 thePreviousIntervalH->setTopNext( leftIntervalH ); 04687 } 04688 leftIntervalH->setTopNext( rightIntervalH ); 04689 rightIntervalH->setTopNext( theNextIntervalH ); 04690 04691 if ( theNextIntervalH != NULL ) { 04692 theNextIntervalH->setTopPrevious( rightIntervalH ); 04693 } 04694 rightIntervalH->setTopPrevious( leftIntervalH ); 04695 leftIntervalH->setTopPrevious( thePreviousIntervalH ); 04696 04697 // Nullify the next and previous links of the interval which is below 04698 // the new one now, since it's not on the top anymore. 04699 04700 theIntervalH->setTopPrevious( NULL ); 04701 theIntervalH->setTopNext( NULL ); 04702 04703 // set end time of left interval to theEndTime 04704 04705 leftIntervalH->setEndTime( theEndTime ); 04706 04707 // set begin time of right interval to theEndTime 04708 04709 rightIntervalH->setBeginTime( theEndTime ); 04710 04711 // put the new calibration object into the left interval object 04712 04713 leftIntervalH->setObject( theNewObjectH ); 04714 leftIntervalH->setTag( theTag ); 04715 04716 // set version time for the LEFT interval only 04717 04718 if ( theVersionTime == BdbTime::minusInfinity ) { 04719 leftIntervalH->setVersionTime( BdbTime( )); 04720 } else { 04721 leftIntervalH->setVersionTime( theVersionTime ); 04722 } 04723 04724 // connect LEFT interval to specified revision if required 04725 04726 if ( ! BdbIsNull(theRevisionH)) { 04727 leftIntervalH->setRevision( theRevisionH ); 04728 } 04729 04730 // name the interval objects 04731 04732 nameVersion( theIntervalH, leftIntervalH ); 04733 nameVersion( theIntervalH, rightIntervalH ); 04734 } 04735 04736 04737 void 04738 BdbDatabase::version2R( const BdbHandle(BdbCondRevision)& theRevisionH, 04739 const BdbHandle(BdbIntervalR)& theIntervalH, 04740 const BdbHandle(BdbObject)& theNewObjectH, 04741 const BdbTime& theBeginTime, 04742 d_ULong theTag, 04743 const BdbTime& theVersionTime ) 04744 { 04745 //--------------------------------------------------------------------------- 04746 // Create two branch versions, 04747 // put the new calibration object into the right interval, 04748 // copy the original calibration object into the left interval. 04749 // 04750 // theEndTime equals the end time of theIntervalH 04751 //--------------------------------------------------------------------------- 04752 04753 // First, create 2 branch versions 04754 04755 BdbHandle(BdbIntervalR) leftIntervalH; 04756 BdbHandle(BdbIntervalR) rightIntervalH; 04757 04758 theIntervalH.setVersStatus( oocBranchVers ); 04759 createRevisedTopVersion( theIntervalH, leftIntervalH ); 04760 createRevisedTopVersion( theIntervalH, rightIntervalH ); 04761 theIntervalH.setVersStatus( oocNoVers ); 04762 04763 // insert the two versioned intervals into the doubly linked list 04764 04765 // get the next and previous intervals in the doubly linked list 04766 04767 BdbHandle(BdbIntervalR) theNextIntervalH; 04768 theIntervalH->getTopNext( theNextIntervalH ); 04769 04770 BdbHandle(BdbIntervalR) thePreviousIntervalH; 04771 theIntervalH->getTopPrevious( thePreviousIntervalH ); 04772 04773 if ( thePreviousIntervalH != NULL ) { 04774 thePreviousIntervalH->setTopNext( leftIntervalH ); 04775 } 04776 04777 leftIntervalH->setTopNext( rightIntervalH ); 04778 rightIntervalH->setTopNext( theNextIntervalH ); 04779 04780 if ( theNextIntervalH != NULL ) { 04781 theNextIntervalH->setTopPrevious( rightIntervalH ); 04782 } 04783 rightIntervalH->setTopPrevious( leftIntervalH ); 04784 leftIntervalH->setTopPrevious( thePreviousIntervalH ); 04785 04786 // Nullify the next and previous links of the interval which is below 04787 // the new one now, since it's not on the top anymore. 04788 04789 theIntervalH->setTopPrevious( NULL ); 04790 theIntervalH->setTopNext( NULL ); 04791 04792 // set end time of left interval to theBeginTime 04793 04794 leftIntervalH->setEndTime( theBeginTime ); 04795 04796 // set begin time of right interval to theBeginTime 04797 04798 rightIntervalH->setBeginTime( theBeginTime ); 04799 04800 // put the new calibration object into the right interval object 04801 04802 rightIntervalH->setObject( theNewObjectH ); 04803 rightIntervalH->setTag( theTag ); 04804 04805 // set version time for the RIGHT interval only 04806 04807 if ( theVersionTime == BdbTime::minusInfinity ) { 04808 rightIntervalH->setVersionTime( BdbTime( )); 04809 } else { 04810 rightIntervalH->setVersionTime( theVersionTime ); 04811 } 04812 04813 // connect RIGHT interval to specified revision if required 04814 04815 if ( ! BdbIsNull(theRevisionH)) { 04816 rightIntervalH->setRevision( theRevisionH ); 04817 } 04818 04819 // name the interval objects 04820 04821 nameVersion( theIntervalH, leftIntervalH ); 04822 nameVersion( theIntervalH, rightIntervalH ); 04823 } 04824 04825 void 04826 BdbDatabase::version3M( const BdbHandle(BdbCondRevision)& theRevisionH, 04827 const BdbHandle(BdbIntervalR)& theIntervalH, 04828 const BdbHandle(BdbObject)& theNewObjectH, 04829 const BdbTime& theBeginTime, 04830 const BdbTime& theEndTime, 04831 d_ULong theTag, 04832 const BdbTime& theVersionTime ) 04833 { 04834 //--------------------------------------------------------------------------- 04835 // Create three branch versions, 04836 // put the new calibration object into the middle interval, 04837 // copy the original calibration object into the left and right intervals. 04838 // 04839 // theBeginTime and theEndTime are contained within theIntervalH 04840 //--------------------------------------------------------------------------- 04841 04842 // First, create 3 branch versions of the interval 04843 04844 BdbHandle(BdbIntervalR) leftIntervalH; 04845 BdbHandle(BdbIntervalR) middleIntervalH; 04846 BdbHandle(BdbIntervalR) rightIntervalH; 04847 04848 theIntervalH.setVersStatus( oocBranchVers ); 04849 createRevisedTopVersion( theIntervalH, leftIntervalH ); 04850 createRevisedTopVersion( theIntervalH, middleIntervalH ); 04851 createRevisedTopVersion( theIntervalH, rightIntervalH ); 04852 theIntervalH.setVersStatus( oocNoVers ); 04853 04854 // insert the three versioned intervals into the doubly linked list 04855 04856 // get the next and previous intervals in the doubly linked list 04857 04858 BdbHandle(BdbIntervalR) theNextIntervalH; 04859 theIntervalH->getTopNext( theNextIntervalH ); 04860 04861 BdbHandle(BdbIntervalR) thePreviousIntervalH; 04862 theIntervalH->getTopPrevious( thePreviousIntervalH ); 04863 04864 if ( thePreviousIntervalH != NULL ) { 04865 thePreviousIntervalH->setTopNext( leftIntervalH ); 04866 } 04867 leftIntervalH->setTopNext( middleIntervalH ); 04868 middleIntervalH->setTopNext( rightIntervalH ); 04869 rightIntervalH->setTopNext(theNextIntervalH ); 04870 04871 if ( theNextIntervalH != NULL ) { 04872 theNextIntervalH->setTopPrevious( rightIntervalH ); 04873 } 04874 rightIntervalH->setTopPrevious( middleIntervalH ); 04875 middleIntervalH->setTopPrevious( leftIntervalH ); 04876 leftIntervalH->setTopPrevious( thePreviousIntervalH ); 04877 04878 // Nullify the next and previous links of the interval which is below 04879 // the new one now, since it's not on the top anymore. 04880 04881 theIntervalH->setTopPrevious( NULL ); 04882 theIntervalH->setTopNext( NULL ); 04883 04884 // set end time of left interval to theBeginTime 04885 04886 leftIntervalH->setEndTime( theBeginTime ); 04887 04888 middleIntervalH->setBeginTime( theBeginTime ); 04889 middleIntervalH->setEndTime( theEndTime ); 04890 04891 // set begin time of right interval to theEndTime 04892 04893 rightIntervalH->setBeginTime( theEndTime ); 04894 04895 // put the new calibration object into the middle interval object 04896 04897 middleIntervalH->setObject( theNewObjectH ); 04898 middleIntervalH->setTag( theTag ); 04899 04900 // set version time for the MIDDLE interval only 04901 04902 if ( theVersionTime == BdbTime::minusInfinity ) { 04903 middleIntervalH->setVersionTime( BdbTime( )); 04904 } else { 04905 middleIntervalH->setVersionTime( theVersionTime ); 04906 } 04907 04908 // connect MIDDLE interval to specified revision if required 04909 04910 if ( ! BdbIsNull(theRevisionH)) { 04911 middleIntervalH->setRevision( theRevisionH ); 04912 } 04913 04914 // name the interval objects 04915 04916 nameVersion( theIntervalH, leftIntervalH ); 04917 nameVersion( theIntervalH, middleIntervalH ); 04918 nameVersion( theIntervalH, rightIntervalH ); 04919 } 04920 04921 04922 BdbStatus 04923 BdbDatabase::updateFirstInterval( const BdbHandle(BdbObject)& theObjectH, 04924 const BdbHandle(BdbIntervalR)& firstIntervalH, 04925 const BdbTime& theEndTime, 04926 d_ULong theTag, 04927 const BdbTime& theVersionTime ) 04928 { 04929 assert( theEndTime <= firstIntervalH->getEndTime( )); 04930 04931 // Does new interval covers the whole FIRST interval? 04932 04933 if ( theEndTime == firstIntervalH->getEndTime( )) { 04934 04935 // It does. Then just replace some information and quit. 04936 04937 firstIntervalH->setObject( theObjectH ); 04938 firstIntervalH->setTag( theTag ); 04939 04940 // modify the version time 04941 04942 if( BdbTime::minusInfinity == theVersionTime ) { 04943 firstIntervalH->setVersionTime( BdbTime( )); 04944 } else { 04945 firstIntervalH->setVersionTime( theVersionTime ); 04946 } 04947 04948 return BdbcSuccess; 04949 } 04950 04951 // Get the cached container handle. 04952 04953 BdbHandle(BdbContObj) intervalContH; 04954 getIntervalContH( intervalContH ); 04955 04956 // Get the cached BASELINE revision. 04957 04958 BdbHandle(BdbCondRevision) baselineRevisionH; 04959 getBaselineRevisionH( baselineRevisionH ); 04960 04961 // Create new first interval at the very beginning. 04962 04963 BdbHandle(BdbIntervalR) newFirstIntervalH; 04964 newFirstIntervalH = new( intervalContH ) BdbIntervalR( theObjectH, 04965 BdbTime::minusInfinity, 04966 theEndTime ); 04967 newFirstIntervalH->setRevision( baselineRevisionH ); 04968 04969 // reset begin time of the current first interval 04970 04971 firstIntervalH->setBeginTime( theEndTime ); 04972 04973 // insert new first interval at the beginning of BASELINE doubly linked list 04974 04975 newFirstIntervalH->setBaselineNext( firstIntervalH ); 04976 firstIntervalH->setBaselinePrevious( newFirstIntervalH ); 04977 04978 // insert new firstst interval at the beginning of TOP doubly linked list 04979 04980 newFirstIntervalH->setTopNext( firstIntervalH ); 04981 firstIntervalH->setTopPrevious( newFirstIntervalH ); 04982 04983 // modify the version time 04984 04985 if( BdbTime::minusInfinity == theVersionTime ) { 04986 newFirstIntervalH->setVersionTime( BdbTime( )); 04987 } else { 04988 newFirstIntervalH->setVersionTime( theVersionTime ); 04989 } 04990 04991 // rename the first interval 04992 04993 firstIntervalH.unnameObj( intervalContH ); 04994 newFirstIntervalH.nameObj( intervalContH, "FirstInterval" ); 04995 04996 return BdbcSuccess; 04997 } 04998 04999 BdbStatus 05000 BdbDatabase::cutFirstInterval( const BdbHandle(BdbObject)& theObjectH, 05001 const BdbHandle(BdbIntervalR)& firstIntervalH, 05002 const BdbTime& theBeginTime, 05003 const BdbTime& theEndTime, 05004 d_ULong theTag, 05005 const BdbTime& theVersionTime ) 05006 { 05007 assert( theBeginTime < theEndTime ); 05008 assert( theEndTime <= firstIntervalH->getEndTime( )); 05009 05010 // If the new interval starts from the minus infinity 05011 // then we go to update the first interval. 05012 05013 if ( theBeginTime == BdbTime::minusInfinity ) { 05014 05015 return updateFirstInterval( theObjectH, 05016 firstIntervalH, 05017 theEndTime, 05018 theTag, 05019 theVersionTime ); 05020 } 05021 05022 // Get the cached container handle. 05023 05024 BdbHandle(BdbContObj) intervalContH; 05025 getIntervalContH( intervalContH ); 05026 05027 // Get the cached BASELINE revision. 05028 05029 BdbHandle(BdbCondRevision) baselineRevisionH; 05030 getBaselineRevisionH( baselineRevisionH ); 05031 05032 // Create new first interval at the very beginning. 05033 // This interval will derive everything from its predesessor. 05034 05035 BdbHandle(BdbIntervalR) newFirstIntervalH; 05036 newFirstIntervalH = new( intervalContH ) BdbIntervalR( firstIntervalH->getObject( ), 05037 BdbTime::minusInfinity, 05038 theBeginTime ); 05039 05040 newFirstIntervalH->setRevision( baselineRevisionH ); 05041 newFirstIntervalH->setVersionTime( firstIntervalH->getVersionTime( )); 05042 newFirstIntervalH->setTag( firstIntervalH->getTag( )); 05043 05044 // reset begin time of the current first interval 05045 05046 firstIntervalH->setBeginTime( theBeginTime ); 05047 05048 // insert new first interval at the beginning of BASELINE doubly linked list 05049 05050 newFirstIntervalH->setBaselineNext( firstIntervalH ); 05051 firstIntervalH->setBaselinePrevious( newFirstIntervalH ); 05052 05053 // insert new firstst interval at the beginning of TOP doubly linked list 05054 05055 newFirstIntervalH->setTopNext( firstIntervalH ); 05056 firstIntervalH->setTopPrevious( newFirstIntervalH ); 05057 05058 // rename the first interval 05059 05060 firstIntervalH.unnameObj( intervalContH ); 05061 newFirstIntervalH.nameObj( intervalContH, "FirstInterval" ); 05062 05063 // version the old/current first interval as a regular interval 05064 // in the middle of the list. 05065 05066 version( NULL, 05067 theObjectH, 05068 theBeginTime, 05069 theEndTime, 05070 theTag, 05071 theVersionTime ); 05072 05073 return BdbcSuccess; 05074 } 05075 05076 BdbStatus 05077 BdbDatabase::updateLastInterval( const BdbHandle(BdbObject)& theObjectH, 05078 const BdbHandle(BdbIntervalR)& lastIntervalH, 05079 d_ULong theTag, 05080 const BdbTime& theVersionTime ) 05081 { 05082 // replace object reference in the last interval 05083 05084 lastIntervalH->setObject( theObjectH ); 05085 lastIntervalH->setTag( theTag ); 05086 05087 // modify the version time 05088 05089 if( BdbTime::minusInfinity == theVersionTime ) { 05090 lastIntervalH->setVersionTime( BdbTime( )); 05091 } else { 05092 lastIntervalH->setVersionTime( theVersionTime ); 05093 } 05094 05095 return BdbcSuccess; 05096 } 05097 05098 BdbStatus 05099 BdbDatabase::cutLastInterval( const BdbHandle(BdbObject)& theObjectH, 05100 const BdbHandle(BdbIntervalR)& lastIntervalH, 05101 const BdbTime& theBeginTime, 05102 const BdbTime& theEndTime, 05103 d_ULong theTag, 05104 const BdbTime& theVersionTime ) 05105 { 05106 assert ( theEndTime > theBeginTime ); 05107 05108 if ( theEndTime == BdbTime::plusInfinity ) { 05109 05110 return updateLastInterval( theObjectH, 05111 lastIntervalH, 05112 theTag, 05113 theVersionTime ); 05114 } else { 05115 05116 // Get the cached container handle. 05117 05118 BdbHandle(BdbContObj) intervalContH; 05119 getIntervalContH( intervalContH ); 05120 05121 // Get the cached BASELINE revision. 05122 05123 BdbHandle(BdbCondRevision) baselineRevisionH; 05124 getBaselineRevisionH( baselineRevisionH ); 05125 05126 // create a new last interval in a BASELINE revision 05127 05128 BdbHandle(BdbIntervalR) newLastIntervalH; 05129 newLastIntervalH = new( intervalContH ) BdbIntervalR( NULL, 05130 theEndTime, 05131 BdbTime::plusInfinity ); 05132 05133 newLastIntervalH->setRevision( baselineRevisionH ); 05134 05135 // reset end time of the current last interval 05136 05137 lastIntervalH->setEndTime( theEndTime ); 05138 05139 // append new last interval to end of BASELINE doubly linked list 05140 05141 lastIntervalH->setBaselineNext( newLastIntervalH ); 05142 newLastIntervalH->setBaselinePrevious( lastIntervalH ); 05143 05144 // append new last interval to end of TOP doubly linked list 05145 05146 lastIntervalH->setTopNext( newLastIntervalH ); 05147 newLastIntervalH->setTopPrevious( lastIntervalH ); 05148 05149 // rename the last interval 05150 05151 lastIntervalH.unnameObj( intervalContH ); 05152 newLastIntervalH.nameObj( intervalContH, "LastInterval" ); 05153 05154 // And finally - create a linear version of the old (shortened) last interval 05155 // We do it here since the version should be created within an established 05156 // structure of horizontal links. 05157 05158 version1( NULL, lastIntervalH, theObjectH, theTag, theVersionTime ); 05159 } 05160 05161 return BdbcSuccess; 05162 } 05163 05164 BdbStatus 05165 BdbDatabase::truncateLastInterval( const BdbHandle(BdbObject)& theObjectH, 05166 const BdbHandle(BdbIntervalR)& lastIntervalH, 05167 const BdbTime& theInsertTime, 05168 const BdbTime& theTruncateTime, 05169 d_ULong theTag ) 05170 { 05171 BdbStatus status = BdbcError; 05172 05173 // the only difference of this algorithm from the ::cutLastInterval() and ::appendIntervalR() 05174 // is that this one sets a BdbObject pointer of the new LastInterval to the one 05175 // specified by current parameter. 05176 05177 assert ( theTruncateTime > theInsertTime ); 05178 assert ( theTruncateTime != BdbTime::plusInfinity ); 05179 05180 // call an insertion method depending on whether the insert time 05181 // starts with the beginning of existing last interval. 05182 05183 if ( theInsertTime == lastIntervalH->getBeginTime( )) { 05184 05185 status = cutLastInterval( theObjectH, 05186 lastIntervalH, 05187 theInsertTime, 05188 theTruncateTime, 05189 theTag ); 05190 } else { 05191 05192 status = appendIntervalR( theObjectH, 05193 lastIntervalH, 05194 theInsertTime, 05195 theTruncateTime, 05196 theTag ); 05197 } 05198 if ( BdbcSuccess != status ) { 05199 return status; 05200 } 05201 05202 // Get the cached container handle. 05203 05204 BdbHandle(BdbContObj) intervalContH; 05205 getIntervalContH( intervalContH ); 05206 05207 // locate new last interval and substitute a BdbObject pointer to 05208 // the new object. 05209 05210 BdbHandle(BdbIntervalR) newLastIntervalH; 05211 newLastIntervalH.lookupObj( intervalContH, "LastInterval" ); 05212 05213 newLastIntervalH->setObject( theObjectH ); 05214 05215 return BdbcSuccess; 05216 } 05217 05218 BdbStatus 05219 BdbDatabase::appendIntervalR( const BdbHandle(BdbObject)& theObjectH, 05220 const BdbHandle(BdbIntervalR)& lastIntervalH, 05221 const BdbTime& theBeginTime, 05222 d_ULong theTag, 05223 const BdbTime& theVersionTime ) 05224 { 05225 // Implement the "revision"-aware algorithm. 05226 // In particular this algorithm assumes no versions 05227 // for the last interval. 05228 05229 assert( theBeginTime > lastIntervalH->getBeginTime( )) ; 05230 05231 // Get the cached container handle. 05232 05233 BdbHandle(BdbContObj) intervalContH; 05234 getIntervalContH( intervalContH ); 05235 05236 // Get the cached BASELINE revision. 05237 05238 BdbHandle(BdbCondRevision) baselineRevisionH; 05239 getBaselineRevisionH( baselineRevisionH ); 05240 05241 // append interval to end of list 05242 05243 // reset end time of the current last interval. 05244 05245 lastIntervalH->setEndTime( theBeginTime ); 05246 05247 // create the new LAST interval 05248 05249 BdbHandle(BdbIntervalR) newLastIntervalH; 05250 newLastIntervalH = new( intervalContH ) BdbIntervalR( theObjectH, 05251 theBeginTime, 05252 BdbTime::plusInfinity, 05253 theTag ); 05254 newLastIntervalH->setRevision( baselineRevisionH ); 05255 05256 // Append new interval to end of BASELINE doubly linked list. 05257 05258 lastIntervalH->setBaselineNext( newLastIntervalH ); 05259 newLastIntervalH->setBaselinePrevious( lastIntervalH ); 05260 05261 // Append new interval by end of TOP doubly linked list. 05262 05263 lastIntervalH->set_next( newLastIntervalH ); 05264 newLastIntervalH->set_previous( lastIntervalH ); 05265 05266 // Explicitly set the version time if required. 05267 05268 if( BdbTime::minusInfinity != theVersionTime ) { 05269 newLastIntervalH->setVersionTime( theVersionTime ); 05270 } 05271 05272 // rename the last interval 05273 05274 lastIntervalH.unnameObj( intervalContH ); 05275 newLastIntervalH.nameObj( intervalContH, "LastInterval" ); 05276 05277 return BdbcSuccess; 05278 } 05279 05280 05281 BdbStatus 05282 BdbDatabase::appendIntervalR( const BdbHandle(BdbObject)& theObjectH, 05283 const BdbHandle(BdbIntervalR)& lastIntervalH, 05284 const BdbTime& theBeginTime, 05285 const BdbTime& theEndTime, 05286 d_ULong theTag, 05287 const BdbTime& theVersionTime ) 05288 { 05289 // Implement the "revision"-aware algorithm. 05290 // In particular this algorithm assumes no versions 05291 // for the last interval. 05292 05293 assert( theBeginTime > lastIntervalH->getBeginTime( )) ; 05294 05295 // append interval to end of list 05296 05297 if ( theEndTime == BdbTime::plusInfinity ) { 05298 return appendIntervalR( theObjectH, lastIntervalH, theBeginTime, theTag, theVersionTime ); 05299 } else { 05300 05301 // Get the cached container handle. 05302 05303 BdbHandle(BdbContObj) intervalContH; 05304 getIntervalContH( intervalContH ); 05305 05306 // Get the cached BASELINE revision. 05307 05308 BdbHandle(BdbCondRevision) baselineRevisionH; 05309 getBaselineRevisionH( baselineRevisionH ); 05310 05311 // reset end time of the current last interval 05312 05313 lastIntervalH->setEndTime( theBeginTime ); 05314 05315 // Create the new interval with the same time limits as a new interval, 05316 // but pointing to the last interval's object. 05317 // Later we will version this interval with a new object. 05318 05319 BdbHandle( BdbIntervalR ) newIntervalH; 05320 newIntervalH = new( intervalContH ) BdbIntervalR( lastIntervalH->getObject( ), 05321 theBeginTime, 05322 theEndTime, 05323 theTag ); 05324 newIntervalH->setVersionTime( lastIntervalH->getVersionTime( )); 05325 newIntervalH->setRevision( baselineRevisionH ); 05326 05327 // create the new last interval 05328 05329 BdbHandle(BdbIntervalR) newLastIntervalH; 05330 newLastIntervalH = new( intervalContH ) BdbIntervalR( 0, 05331 theEndTime, 05332 BdbTime::plusInfinity ); 05333 newLastIntervalH->setRevision( baselineRevisionH ); 05334 05335 // insert new interval and new last interval into BASELINE doubly linked list 05336 05337 lastIntervalH->setBaselineNext( newIntervalH ); 05338 newIntervalH->setBaselinePrevious( lastIntervalH ); 05339 newIntervalH->setBaselineNext( newLastIntervalH ); 05340 newLastIntervalH->setBaselinePrevious( newIntervalH ); 05341 05342 // insert new interval and new last interval into TOP doubly linked list 05343 05344 lastIntervalH->setTopNext( newIntervalH ); 05345 newIntervalH->setTopPrevious( lastIntervalH ); 05346 newIntervalH->setTopNext( newLastIntervalH ); 05347 newLastIntervalH->setTopPrevious( newIntervalH ); 05348 05349 // rename the last interval 05350 05351 lastIntervalH.unnameObj( intervalContH ); 05352 newLastIntervalH.nameObj( intervalContH, "LastInterval" ); 05353 05354 // And finally - create a linear version of the new interval 05355 // created in between a previous interval and a new last interval. 05356 // We do it here since the version should be created within an established 05357 // structure. 05358 05359 version1( 0, newIntervalH, theObjectH, theTag, theVersionTime ); 05360 } 05361 05362 return BdbcSuccess; 05363 } 05364 05365 05366 void 05367 BdbDatabase::createVersion( const BdbHandle(BdbIntervalR)& theOldIntervalH, 05368 BdbHandle(BdbIntervalR)& theNewIntervalH ) 05369 { 05370 05371 // Replace the following code: 05372 // 05373 // theOldIntervalH.close( ); 05374 // theNewIntervalH = theOldIntervalH; 05375 // theNewIntervalH.update( ); 05376 // theNewIntervalH.setVersStatus( oocNoVers ); 05377 // 05378 // With more efficient functional equivalent. 05379 // 05380 // NOTE: a) The newly created interval would automatically 05381 // get "oocNoVers" status. 05382 // b) The versioning status of the old interval must be maintained 05383 // by the callers code, since this is out of scope of this 05384 // method's code. 05385 05386 theNewIntervalH = new( theOldIntervalH ) BdbIntervalR( theOldIntervalH->getObject( ), 05387 theOldIntervalH->getBeginTime( ), 05388 theOldIntervalH->getEndTime( ), 05389 theOldIntervalH->getTag( )); 05390 theOldIntervalH->add_nextVers( theNewIntervalH ); 05391 } 05392 05393 05394 void 05395 BdbDatabase::createRevisedTopVersion( const BdbHandle(BdbIntervalR)& theOldIntervalH, 05396 BdbHandle(BdbIntervalR)& theNewIntervalH ) 05397 { 05398 05399 // Create new version as usual. 05400 05401 createVersion( theOldIntervalH, theNewIntervalH ); 05402 05403 // Connect interval to a revision (which may be empty of course). 05404 05405 theNewIntervalH->setRevision( reviseAfterStoreRevisionH( )); 05406 } 05407 05408 05409 void 05410 BdbDatabase::nameVersion( const BdbHandle(BdbInterval)& theOriginalIntervalH, 05411 const BdbHandle(BdbInterval)& theIntervalH ) 05412 { 05413 BdbHandle(BdbIntervalGene) theGeneH; 05414 string theOriginalIntervalName; 05415 05416 // Get the Genealogy object and a previous version name. 05417 // Name the original (BASELINE) interval if required. 05418 05419 if ( theOriginalIntervalH->exist_geneObj( )) { 05420 05421 // Reuse already existing Genealogy object. 05422 05423 theGeneH = (const BdbHandle(BdbIntervalGene)&) theOriginalIntervalH->geneObj( ); 05424 theOriginalIntervalName = string( theGeneH->getVersionName( )); 05425 05426 } else { 05427 05428 // Get the cached container handle. We will use it as a clustering hint 05429 // for the newely created Genealogy object. 05430 05431 BdbHandle(BdbContObj) theIntervalContH; 05432 getIntervalContH( theIntervalContH ); 05433 05434 // Create a genealogy object. 05435 05436 theGeneH = new( theIntervalContH ) BdbIntervalGene( ); 05437 05438 theGeneH->set_defaultVers( theOriginalIntervalH ); 05439 theGeneH->add_allVers( theOriginalIntervalH ); 05440 05441 theOriginalIntervalName = string( theGeneH->getVersionName( )); 05442 theOriginalIntervalH.nameObj( theGeneH, theOriginalIntervalName.c_str() ); 05443 } 05444 05445 // Add new interval to the genealogy. 05446 05447 theGeneH->add_allVers( theIntervalH ); 05448 05449 // Increment the version number and name the new version. 05450 05451 char* theNewIntervalName = upDateVersionName( theOriginalIntervalName.c_str() ); 05452 05453 theIntervalH.nameObj( theGeneH, theNewIntervalName ); 05454 theGeneH->setVersionName( theNewIntervalName ); 05455 05456 delete [] theNewIntervalName; 05457 } 05458 05459 char* 05460 BdbDatabase::upDateVersionName( const char* oldName ) const 05461 { 05462 05463 //----------------------------------------------------------------------------- 05464 // 05465 // This function takes the current version name and returns 05466 // the name for the next version. 05467 // 05468 // Input: char* oldName : the name of the present version 05469 // 05470 // Output: char* newName : the name of the next version 05471 // 05472 // The version name is assumed to have the form sd 05473 // where s denotes a string of alphabetic characters 05474 // and d denotes a string of numerical characters. 05475 // 05476 // Example: 05477 // if char* oldName = "V1" 05478 // then char* newName = "V2" 05479 // 05480 //----------------------------------------------------------------------------- 05481 05482 assert( NULL != oldName ); 05483 05484 char* theName = new char[ strlen(oldName) + 1 ]; 05485 strcpy( theName, oldName ); 05486 05487 // Decompose theName as theName = prefixName + theDigits 05488 05489 // Get theDigits 05490 05491 char* str = strpbrk( theName, "0123456789" ); 05492 if ( str == (char*) 0 ) { 05493 05494 ErrMsg(warning) << "BdbDatabase::upDateVersionName() -- warning." << endl 05495 << " Version name has no digits, use " << Zero << " as default digits" << endmsg; 05496 05497 str = new char[ strlen( Zero ) + 1 ]; 05498 strcpy( str, Zero ); 05499 } 05500 05501 char* theDigits = new char[ strlen(str) + 1 ]; 05502 strcpy( theDigits, str ); 05503 05504 // Get prefixName 05505 05506 str = strtok( theName, "0123456789" ); 05507 char* prefixName = new char[ strlen(str) + 1 ]; 05508 strcpy( prefixName, str ); 05509 05510 // Convert char digits to int digits 05511 05512 int intDigits = atoi( theDigits ); 05513 intDigits++; 05514 05515 // Convert int digits to char digits 05516 05517 char string[16]; 05518 sprintf( string, "%i", intDigits ); 05519 05520 char* newDigits = new char[ strlen( string ) + 1 ]; 05521 strcpy( newDigits, string ); 05522 05523 // Put the pieces back together 05524 05525 char* newName = new char[ strlen( prefixName ) + strlen( newDigits ) + 1 ]; 05526 strcpy( newName, prefixName ); 05527 strcat( newName, newDigits ); 05528 05529 delete [] theName; 05530 delete [] theDigits; 05531 delete [] prefixName; 05532 delete [] newDigits; 05533 05534 return newName; 05535 } 05536 05537 int 05538 BdbDatabase::verticalCompare( const BdbHandle(BdbInterval)& theLeftIntervalH, 05539 const BdbHandle(BdbInterval)& theRightIntervalH ) 05540 { 05541 BdbHandle(BdbInterval) thePrevIntervalH; 05542 BdbHandle(BdbInterval) thePrevPrevIntervalH; 05543 05544 assert( ! BdbIsNull(theLeftIntervalH)); 05545 assert( ! BdbIsNull(theRightIntervalH)); 05546 05547 // 0: The same interval. 05548 05549 if ( theLeftIntervalH == theRightIntervalH ) { 05550 return 0; 05551 } 05552 05553 // 0: Intervals from different trees. 05554 05555 if ( ! ( theLeftIntervalH->inInterval( *theRightIntervalH ) || 05556 theRightIntervalH->inInterval( *theLeftIntervalH ))) { 05557 return 0; 05558 } 05559 05560 // -1: The left interval is lower (closer to a baseline one) 05561 // then the right one. 05562 05563 theRightIntervalH->prevVers( thePrevIntervalH ); 05564 while( ! BdbIsNull(thePrevIntervalH)) { 05565 05566 if ( thePrevIntervalH == theLeftIntervalH ) { 05567 return -1; 05568 } 05569 05570 thePrevIntervalH->prevVers( thePrevPrevIntervalH ); 05571 thePrevIntervalH = thePrevPrevIntervalH; 05572 } 05573 05574 // 1: The left interval is upper than the right one. 05575 05576 theLeftIntervalH->prevVers( thePrevIntervalH ); 05577 while( ! BdbIsNull(thePrevIntervalH)) { 05578 05579 if ( thePrevIntervalH == theRightIntervalH ) { 05580 return 1; 05581 } 05582 05583 thePrevIntervalH->prevVers( thePrevPrevIntervalH ); 05584 thePrevIntervalH = thePrevPrevIntervalH; 05585 } 05586 05587 // 0: The database structure has been corrupted or there is an attempt 05588 // to compare intervals from different containers. 05589 05590 return 0; 05591 } 05592 05593 BdbStatus 05594 BdbDatabase::verifyIntervals( vector<BdbHandle(BdbInterval)>& theList, 05595 const char* theContainerName, 05596 d_ULong theRevisionId ) 05597 { 05598 const char* errorString = "BdbDatabase::verifyIntervals() -- ERROR."; 05599 05600 BdbStatus status; 05601 05602 // Perform the following action in an exception-like loop. 05603 05604 bool theOuterLoopFailed = true; 05605 05606 while( true ) { 05607 05608 // Find specified container. Reload cache if nessesary. 05609 05610 BdbHandle(BdbContObj) intervalContH; 05611 05612 status = findIntervalCont( intervalContH, theContainerName ); 05613 if (( BdbcSuccess != status ) || BdbIsNull(intervalContH)) { 05614 ErrMsg(error) << errorString << endl 05615 << " Failed to locate specified interval container." << endmsg; 05616 break; 05617 } 05618 05619 // Load the FIRST and LAST intervals. 05620 05621 BdbHandle(BdbInterval) theFirstIntervalH; 05622 05623 status = firstInterval( theFirstIntervalH, theContainerName ); 05624 if ( BdbcSuccess != status ) return status; 05625 05626 BdbHandle(BdbInterval) theLastIntervalH; 05627 05628 status = lastInterval( theLastIntervalH, theContainerName ); 05629 if ( BdbcSuccess != status ) return status; 05630 05631 // Perform a quality checking of the intervals in the list. 05632 // 05633 // 1. Check if all intervals in the list belong to specified container. 05634 // 2. Check for the class of elements (we expect BdbIntervalR). 05635 // 3. Check that elements do not correspond neither FIRST nor LAST intervals. 05636 // 4. Check if there is not "revision duplicates" on the vertical stack of intervals 05637 // 5. Check if there is not "revision duplicates" between in supplied intervals 05638 // list by checking "previous-next" dependancies between them. 05639 05640 bool theInnerLoopFailed = false; 05641 05642 for( int i = 0; i < theList.size( ); i++ ) { 05643 05644 // - - - - 05645 // Test: 1 05646 // - - - - 05647 05648 if( intervalContH != theList[i].containedIn( )) { 05649 ErrMsg(error) << errorString << endl 05650 << " A wrong interval handle is found in the list." << endl 05651 << " The interval does not belong to the container: " << theContainerName << endl 05652 << " Element of theList[" << i << "] = " << getOID( theList[i] ) << endmsg; 05653 theInnerLoopFailed = true; 05654 break; 05655 } 05656 05657 // - - - - 05658 // Test: 2 05659 // - - - - 05660 05661 if( ooTypeN( BdbIntervalR ) != theList[i].typeN( )) { 05662 ErrMsg(error) << errorString << endl 05663 << " A wrong interval handle is found in the list." << endl 05664 << " The interval has unexpected class \"" << theList[i].typeName( ) << "\"" << endl 05665 << " instead of \"BdbIntervalR\"" << endl 05666 << " Element of theList[" << i << "] = " << getOID( theList[i] ) << endmsg; 05667 theInnerLoopFailed = true; 05668 break; 05669 } 05670 05671 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 05672 // Test: 3: check that elements do not correspond neither FIRST nor LAST intervals 05673 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 05674 05675 if( theFirstIntervalH == theList[i]) { 05676 ErrMsg(error) << errorString << endl 05677 << " The FIRST interval is found in the list." << endl 05678 << " Operation is not allowed for this interval." << endl 05679 << " Element of theList[" << i << "] = " << getOID( theList[i] ) << endmsg; 05680 theInnerLoopFailed = true; 05681 break; 05682 } 05683 05684 if( theLastIntervalH == theList[i]) { 05685 ErrMsg(error) << errorString << endl 05686 << " The LAST interval is found in the list." << endl 05687 << " Operation is not allowed for this interval." << endl 05688 << " Element of theList[" << i << "] = " << getOID( theList[i] ) << endmsg; 05689 theInnerLoopFailed = true; 05690 break; 05691 } 05692 05693 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 05694 // Test: 4: locate revision duplicate(s) on the same vertical stack 05695 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 05696 05697 vector<BdbHandle(BdbIntervalR)> theIntervalVector; 05698 05699 status = getRevisedIntervalsInSubTree( theIntervalVector, 05700 (const BdbHandle(BdbIntervalR)&) theList[i], 05701 theRevisionId ); 05702 if( BdbcSuccess != status ) { 05703 return status; 05704 } 05705 05706 if( theIntervalVector.size( )) { 05707 ErrMsg(error) << errorString << endl 05708 << " An interval(s) from the same revision were found in the vertical" << endl 05709 << " hierarchy of versions. Including another interval into the same" << endl 05710 << " revision will create ambiguity." << endl 05711 << " Element of theList[" << i << "] = " << getOID( theList[i] ) << endmsg; 05712 theInnerLoopFailed = true; 05713 break; 05714 } 05715 05716 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 05717 // 5. Check if there is not "revision duplicates" between in supplied intervals 05718 // list by checking "previous-next" dependancies between them. 05719 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 05720 05721 vector<BdbHandle(BdbInterval)> theBoundIntervalsVector; 05722 05723 status = getBoundIntervalsInSubTree( theBoundIntervalsVector, 05724 theList, 05725 theList[i] ); 05726 if( BdbcSuccess != status ) { 05727 return status; 05728 } 05729 05730 if( theBoundIntervalsVector.size( )) { 05731 ErrMsg(error) << errorString << endl 05732 << " The interval(s) from the same vertical hierarchy of versions" << endl 05733 << " willing to go into the same revision were found in the input list." << endl 05734 << " Including these intervals into the same revision will create ambiguity." << endl 05735 << " Element of theList[" << i << "] = " << getOID( theList[i] ) << endmsg; 05736 theInnerLoopFailed = true; 05737 break; 05738 } 05739 05740 } 05741 05742 theOuterLoopFailed = theInnerLoopFailed; 05743 break; 05744 } 05745 if ( theOuterLoopFailed ) { 05746 05747 ErrMsg(error) << " DETECTOR -> " << subsystemTLA( ) << endl 05748 << " CONTAINER -> " << theContainerName << endmsg; 05749 return BdbcError; 05750 } 05751 05752 return BdbcSuccess; 05753 } 05754 05755 void 05756 BdbDatabase::includeIntoRevision( vector<BdbHandle(BdbInterval)>& theList, 05757 const BdbHandle(BdbCondRevision)& theRevisionH ) 05758 { 05759 05760 // Go through the list and set a proper revision for the elements. 05761 // This algorithm has two different inplementations depending on wheather 05762 // an interval is or is not a member of a revision. 05763 // 05764 // 1. If it's not - just include it into a revision. 05765 // 2. If it's a member - then put a version of this interval 05766 // on a top of the stack. This is based on using of an extended 05767 // versioning algorithm which accepts a revision handle and 05768 // specific versioning time. 05769 // 05770 // NOTE: If the interval is already a member of specified 05771 // revision -- then nothing to do. 05772 // 05773 // This algorithm will also ignore any duplicates in the input list. 05774 // A duplicate is an interval which is met twice or more times in the list. 05775 05776 05777 int entries = theList.size( ); 05778 05779 for( int i = 0; i < entries; i++ ) { 05780 05781 BdbHandle(BdbIntervalR) theIntervalH; 05782 theIntervalH = (BdbHandle(BdbIntervalR)&) theList[i]; 05783 05784 // Ignore duplicates 05785 05786 bool aDuplicateFound = false; 05787 05788 for( int j = 0; j < i; j++ ) { 05789 if( theList[j] == theList[i] ) { 05790 aDuplicateFound = true; 05791 break; 05792 } 05793 } 05794 if( aDuplicateFound ) { 05795 continue; 05796 } 05797 05798 // Go further... 05799 05800 BdbHandle(BdbCondRevision) theOldRevisionH; 05801 theIntervalH->getRevision( theOldRevisionH ); 05802 05803 if( BdbIsNull( theOldRevisionH )) { 05804 theIntervalH->setRevision( theRevisionH ); 05805 } else { 05806 05807 if( theRevisionH != theOldRevisionH ) { 05808 05809 version( theRevisionH, 05810 theIntervalH->getObject( ), 05811 theIntervalH->getBeginTime( ), 05812 theIntervalH->getEndTime( ), 05813 theIntervalH->getTag( ), 05814 theIntervalH->getVersionTime( )); 05815 } 05816 } 05817 } 05818 05819 return; 05820 } 05821 05822 BdbStatus 05823 BdbDatabase::getRevisionStack( vector<d_ULong>& theRevisionStack, 05824 d_ULong theRevisionId ) 05825 { 05826 // Reset a stack 05827 05828 theRevisionStack.clear( ); 05829 05830 // Get a cached handle for REgistry. 05831 05832 BdbHandle(BdbCondRegistry) registryH; 05833 getRegistryH( registryH ); 05834 05835 // Locate a persistent record for specified revision 05836 05837 BdbItr(BdbCondRevision) theRevisionItr; 05838 BdbHandle(BdbCondRevision) theRevisionH; 05839 05840 registryH->setRevisionItr( theRevisionItr ); 05841 05842 bool revisionIsFound = false; 05843 05844 while ( theRevisionItr.next( )) { 05845 if ( theRevisionId == theRevisionItr->id( )) { 05846 05847 theRevisionH = theRevisionItr; 05848 revisionIsFound = true; 05849 05850 break; 05851 } 05852 } 05853 if ( ! revisionIsFound ) { 05854 05855 ErrMsg(error) << "BdbDatabase::getRevisionStack() -- error." << endl 05856 << " Specified revision was not found." << endmsg; 05857 05858 return BdbcError; 05859 } 05860 05861 // Put specified revision itself onto the top of the stack 05862 05863 theRevisionStack.push_back( theRevisionId ); 05864 05865 // Traverse through "base" revisions path of this particular 05866 // revision and all their base revisions and record the corresponding 05867 // revisions id-s into supplied stack object. 05868 05869 BdbHandle(BdbCondRevision) theBaseRevisionH; 05870 05871 theRevisionH->getBaseRevision( theBaseRevisionH ); 05872 05873 while ( ! BdbIsNull( theBaseRevisionH )) { 05874 05875 theRevisionH = theBaseRevisionH; 05876 05877 theRevisionStack.push_back( theRevisionH->id( )); 05878 05879 theRevisionH->getBaseRevision( theBaseRevisionH ); 05880 } 05881 05882 return BdbcSuccess; 05883 } 05884 05885 // ----------------------------------------------------------------------- 05886 // *********************************************************************** 05887 // 05888 // ::getRevisedIntervalsInSubTree() 05889 // 05890 // DESCRIPTION: 05891 // 05892 // Locate all possible intervals belonging to specified revision 05893 // in a versioning sub-tree. 05894 // 05895 // The sub-tree includes specified interval, a list of previous 05896 // intervals, and a sub-tree of the next intervals. 05897 // 05898 // PARAMETERS: 05899 // 05900 // theIntervalVector a list of intervals matching specified 05901 // revision is returned here. Has 0 entries 05902 // if nothing were found. 05903 // The order of entries in the list is not 05904 // defined. 05905 // 05906 // theIntervalH an interval which specifies a start point 05907 // in the sub-tree. 05908 // 05909 // theRevisionId a revision ID to look for. 05910 // 05911 // RETURN: 05912 // 05913 // BdbcSuccess means success, even if nothing were found. 05914 // 05915 // BdbcError means any error. The vector will contain 05916 // entries which were successfully found before 05917 // an error had occured. 05918 // 05919 // *********************************************************************** 05920 // ----------------------------------------------------------------------- 05921 05922 BdbStatus 05923 BdbDatabase::getRevisedIntervalsInSubTree( vector<BdbHandle(BdbIntervalR)>& theIntervalVector, 05924 const BdbHandle(BdbIntervalR)& theIntervalH, 05925 d_ULong theRevisionId ) 05926 { 05927 BdbStatus status = BdbcError; 05928 05929 // Reset a stack 05930 05931 theIntervalVector.clear( ); 05932 05933 // Traverse a list of previous intervals. 05934 05935 BdbHandle(BdbIntervalR) thePrevPrevIntervalH; 05936 BdbHandle(BdbIntervalR) thePrevIntervalH; 05937 BdbHandle(BdbCondRevision) theRevisionH; 05938 05939 theIntervalH->prevVers( thePrevIntervalH ); 05940 while( ! BdbIsNull(thePrevIntervalH)) { 05941 05942 // Check revision ID of the next interval. 05943 05944 thePrevIntervalH->getRevision( theRevisionH ); 05945 05946 if( ! BdbIsNull(theRevisionH)) { 05947 if( theRevisionId == theRevisionH->id( )) { 05948 theIntervalVector.push_back( thePrevIntervalH ); 05949 } 05950 } 05951 05952 // Go deeper to the next previous version. 05953 05954 thePrevIntervalH->prevVers( thePrevPrevIntervalH ); 05955 thePrevIntervalH = thePrevPrevIntervalH; 05956 } 05957 05958 // Traverse a tree of next intervals. 05959 // This is recursive algorithm. 05960 05961 status = getNextRevisedIntervals( theIntervalVector, 05962 theIntervalH, 05963 theRevisionId ); 05964 if( BdbcSuccess != status ) { 05965 return status; 05966 } 05967 05968 return BdbcSuccess; 05969 } 05970 05971 // ----------------------------------------------------------------------- 05972 // *********************************************************************** 05973 // 05974 // ::getBoundIntervalsInSubTree() 05975 // 05976 // DESCRIPTION: 05977 // 05978 // Check the if specified interval has any "bound" intervals 05979 // in a specified list of intervals. 05980 // 05981 // "Bound intervals" are those intervals that are in the same 05982 // vertical versioning tree. 05983 // 05984 // This checking is always done from the "top-most" to 05985 // the "bottom-most" interval in two 05986 // passes. I the first path the check is done for a specified 05987 // interval agains every element in the list. In the second 05988 // path the check is done for each list's elemen against 05989 // the specified interval. 05990 // 05991 // 05992 // PARAMETERS: 05993 // 05994 // theIntervalVector a list of intervals being bound to 05995 // specified interval is returned here. 05996 // The list has 0 entries if nothing were found. 05997 // The order of entries in the list is not 05998 // defined. 05999 // 06000 // theList a list of intervals to be checked. 06001 // 06002 // theIntervalH an interval which is ment to be checked 06003 // against a specified list of intervals. 06004 // 06005 // RETURN: 06006 // 06007 // BdbcSuccess means success, even if nothing were found. 06008 // 06009 // BdbcError means any error. The vector will contain 06010 // entries which were successfully found before 06011 // an error had occured. 06012 // 06013 // *********************************************************************** 06014 // ----------------------------------------------------------------------- 06015 06016 BdbStatus 06017 BdbDatabase::getBoundIntervalsInSubTree( vector<BdbHandle(BdbInterval)>& theIntervalVector, 06018 const vector<BdbHandle(BdbInterval)>& theList, 06019 const BdbHandle(BdbInterval)& theIntervalH ) 06020 { 06021 BdbStatus status = BdbcError; 06022 int i; 06023 int numEntries = theList.size( ); 06024 06025 // Reset a stack 06026 06027 theIntervalVector.clear( ); 06028 06029 // PATH I: Check all the "previous" intervals of the specified 06030 // interval against all elements in the list. 06031 06032 BdbHandle(BdbInterval) thePrevPrevIntervalH; 06033 BdbHandle(BdbInterval) thePrevIntervalH; 06034 06035 theIntervalH->prevVers( thePrevIntervalH ); 06036 while( ! BdbIsNull(thePrevIntervalH)) { 06037 06038 for( i = 0; i < numEntries; i++ ) { 06039 if( thePrevIntervalH == theList[i] ) { 06040 theIntervalVector.push_back( theList[i] ); 06041 } 06042 } 06043 06044 // Go deeper to the next previous version. 06045 06046 thePrevIntervalH->prevVers( thePrevPrevIntervalH ); 06047 thePrevIntervalH = thePrevPrevIntervalH; 06048 } 06049 06050 // PATH II: Check all the "previous" intervals of each interval from 06051 // the input list against the specified interval. 06052 06053 for( i = 0; i < numEntries; i++ ) { 06054 06055 theList[i]->prevVers( thePrevIntervalH ); 06056 while( ! BdbIsNull(thePrevIntervalH)) { 06057 if( thePrevIntervalH == theIntervalH ) { 06058 theIntervalVector.push_back( theList[i] ); 06059 } 06060 06061 // Go deeper to the next previous version. 06062 06063 thePrevIntervalH->prevVers( thePrevPrevIntervalH ); 06064 thePrevIntervalH = thePrevPrevIntervalH; 06065 } 06066 } 06067 06068 return BdbcSuccess; 06069 } 06070 06071 // ----------------------------------------------------------------------- 06072 // *********************************************************************** 06073 // 06074 // ::getNextRevisedIntervals() 06075 // 06076 // DESCRIPTION: 06077 // 06078 // Locate all possible intervals belonging to specified revision 06079 // in higher versions above specified interval. 06080 // 06081 // The newly found intervals are appended to the vector. 06082 // 06083 // This is recursive algorithm. 06084 // 06085 // PARAMETERS: 06086 // 06087 // theIntervalVector a list of intervals matching specified 06088 // revision is returned here. Has 0 entries 06089 // if nothing were found. 06090 // The order of entries in the list is not 06091 // defined. 06092 // 06093 // theIntervalH an interval which specifies a start point 06094 // to locate version. 06095 // 06096 // theRevisionId a revision ID to look for. 06097 // 06098 // RETURN: 06099 // 06100 // BdbcSuccess means success, even if nothing were found. 06101 // 06102 // BdbcError means any error. The vector will contain 06103 // entries which were successfully found before 06104 // an error had occured. 06105 // 06106 // *********************************************************************** 06107 // ----------------------------------------------------------------------- 06108 06109 BdbStatus 06110 BdbDatabase::getNextRevisedIntervals( vector<BdbHandle(BdbIntervalR)>& theIntervalVector, 06111 const BdbHandle(BdbIntervalR)& theIntervalH, 06112 d_ULong theRevisionId ) 06113 { 06114 BdbStatus status = BdbcError; 06115 06116 BdbHandle(BdbIntervalR) theNextIntervalH; 06117 BdbItr(BdbPersObj) nextItr; 06118 BdbHandle(BdbCondRevision) theRevisionH; 06119 06120 theIntervalH->nextVers( nextItr ); 06121 while( nextItr.next( )) { 06122 06123 // Check revision ID of the next interval. 06124 06125 theNextIntervalH = (BdbHandle(BdbIntervalR)&) nextItr; 06126 theNextIntervalH->getRevision( theRevisionH ); 06127 06128 if( ! BdbIsNull(theRevisionH)) { 06129 if( theRevisionId == theRevisionH->id( )) { 06130 theIntervalVector.push_back( theNextIntervalH ); 06131 } 06132 } 06133 06134 // Check all the next versions (if any) of this interval. 06135 06136 status = getNextRevisedIntervals( theIntervalVector, 06137 theNextIntervalH, 06138 theRevisionId ); 06139 if( BdbcSuccess != status ) { 06140 return status; 06141 } 06142 } 06143 06144 return BdbcSuccess; 06145 } 06146 06147 // ----------------------------------------------------------------------- 06148 // *********************************************************************** 06149 // 06150 // ::sortIntervalsList() 06151 // 06152 // DESCRIPTION: 06153 // 06154 // Sorts the intervals "in place" according to their 06155 // version. The interval with the lowest version comes first. 06156 // 06157 // PARAMETERS: 06158 // 06159 // theList a list of intervals to be sorted. 06160 // 06161 // RETURN: 06162 // 06163 // BdbcSuccess when done. 06164 // BdbcError when a "circular" dependancy is met in the 06165 // versions tree. Means a fatal error. 06166 // 06167 // *********************************************************************** 06168 // ----------------------------------------------------------------------- 06169 06170 BdbStatus 06171 BdbDatabase::sortIntervalsList( vector<BdbHandle(BdbInterval)>& theList ) 06172 { 06173 vector<BdbHandle(BdbInterval)> theTmpList; 06174 BdbHandle(BdbInterval) theIntervalH; 06175 BdbHandle(BdbInterval) thePrevIntervalH; 06176 06177 // The algorithm of finding the "bottom-most" element in the list 06178 // is repeaed as meny times as many elements in the original list. 06179 06180 int originalNumber = theList.size( ); 06181 06182 for( int i = 0; i < originalNumber; i++ ) { 06183 06184 // Locate an element which is the "bottom-most" in the list. 06185 // The "found" variable is used to eascape further searching when 06186 // such a "bottom" element is found. 06187 06188 bool found = false; 06189 int currentNumber = theList.size( ); 06190 06191 for( int j = 0; j < currentNumber; j++ ) { 06192 06193 // Check if the current indexed interval has not any of 06194 // other intervals in the list in the "previous" dependency list. 06195 // When we found such an interval then 06196 06197 bool hasDependents = false; 06198 06199 theIntervalH = theList[j]; 06200 theIntervalH->prevVers( thePrevIntervalH ); 06201 06202 while( ! BdbIsNull(thePrevIntervalH)) { 06203 06204 // Find dependents in the whole list except ourself. 06205 06206 for( int k = 0; k < currentNumber; k++ ) { 06207 if( thePrevIntervalH == theList[k] ) { 06208 if( j != k ) { 06209 hasDependents = true; 06210 break; 06211 } 06212 } 06213 } 06214 06215 // Well. The attempt faild -- this is not the "bottom-most" 06216 // element -- will continue searching. 06217 06218 if( hasDependents ) { 06219 break; 06220 } 06221 06222 // Go one step down to the next previous interval. 06223 06224 theIntervalH = thePrevIntervalH; 06225 theIntervalH->prevVers( thePrevIntervalH ); 06226 } 06227 06228 // If current indexed element does not have any dependents 06229 // the (1) include into another list and (2) exclude it from 06230 // the original list. 06231 06232 if( ! hasDependents ) { 06233 theTmpList.push_back( theList[j] ); 06234 theList.erase(std::find(theList.begin(),theList.end(),theList[j])); 06235 found = true; 06236 break; 06237 } 06238 } 06239 06240 // Absence of the "bottom-most" element means a circular 06241 // dependency between the elements. 06242 06243 if( ! found ) { 06244 ErrMsg(error) << "BdbDatabase::sortIntervalsList() -- ERROR." << endl 06245 << " The circular dependency has been detected between versions" << endl 06246 << " in the same interval tree." << endl 06247 << " A persistent container might be badly corrupted." << endl 06248 << " DETECTOR -> " << subsystemTLA( ) << endl 06249 << " CONTAINER -> " << containerName( ) << endmsg; 06250 return BdbcError; 06251 } 06252 } 06253 06254 // Here we expect the original list to be empty. If not -- there is 06255 // something wrong, either with the algorithm itself or with the persistent 06256 // data structures. 06257 06258 if( theList.size( )) { 06259 ErrMsg(error) << "BdbDatabase::sortIntervalsList() -- ERROR." << endl 06260 << " The sorting algorithm failed for internal error." << endl 06261 << " A persistent container might be corrupted." << endl 06262 << " DETECTOR -> " << subsystemTLA( ) << endl 06263 << " CONTAINER -> " << containerName( ) << endmsg; 06264 return BdbcError; 06265 } 06266 06267 // Just make a copy of the temporary vector to the input (now empty) 06268 // vector. 06269 06270 theList = theTmpList; 06271 06272 return BdbcSuccess; 06273 } 06274 06275 const char* 06276 BdbDatabase::getOID( const BdbHandle(BdbPersObj)& thePersObjH ) 06277 { 06278 static char buf[255]; 06279 06280 ooId id = thePersObjH; 06281 06282 int db = id.get_DB(); 06283 int cont = id.get_OC(); 06284 int page = id.get_page(); 06285 int slot = id.get_slot(); 06286 06287 sprintf( buf, "#%d-%d-%d-%d", db, cont, page, slot ); 06288 06289 return buf; 06290 } 06291 06292 /** This function is ment to reset the internal cache of the current object 06293 ** when a base class resets their local cache. 06294 **/ 06295 06296 void 06297 BdbDatabase::resetCacheHandler( ) 06298 { 06299 _intervalCacheH = 0; 06300 } 06301 06302 void 06303 BdbDatabase::setIntervalCache( const BdbHandle(BdbInterval)& theIntervalH ) 06304 { 06305 _intervalCacheH = theIntervalH; 06306 } 06307 06308 BdbStatus 06309 BdbDatabase::splitBaselineInterval( BdbHandle(BdbIntervalR)& theOldIntervalH, 06310 const BdbTime& theTime ) 06311 { 06312 const char* errorString = "BdbDatabase::splitBaselineInterval() -- ERROR."; 06313 06314 BdbStatus status; 06315 06316 // Now we will split the baseline interval. This procedure would be different for 06317 // the FIRST, LAST, an interval in the middle, and the ONLY interval. 06318 06319 BdbHandle(BdbIntervalR) theNewIntervalH; 06320 06321 BdbHandle(BdbIntervalR) theTopNextIntervalH; 06322 BdbHandle(BdbIntervalR) theBaselineNextIntervalH; 06323 06324 theOldIntervalH->getTopNext( theTopNextIntervalH ); 06325 theOldIntervalH->getBaselineNext( theBaselineNextIntervalH ); 06326 06327 // Create the new interval on the right side of the existing interval. 06328 06329 theNewIntervalH = new( theOldIntervalH ) BdbIntervalR( theOldIntervalH->getObject( ), 06330 theTime, 06331 theOldIntervalH->getEndTime( ), 06332 theOldIntervalH->getTag( )); 06333 theOldIntervalH->setEndTime( theTime ); 06334 06335 // Tune the links 06336 06337 theOldIntervalH->setTopNext( theNewIntervalH ); 06338 theOldIntervalH->setBaselineNext( theNewIntervalH ); 06339 06340 theNewIntervalH->setTopPrevious( theOldIntervalH ); 06341 theNewIntervalH->setBaselinePrevious( theOldIntervalH ); 06342 06343 theNewIntervalH->setTopNext( theTopNextIntervalH ); 06344 theNewIntervalH->setBaselineNext( theBaselineNextIntervalH ); 06345 06346 if ( ! BdbIsNull(theTopNextIntervalH)) { 06347 theTopNextIntervalH->setTopPrevious( theNewIntervalH ); 06348 } 06349 if ( ! BdbIsNull(theBaselineNextIntervalH)) { 06350 theBaselineNextIntervalH->setBaselinePrevious( theNewIntervalH ); 06351 } 06352 06353 // Special tuning for the last interval - set its name in 06354 // in the container scope. 06355 06356 BdbHandle(BdbContObj) intervalContH; 06357 getIntervalContH( intervalContH ); 06358 06359 if ( BdbTime::plusInfinity == theNewIntervalH->getEndTime( )) { 06360 theOldIntervalH.unnameObj( intervalContH ); 06361 theNewIntervalH.nameObj( intervalContH, "LastInterval" ); 06362 } 06363 06364 // And finally we make some commont settings to the newely created interval. 06365 06366 theNewIntervalH->setVersionTime( theOldIntervalH->getVersionTime( )); 06367 06368 BdbHandle(BdbCondRevision) theRevisionH; 06369 theOldIntervalH->getRevision( theRevisionH ); 06370 theNewIntervalH->setRevision( theRevisionH ); 06371 06372 return BdbcSuccess; 06373 } 06374 06375 BdbStatus 06376 BdbDatabase::splitIntervalsTree( const char* theContainerName, 06377 BdbHandle(BdbIntervalR)& theOldIntervalH, 06378 const BdbTime& theTime ) 06379 { 06380 const char* errorString = "BdbDatabase::splitIntervalsTree() -- ERROR."; 06381 06382 BdbStatus status; 06383 06384 BdbHandle(BdbIntervalR) theLeftBaselineIntervalH; 06385 BdbHandle(BdbIntervalR) theRightBaselineIntervalH; 06386 06387 // Get the adjacent topmost interval ("DesiredH") left to the beginning 06388 // of the current old interval ("theOldIntervalH"). Since the current old interval 06389 // is the baseline one then we will locate desired interval via the "IntermediateTopH" 06390 // interval at the beginning of the current baseline interval. 06391 // 06392 // ............................................ 06393 // : : 06394 // (3:getTopPrevious) : 06395 // : +----------------- : 06396 // V | theTopIntervalH (2:getTopmostInterval) 06397 // -------------------------+----------------- : 06398 // theTopPreviousIntervalH | - - - : 06399 // ------------------------------+------------------ : 06400 // - - - | theOldIntervalH : 06401 // ------------------------------+------------------ : 06402 // V : 06403 // : : 06404 // (1:getBeginTime()) : 06405 // : : 06406 // ............................... 06407 // 06408 // NOTE: This procedure should be called before any other new intervals 06409 // are created in the container. The problem is with Objectivity's 06410 // indexing. This index knows nothing about our intentions. 06411 06412 BdbHandle(BdbIntervalR) theTopPreviousIntervalH; 06413 BdbHandle(BdbIntervalR) theTopIntervalH; 06414 06415 status = getTopmostInterval( theTopIntervalH, 06416 theContainerName, 06417 theOldIntervalH->getBeginTime( )); 06418 if( BdbcSuccess != status ) { 06419 ErrMsg(error) << errorString << endl 06420 << " Failed to locate a topmost interval interval at: " << theOldIntervalH->getBeginTime( ) << endl 06421 << " DETECTOR -> " << subsystemTLA( ) << endl 06422 << " CONTAINER -> " << theContainerName << endmsg; 06423 return BdbcError; 06424 } 06425 theTopIntervalH->getTopPrevious( theTopPreviousIntervalH ); 06426 06427 // Get adjucent baseline intervals for the old interval. 06428 06429 BdbHandle(BdbIntervalR) theBaselinePreviousIntervalH; 06430 BdbHandle(BdbIntervalR) theBaselineNextIntervalH; 06431 06432 theOldIntervalH->getBaselinePrevious( theBaselinePreviousIntervalH ); 06433 theOldIntervalH->getBaselineNext( theBaselineNextIntervalH ); 06434 06435 // Get baseline revision. 06436 06437 BdbHandle(BdbCondRevision) theRevisionH; 06438 06439 theOldIntervalH->getRevision( theRevisionH ); 06440 06441 // Split the specified old interval into two copies. Connect these copies 06442 // to each other in a regular way as two sequential baseline intervals. 06443 // 06444 // NOTE: We do not delete the old interval and its version tree and its 06445 // genealogy object because we will use this stuff to produce 06446 // the left and right sub-trees under the newely created intervals. 06447 06448 // Previous<->Left... 06449 06450 theLeftBaselineIntervalH = new( theOldIntervalH ) BdbIntervalR( theOldIntervalH->getObject( ), 06451 theOldIntervalH->getBeginTime( ), 06452 theTime, 06453 theOldIntervalH->getTag( )); 06454 06455 theLeftBaselineIntervalH->setVersionTime( theOldIntervalH->getVersionTime( )); 06456 theLeftBaselineIntervalH->setRevision( theRevisionH ); 06457 06458 theBaselinePreviousIntervalH->setBaselineNext( theLeftBaselineIntervalH ); 06459 theLeftBaselineIntervalH->setBaselinePrevious( theBaselinePreviousIntervalH ); 06460 06461 // Right<->Next... 06462 06463 theRightBaselineIntervalH = new( theOldIntervalH ) BdbIntervalR( theOldIntervalH->getObject( ), 06464 theTime, 06465 theOldIntervalH->getEndTime( ), 06466 theOldIntervalH->getTag( )); 06467 06468 theRightBaselineIntervalH->setVersionTime( theOldIntervalH->getVersionTime( )); 06469 theRightBaselineIntervalH->setRevision( theRevisionH ); 06470 06471 theRightBaselineIntervalH->setBaselineNext( theBaselineNextIntervalH ); 06472 theBaselineNextIntervalH->setBaselinePrevious( theRightBaselineIntervalH ); 06473 06474 // Left <-> Right... 06475 06476 theLeftBaselineIntervalH->setBaselineNext( theRightBaselineIntervalH ); 06477 theRightBaselineIntervalH->setBaselinePrevious( theLeftBaselineIntervalH ); 06478 06479 // Create limited subtrees above the newely created intervals using the whole 06480 // sub-tree of the old one. 06481 06482 status = copyLimitedSubTree( theOldIntervalH, 06483 theOldIntervalH->getBeginTime( ), 06484 theTime, 06485 theLeftBaselineIntervalH ); 06486 if( BdbcSuccess != status ) { 06487 ErrMsg(error) << errorString << endl 06488 << " Failed to copy the left sub-tree of the split interval." << endmsg; 06489 return BdbcError; 06490 } 06491 status = copyLimitedSubTree( theOldIntervalH, 06492 theTime, 06493 theOldIntervalH->getEndTime( ), 06494 theRightBaselineIntervalH ); 06495 if( BdbcSuccess != status ) { 06496 ErrMsg(error) << errorString << endl 06497 << " Failed to copy the right sub-tree of the split interval." << endmsg; 06498 return BdbcError; 06499 } 06500 06501 // Draw the topmost linked list over the new intervals trees. 06502 // This would also include binding with the previous and the next intervals 06503 // of the old interval. 06504 // This operation is done in 3 steps: 06505 // 06506 // 1. the border before the left fragnment. 06507 // 2. the border between the left and right fragnments. 06508 // 3. the border after the rightfragnment. 06509 // 06510 // IMPORTANT NOTE: In all these steps we are using the same 06511 // interval "theTopPreviousIntervalH" as a link to the previous topmost interval. 06512 // Due to a way the "::linkTopIntervalsInSubTree()" method works, the value 06513 // of this back link is always modified upon the completion of the method. 06514 06515 status = linkTopIntervalsInSubTree( theLeftBaselineIntervalH, 06516 theTopPreviousIntervalH ); 06517 if( BdbcSuccess != status ) { 06518 ErrMsg(error) << errorString << endl 06519 << " Failed to draw the topmost line before the split interval." << endmsg; 06520 return BdbcError; 06521 } 06522 status = linkTopIntervalsInSubTree( theRightBaselineIntervalH, 06523 theTopPreviousIntervalH ); 06524 if( BdbcSuccess != status ) { 06525 ErrMsg(error) << errorString << endl 06526 << " Failed to draw the topmost line between fragments of the split interval." << endmsg; 06527 return BdbcError; 06528 } 06529 status = linkTopIntervalsInSubTree( theBaselineNextIntervalH, 06530 theTopPreviousIntervalH ); 06531 if( BdbcSuccess != status ) { 06532 ErrMsg(error) << errorString << endl 06533 << " Failed to draw the topmost line after the split interval." << endmsg; 06534 return BdbcError; 06535 } 06536 06537 // And finally delete the old intervals together with its version tree 06538 // and the genealogy object (note tha last parameter set to "true"). 06539 06540 deleteIntervalsInSubTree( theOldIntervalH, true ); 06541 06542 return BdbcSuccess; 06543 } 06544 06545 06546 /** Copy a subtree of intervals, limited by the left and right borders 06547 ** in validity time, assuming that the passed intervals already exist. 06548 **/ 06549 06550 BdbStatus 06551 BdbDatabase::copyLimitedSubTree( const BdbHandle(BdbIntervalR)& theInIntervalH, 06552 const BdbTime& theLeftBorderTime, 06553 const BdbTime& theRightBorderTime, 06554 BdbHandle(BdbIntervalR)& theOutIntervalH ) 06555 { 06556 const char* errorString = "BdbDatabase::copyLimitedSubTree() -- error."; 06557 06558 BdbStatus status = BdbcError; 06559 06560 int i; 06561 06562 // Get sub-trees (if any). 06563 06564 vector<BdbHandle(BdbIntervalR)> theInNextIntervalH; 06565 BdbItr(BdbPersObj) theItr; 06566 BdbHandle(BdbIntervalR) theIntervalH; 06567 06568 theInIntervalH->nextVers( theItr ); 06569 while( theItr.next( )) { 06570 theIntervalH = (BdbHandle(BdbIntervalR)&) theItr; 06571 if( ! ((( theLeftBorderTime <= theIntervalH->beginTime( )) && 06572 ( theRightBorderTime <= theIntervalH->beginTime( ))) 06573 || 06574 (( theLeftBorderTime >= theIntervalH->endTime( )) && 06575 ( theRightBorderTime >= theIntervalH->endTime( ))))) { 06576 theInNextIntervalH.push_back( theIntervalH ); 06577 } 06578 } 06579 06580 // Create duplicate sub-trees in the output container if at least one 06581 // sub-tree was found in the input one. 06582 06583 int numSubTrees = theInNextIntervalH.size( ); 06584 06585 if( numSubTrees > 0 ) { 06586 06587 // Enable linear/branch versioning on the original interval object. 06588 06589 if( numSubTrees == 1 ) { 06590 theOutIntervalH.setVersStatus( oocLinearVers ); 06591 } else { 06592 theOutIntervalH.setVersStatus( oocBranchVers ); 06593 } 06594 06595 // Create and name as many linear/branch version(s) for the output interval 06596 // as it were found for the input interval. 06597 06598 BdbHandle(BdbIntervalR) theOutNewIntervalH; 06599 vector<BdbHandle(BdbIntervalR)> theOutNextIntervalH; 06600 06601 for( i = 0; i < numSubTrees; i++ ) { 06602 createVersion( theOutIntervalH, theOutNewIntervalH ); 06603 nameVersion( theOutIntervalH, theOutNewIntervalH ); 06604 theOutNextIntervalH.push_back( theOutNewIntervalH ); 06605 } 06606 06607 // Disable versioning of the current interval. 06608 06609 theOutIntervalH.setVersStatus( oocNoVers ); 06610 06611 // Copy information from the input intervals into the output ones. 06612 // 06613 // Truncate the very first and very last interval in the list 06614 // if the validity limits were specified for this method. 06615 // 06616 // NOTE: We do not copy the TOP and BASELINE navigation links 06617 // because they would be invalid in the new context. 06618 06619 BdbHandle(BdbCondRevision) theRevisionH; 06620 06621 for( i = 0; i < numSubTrees; i++ ) { 06622 06623 // Copy the basic characteristics. 06624 06625 theOutNextIntervalH[i]->setObject( theInNextIntervalH[i]->getObject( )); 06626 theOutNextIntervalH[i]->setBeginTime( theInNextIntervalH[i]->getBeginTime( )); 06627 theOutNextIntervalH[i]->setEndTime( theInNextIntervalH[i]->getEndTime( )); 06628 theOutNextIntervalH[i]->setVersionTime( theInNextIntervalH[i]->getVersionTime( )); 06629 theOutNextIntervalH[i]->setTag( theInNextIntervalH[i]->getTag( )); 06630 06631 // Copy the revision information. 06632 06633 theInNextIntervalH[i]->getRevision( theRevisionH ); 06634 theOutNextIntervalH[i]->setRevision( theRevisionH ); 06635 06636 // Truncate the first and last intervals (if needed). 06637 06638 if(( 0 == i ) && 06639 ( theOutNextIntervalH[i]->beginTime( ) < theLeftBorderTime )) { 06640 theOutNextIntervalH[i]->setBeginTime( theLeftBorderTime ); 06641 } 06642 if((( numSubTrees - 1 ) == i ) && 06643 ( theOutNextIntervalH[i]->endTime( ) > theRightBorderTime )) { 06644 theOutNextIntervalH[i]->setEndTime( theRightBorderTime ); 06645 } 06646 } 06647 06648 // Proceed along the version tree. 06649 06650 for( i = 0; i < numSubTrees; i++ ) { 06651 06652 status = copyLimitedSubTree( theInNextIntervalH[i], 06653 theLeftBorderTime, 06654 theRightBorderTime, 06655 theOutNextIntervalH[i] ); 06656 if( BdbcSuccess != status ) { 06657 return status; 06658 } 06659 } 06660 } 06661 06662 return BdbcSuccess; 06663 } 06664 06665 BdbStatus 06666 BdbDatabase::linkTopIntervalsInSubTree( const BdbHandle(BdbIntervalR)& theIntervalH, 06667 BdbHandle(BdbIntervalR)& thePreviousIntervalH ) 06668 { 06669 const char* errorString = "BdbDatabase::linkTopIntervalsInSubTree() -- error."; 06670 06671 BdbStatus status = BdbcError; 06672 06673 // This check will prevent us from accidental crashing. 06674 06675 if( BdbIsNull( theIntervalH ) || BdbIsNull( thePreviousIntervalH )) { 06676 ErrMsg(error) << errorString << endl 06677 << " NULL handles have been detected." << endl 06678 << " The output container may have incorrect internal structure." << endmsg; 06679 return BdbcError; 06680 } 06681 06682 // Iterate over sub-tree(s) (if amy). 06683 06684 bool subTreeFound = false; 06685 06686 BdbItr(BdbPersObj) theItr; 06687 06688 theIntervalH->nextVers( theItr ); 06689 while( theItr.next( )) { 06690 06691 status = linkTopIntervalsInSubTree( (BdbHandle(BdbIntervalR)&) theItr, 06692 thePreviousIntervalH ); 06693 if( BdbcSuccess != status ) { 06694 return status; 06695 } 06696 06697 subTreeFound = true; 06698 } 06699 06700 // If the subtree was not found this means that the current interval 06701 // is the TOPMOST one and must be included into the list. 06702 06703 if ( ! subTreeFound ) { 06704 06705 thePreviousIntervalH->setTopNext( theIntervalH ); 06706 theIntervalH->setTopPrevious( thePreviousIntervalH ); 06707 06708 thePreviousIntervalH = theIntervalH; 06709 } 06710 06711 return BdbcSuccess; 06712 } 06713 06714 06715 void 06716 BdbDatabase::deleteIntervalsInSubTree( BdbHandle(BdbIntervalR)& theIntervalH, 06717 bool deleteGeneObject ) 06718 { 06719 // First of all we propagate recursively along the branches (if any) 06720 // and delete intervals there. 06721 06722 BdbItr(BdbPersObj) theItr; 06723 06724 if( theIntervalH->exist_geneObj( )) { 06725 theIntervalH->nextVers( theItr ); 06726 while( theItr.next( )) { 06727 deleteIntervalsInSubTree((BdbHandle(BdbIntervalR)&) theItr ); 06728 } 06729 } 06730 06731 // Then we delete the genealogy object if required. 06732 06733 if( deleteGeneObject && theIntervalH->exist_geneObj( )) { 06734 06735 BdbHandle(BdbIntervalGene) theGeneObjH; 06736 theGeneObjH = (const BdbHandle(BdbIntervalGene)&) theIntervalH->geneObj( ); 06737 06738 BdbDelete(theGeneObjH); 06739 } 06740 06741 // And finally we delete current interval itself. 06742 06743 BdbDelete( theIntervalH ); 06744 06745 return; 06746 } 06747 06748 ///////////////// 06749 // End Of File // 06750 /////////////////
BaBar Public Site | SLAC | News | Links | Who's Who | Contact Us
Page Owner: Jacek Becla
Last Update: October 04, 2002