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

Search | Site Map .

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

/BdbTrees/BdbTreeNode.cc

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //  $Id: BdbTreeNode.cc,v 1.40 2002/04/25 02:00:52 patton Exp $
00004 //
00005 // Description:
00006 //  Class BdbTreeNode implementation file. This class represents a node
00007 //  in a tree. A node may have a parent, and multiple children, which
00008 //  themselves may be tree nodes, or leaf objects. This is the transient
00009 //  wrapper class that provides the user interface to the persistent
00010 //  BdbTreeNodeP class.
00011 //
00012 // Environment:
00013 //  Software developed for the BaBar Detector at the SLAC B-Factory.
00014 //
00015 // Author List:
00016 //  David R. Quarrie                Original Author
00017 //
00018 // Copyright Information:
00019 //  Copyright (C) 1998              Lawrence Berkeley Laboratory
00020 //
00021 //------------------------------------------------------------------------
00022 
00023 //-----------------------
00024 // This Class's Header --
00025 //-----------------------
00026 #include "BdbTrees/BdbTreeNode.hh"
00027 
00028 //-------------
00029 // C Headers --
00030 //-------------
00031 extern "C" {
00032 #include <assert.h>
00033 #include <ctype.h>
00034 #include <stddef.h>
00035 #include <string.h>
00036 #include <unistd.h>
00037 }
00038 
00039 //---------------------------------
00040 // Collaborating Class's Headers --
00041 //---------------------------------
00042 #include "ErrLogger/ErrLog.hh"
00043 #include "BdbUtil/BdbPathName.hh"
00044 #include "BdbAccess/BdbDbAccessMgr.hh"
00045 #include "BdbAccess/BdbContAccessMgr.hh"
00046 #include "BdbApplication/BdbDomain.hh"
00047 #include "BdbApplication/BdbDebug.hh"
00048 #include "BdbTrees/BdbMetaData.hh"
00049 #include "BdbTrees/BdbTreesErrors.hh"
00050 #include "BdbTrees/BdbTreeNodeCache.hh"
00051 #include "BdbTrees/BdbTreeNodeLocking.hh"
00052 
00053 //-----------------------------------------------------------------------
00054 // Local Macros, Typedefs, Structures, Unions and Forward Declarations --
00055 //-----------------------------------------------------------------------
00056 
00057 static const char rcsid[] = "$Id: BdbTreeNode.cc,v 1.40 2002/04/25 02:00:52 patton Exp $";
00058 
00059 
00060 BdbTreeNodeCache*   BdbTreeNode::_tnCache = new BdbTreeNodeCache();
00061 BdbTreeNodeLocking* BdbTreeNode::_tnLock  = new BdbTreeNodeLocking();
00062 const d_Boolean   BdbTreeNode::USE_CACHE  = (getenv("BDB_DO_NOT_USE_TREE_NODE_CACHE") == 0);
00063 
00064 
00065 //      ----------------------------------------
00066 //      -- Public Function Member Definitions --
00067 //      ----------------------------------------
00068 
00069 //----------------
00070 // Constructors --
00071 //----------------
00072 
00073 BdbTreeNode::BdbTreeNode( )
00074 : BdbAbsWrapper( )
00075 {
00076 }
00077 
00078 BdbTreeNode::BdbTreeNode( BdbTreeNode& theParent, 
00079                           const char* const theName,
00080                           BdbHandleAny& placement )
00081 : BdbAbsWrapper( )
00082 {
00083     BdbHandle(BdbTreeNodeP) theParentP = theParent.persistent( );
00084     BdbHandleAny usePlacement = placement;
00085     if ( BdbIsNull( usePlacement ) ) {
00086         usePlacement = theParentP;
00087     }
00088     BdbHandle(BdbTreeNodeP) theNodeP;
00089     theNodeP = new(usePlacement) BdbTreeNodeP( theParentP, theName );
00090     if ( ! BdbIsNull( theNodeP ) ) {
00091         setPersistent( theNodeP );
00092         theParentP->replace( theNodeP, theName );
00093     }
00094 }
00095 
00096 BdbTreeNode::BdbTreeNode( BdbHandle(BdbTreeNodeP)& theNode )
00097 : BdbAbsWrapper( )
00098 {
00099     setObject( theNode );
00100 }
00101 
00102 BdbTreeNode::BdbTreeNode( const BdbTreeNode& theNode )
00103 : BdbAbsWrapper( )
00104 {
00105     BdbHandleAny theObj = theNode.object( );
00106     setObject( theObj );
00107 }
00108 
00109 //--------------
00110 // Destructor --
00111 //--------------
00112 
00113 BdbTreeNode::~BdbTreeNode( )
00114 {
00115 }
00116 
00117 //-------------
00118 // Selectors --
00119 //-------------
00120     
00121 d_ULong 
00122 BdbTreeNode::count( ) const
00123 {
00124     return persistent( )->count( );
00125 }
00126 
00127 const char*
00128 BdbTreeNode::name( ) const
00129 {
00130     return persistent( )->name( );
00131 }
00132 
00133 const char*
00134 BdbTreeNode::fullName( ) const
00135 {
00136     return persistent( )->fullName( );
00137 }
00138 
00139 const char*
00140 BdbTreeNode::pathName( ) const
00141 {
00142     return persistent( )->pathName( );
00143 }
00144 
00145 //--------------
00146 // Operations --
00147 //--------------
00148     
00149 BdbStatus
00150 BdbTreeNode::add( BdbTreeNode& aChild, const char* const theName )
00151 {
00152     BdbHandle(BdbTreeNodeP) aChildP = aChild.persistent( );
00153     BdbStatus result = updateAndWait( );
00154     if (BdbcSuccess == result ) {
00155         result = persistent( )->add( aChildP, theName );
00156     } else {
00157         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00158                    "BdbTreeNode::add", name( ) ); 
00159     }
00160     return result;
00161 }
00162 
00163 BdbStatus
00164 BdbTreeNode::add( BdbHandle(BdbPersObj)& aChild, const char* const theName ) 
00165 {
00166     BdbStatus result = updateAndWait( );
00167     if (BdbcSuccess == result ) {
00168         result = persistent( )->add( aChild, theName );
00169     } else {
00170         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00171                    "BdbTreeNode::add", name( ) ); 
00172     }
00173     return result;
00174 }
00175 
00176 BdbStatus
00177 BdbTreeNode::child( BdbTreeNode& aChild, const char* const theName ) const
00178 {
00179     BdbHandle(BdbPersObj) aChildP;
00180     BdbStatus result = BdbcError;
00181     
00182     if ( persistent( )->childIsTreeNode( theName ) ) {
00183         result = persistent( )->child( aChildP, theName );
00184     }
00185     aChild.setPersistent( (BdbHandle(BdbTreeNodeP)&)aChildP );
00186     return result;
00187 }
00188 
00189 BdbStatus
00190 BdbTreeNode::child( BdbHandle(BdbPersObj)& aChild, const char* const theName ) const 
00191 {
00192     BdbStatus result = persistent( )->child( aChild, theName );
00193     return result;
00194 }
00195 
00196 BdbStatus
00197 BdbTreeNode::child( BdbHandle(BdbPersObj)& aChild, 
00198                     const char* const theName, 
00199                     ooTypeNumber theType ) const 
00200 {
00201     BdbStatus result = persistent( )->child( aChild, theName, theType );
00202     return result;
00203 }
00204 
00205 BdbStatus
00206 BdbTreeNode::child( BdbHandle(BdbPersObj)& aChild, 
00207                     const char* const theName, 
00208                     ooTypeNumber theTypes[], d_ULong numTypes ) const 
00209 {
00210     BdbStatus result = persistent( )->child( aChild, theName, theTypes, numTypes );
00211     return result;
00212 }
00213 
00214 BdbStatus
00215 BdbTreeNode::clear( ) 
00216 {
00217     BdbStatus result = updateAndWait( );
00218     if (BdbcSuccess == result ) {
00219         result = persistent( )->clear( );
00220     } else {
00221         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00222                    "BdbTreeNode::clear", name( ) ); 
00223     }
00224     return result;
00225 }
00226 
00227 BdbStatus
00228 BdbTreeNode::clearAndDestroy( ) 
00229 {
00230     BdbStatus result = updateAndWait( );
00231     if (BdbcSuccess == result ) {
00232         result = persistent( )->clearAndDestroy( );
00233     } else {
00234         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00235                    "BdbTreeNode::remove", name( ) ); 
00236     }
00237     return result;
00238 }
00239 
00240 d_Boolean
00241 BdbTreeNode::hasChild( const char* const theName ) const
00242 {
00243     return persistent( )->hasChild( theName );
00244 }
00245 
00246 d_Boolean
00247 BdbTreeNode::hasChild( BdbTreeNode& aChild, d_Boolean descend ) const
00248 {
00249     BdbHandle(BdbTreeNodeP) aChildP = aChild.persistent( );
00250     return persistent( )->hasChild( aChildP, descend );
00251 }
00252 
00253 d_Boolean
00254 BdbTreeNode::hasChild( BdbHandle(BdbPersObj)& aChild, d_Boolean descend ) const
00255 {
00256     return persistent( )->hasChild( aChild, descend );
00257 }
00258 
00259 BdbStatus
00260 BdbTreeNode::makeChild( BdbTreeNode& aNode, const char* const theName )
00261 {
00262     BdbHandle(BdbTreeNodeP) theNodeP;
00263     BdbStatus result = updateAndWait( );
00264     if (BdbcSuccess == result ) {
00265         result = persistent( )->makeChild( theNodeP, theName );
00266         if ( BdbcSuccess == result ) {
00267             aNode.setPersistent( theNodeP );
00268         }
00269     } else {
00270         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00271                    "BdbTreeNode::makeChild", name( ) ); 
00272     }
00273     return result;
00274 }
00275 
00276 BdbStatus
00277 BdbTreeNode::parent( BdbTreeNode& theParent ) const
00278 {
00279     BdbHandle(BdbTreeNodeP) theParentP;
00280     BdbStatus result = persistent( )->parent( theParentP );
00281     theParent.setPersistent( theParentP );
00282     return result;
00283 }
00284 
00285 BdbStatus
00286 BdbTreeNode::remove( const char* const theName ) 
00287 {
00288     BdbStatus result = updateAndWait( );
00289     if (BdbcSuccess == result ) {
00290         result = persistent( )->remove( theName );
00291     } else {
00292         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00293                    "BdbTreeNode::remove", name( ) ); 
00294     }
00295     return result;
00296 }
00297 
00298 BdbStatus
00299 BdbTreeNode::remove( BdbTreeNode& aChild ) 
00300 {
00301     BdbHandle(BdbTreeNodeP) aChildP = aChild.persistent( );
00302     BdbStatus result = updateAndWait( );
00303     if (BdbcSuccess == result ) {
00304         result = persistent( )->remove( aChildP );
00305     } else {
00306         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00307                    "BdbTreeNode::remove", name( ) ); 
00308     }
00309     return result;
00310 }
00311 
00312 BdbStatus
00313 BdbTreeNode::remove( BdbHandle(BdbPersObj)& aChild ) 
00314 {
00315     BdbStatus result = updateAndWait( );
00316     if (BdbcSuccess == result ) {
00317         result = persistent( )->remove( aChild );
00318     } else {
00319         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00320                    "BdbTreeNode::remove", name( ) ); 
00321     }
00322     return result;
00323 }
00324 
00325 BdbStatus
00326 BdbTreeNode::removeAndDestroy( const char* const theName ) 
00327 {
00328     BdbStatus result = updateAndWait( );
00329     if (BdbcSuccess == result ) {
00330         result = persistent( )->removeAndDestroy( theName );
00331     } else {
00332         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00333                    "BdbTreeNode::removeAndDestroy", name( ) ); 
00334     }
00335     return result;
00336 }
00337 
00338 BdbStatus
00339 BdbTreeNode::removeAndDestroy( BdbTreeNode& aChild ) 
00340 {
00341     BdbHandle(BdbTreeNodeP) aChildP = aChild.persistent( );
00342     BdbStatus result = updateAndWait( );
00343     if (BdbcSuccess == result ) {
00344         result = persistent( )->removeAndDestroy( aChildP );
00345     } else {
00346         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00347                    "BdbTreeNode::removeAndDestroy", name( ) ); 
00348     }
00349     return result;
00350 }
00351 
00352 BdbStatus
00353 BdbTreeNode::removeAndDestroy( BdbHandle(BdbPersObj)& aChild ) 
00354 {
00355     BdbStatus result = updateAndWait( );
00356     if (BdbcSuccess == result ) {
00357         result = persistent( )->removeAndDestroy( aChild );
00358     } else {
00359         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00360                    "BdbTreeNode::removeAndDestroy", name( ) ); 
00361     }
00362     return result;
00363 }
00364 
00365 BdbStatus
00366 BdbTreeNode::replace( BdbTreeNode& aChild, const char* const theName )
00367 {
00368     BdbHandle(BdbTreeNodeP) aChildP = aChild.persistent( );
00369     BdbStatus result = updateAndWait( );
00370     if (BdbcSuccess == result ) {
00371         result = persistent( )->replace( aChildP, theName );
00372     } else {
00373         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00374                    "BdbTreeNode::replace", name( ) ); 
00375     }
00376     return result;
00377 }
00378 
00379 BdbStatus
00380 BdbTreeNode::replace( BdbHandle(BdbPersObj)& aChild, const char* const theName ) 
00381 {
00382     BdbStatus result = updateAndWait( );
00383     if (BdbcSuccess == result ) {
00384         result = persistent( )->replace( aChild, theName );
00385     } else {
00386         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00387                    "BdbTreeNode::replace", name( ) ); 
00388     }
00389     return result;
00390 }
00391 
00392 BdbStatus
00393 BdbTreeNode::upgradeName( )
00394 {
00395     return persistent( )->upgradeName( );
00396 }
00397 
00398 BdbStatus 
00399 BdbTreeNode::moveTo( const char* const thePath )
00400 // Move this transient tree node to reference the persistent tree node
00401 // that corresponds to the specified path. This obeys Unix file syntax.
00402 // An absolute path begins with the "/" character and must specify the
00403 // authorization level and any relevant sublevels. A relative path omits
00404 // the leading "/" character. Moving up the tree is denoted by "../".
00405 {
00406     BdbTreeNode theNode;
00407     BdbHandle(BdbTreeNodeP) theNodeP;
00408     char        theFragment[256];
00409     const char* fragmentStart = thePath;
00410     const char* fragmentEnd   = thePath;
00411     size_t      fragmentLength;
00412     int         nodePathL = 0; // for cache
00413     BdbStatus   result = BdbcSuccess;
00414 
00415     if ( NULL != thePath ) {
00416         if ( ! isNull( ) ) {
00417             theNode = *this;
00418             setNull( );
00419         }
00420         result = BdbcError;
00421         if ( BdbPathName::separator() == *thePath ) {
00422             // it is important to use cache first, because theNode.fullName() touches "Root" container
00423             if ( USE_CACHE ) {
00424                 // Try to move to the farthest cached tree-node (or Root)
00425                 if ( BdbcSuccess == findBestCachedNode(thePath, theNode, fragmentStart) ) {
00426                     if ( 0 == fragmentStart ) { // exact match
00427                         result = BdbcSuccess;
00428                     }
00429                 } else {
00430                     if ( BdbcSuccess != theNode.moveToRoot( ) ) {
00431                         return BdbSignal(BdbcUserError, BdbTreesErrFunctionFailed, 0,
00432                                          "BdbTreeNode::moveTo", "in moveToRoot 1") ;
00433                     }
00434                     fragmentStart++;
00435                 }
00436                 nodePathL = fragmentStart - thePath;
00437             } else {
00438                 if ( ! theNode.isNull( ) && ( 0 == strcmp( thePath, theNode.fullName( ) ) ) ) {
00439                     // It's identical - no movement is necessary
00440                     COUT1 << "BdbTreeNode::moveTo: Cached path" << endl;
00441                     result = BdbcSuccess;
00442                 } else {
00443                     // It's not identical - Move to the root tree-node.
00444                     if ( BdbcSuccess != theNode.moveToRoot( ) ) {
00445                         return BdbSignal(BdbcUserError, BdbTreesErrFunctionFailed, 0,
00446                                          "BdbTreeNode::moveTo", "in moveToRoot 2") ;
00447                     }
00448                     fragmentStart++;
00449                 }
00450             }
00451         }
00452         if ( BdbcSuccess != result ) {
00453 
00454             // Traverse the path
00455             result = BdbcSuccess;
00456             while ( ( BdbcSuccess == result ) && 
00457                     ( NULL != ( fragmentEnd = strchr( fragmentStart, BdbPathName::separator() ) ) ) ) {
00458                 fragmentLength = fragmentEnd - fragmentStart;
00459                 if ( 0 < fragmentLength ) {
00460                     strncpy( theFragment, fragmentStart, fragmentLength );
00461                     theFragment[fragmentLength] = '\0';
00462                     result = theNode.moveOneLevel( theFragment, d_False );
00463                     if ( BdbcSuccess == result && USE_CACHE ) { // insert entry into the cache
00464                         char nodePath[256];
00465                         nodePathL += fragmentLength;
00466                         strncpy(nodePath, thePath, nodePathL);
00467                         nodePath[nodePathL] = '\0';
00468                         BdbRef(BdbObj) r = (BdbRef(BdbObj)) theNode.persistent();
00469                         //cout << "TNCACHE: inserting \"" << nodePath
00470                         //     << "\", oid = " << r.sprint() << endl;
00471                         _tnCache->insertEntry(nodePath, r);
00472                     }
00473                }
00474                 fragmentStart = fragmentEnd + 1;
00475                 nodePathL++;
00476             }
00477             if ( BdbcSuccess == result ) {
00478                 // Deal with last fragment
00479                 fragmentLength = strlen( fragmentStart );
00480                 if ( 0 < fragmentLength ) {
00481                     result = theNode.moveOneLevel( fragmentStart, d_False );
00482                     if ( BdbcSuccess == result && USE_CACHE ) { // insert entry into the cache
00483                         char nodePath[256];
00484                         nodePathL += fragmentLength;
00485                         strncpy(nodePath, thePath, nodePathL);
00486                         nodePath[nodePathL] = '\0';
00487                         BdbRef(BdbObj) r = (BdbRef(BdbObj)) theNode.persistent();
00488                         //cout << "TNCACHE: inserting \"" << nodePath
00489                         //     << "\", oid = " << r.sprint() << endl;
00490                         _tnCache->insertEntry(nodePath, r);
00491                     }
00492                 }
00493             }
00494         }
00495         if ( BdbcSuccess == result ) {
00496             *this = theNode;
00497         }
00498     }
00499     return result;
00500 }
00501 
00502 
00503 /**
00504  **  The function sets "theNode" to the farthest cached node.
00505  **  It also sets fragmentStart, to the first character after 
00506  **  the part of the path corresponding to cached node.
00507  **  If no cached node is found, the function returns an error, 
00508  **  and "theNode"/startAfterCached are not altered.
00509  **  Successful return and startAfterCached == 0 means
00510  **  that an exact match was found.
00511  **/
00512 BdbStatus
00513 BdbTreeNode::findBestCachedNode(const char* thePath, 
00514                                 BdbTreeNode& theNode, 
00515                                 const char*& startAfterCached)
00516 {
00517     char theFragment[256];
00518     strcpy(theFragment, thePath);
00519     char* fragmentEnd   = theFragment;
00520     BdbRef(BdbObj) r;
00521 
00522     if ( BdbcSuccess == _tnCache->findEntry(thePath, r) ) {
00523         startAfterCached = 0;
00524         BdbRef(BdbTreeNodeP) tnR = (BdbRef(BdbTreeNodeP)) r;
00525         BdbHandle(BdbTreeNodeP) tnH = tnR;
00526         theNode.setPersistent(tnH);
00527         COUT2 << "Used cached intermediate node " << thePath << endl;
00528         return BdbcSuccess; // exact match
00529     }
00530     
00531     while ( NULL != ( fragmentEnd = strrchr(theFragment, BdbPathName::separator()) ) ) {
00532         *fragmentEnd = '\0';
00533         if ( 0 == strlen(theFragment) ) {
00534             break;
00535         }
00536         if ( BdbcSuccess == _tnCache->findEntry(theFragment, r) ) {
00537             startAfterCached = thePath + strlen(theFragment) +1;
00538             //cout << "found tn for " << theFragment 
00539             //     << ", startAfterCached = " << startAfterCached << endl;
00540             BdbRef(BdbTreeNodeP) tnR = (BdbRef(BdbTreeNodeP)) r;
00541             BdbHandle(BdbTreeNodeP) tnH = tnR;
00542             theNode.setPersistent(tnH);
00543             COUT2 << "Used cached intermediate node " << thePath << endl;
00544             return BdbcSuccess;
00545         }
00546     }
00547 
00548     return BdbcError;
00549 }
00550 
00551 
00552 BdbStatus 
00553 BdbTreeNode::moveUp( )
00554 // Move up to the parent node.
00555 {
00556     BdbHandle(BdbTreeNodeP) theParentP;
00557     BdbStatus result = persistent( )->parent( theParentP );
00558     setPersistent( theParentP );
00559     return result;
00560 }
00561 
00562 BdbStatus 
00563 BdbTreeNode::moveToRoot( const char* const theRootName )
00564 // Move to the root node with the specified name. The default is "main".
00565 {
00566     BdbHandle(BdbPersObj) theObj; 
00567     BdbHandle(BdbTreeNodeP) theRootP; 
00568     const char* theSysName = lowerRootName( theRootName );
00569     BdbStatus result = theObj.lookupObj( BdbApplicationOrDomain::activeInstance()->fd(), theSysName, BdbcRead );
00570     if ( BdbcSuccess == result ) {
00571 
00572         if ( ! BdbTreeNodeP::isTreeNode( theObj ) ) {
00573             BdbSignal( BdbcUserError, BdbTreesErrRootTreeNodeWrongType, 0, 
00574                        "BdbTreeNode::root", theRootName );
00575             result = BdbcError;
00576         } else {
00577             theRootP = (BdbHandle(BdbTreeNodeP)&)theObj;
00578         }
00579         setPersistent( theRootP );
00580     }
00581     return result;
00582 }
00583 
00584 BdbStatus
00585 BdbTreeNode::moveToRootChild( const char* const theChildName, 
00586                               const char* const theRootName )
00587 // Locate the tree node having the specified name as a child of the named root 
00588 // tree node. This is a convenience function. The default root is "main".
00589 {
00590     BdbStatus result = moveToRoot( theRootName);
00591     if ( BdbcSuccess == result ) {
00592         result = moveTo( theChildName );
00593     }
00594     return result;
00595 }
00596 
00597 BdbStatus 
00598 BdbTreeNode::makeTo( const char* const thePath, d_Boolean createIntermediate )
00599 // Move this transient tree node to reference the persistent tree node
00600 // that corresponds to the specified path. This obeys Unix file syntax.
00601 // An absolute path begins with the "/" character. A relative path omits
00602 // the leading "/" character. Moving up the tree is denoted by "../".
00603 // The "createIntermediate" flag determines whether any intermediate nodes
00604 // are created if required, or only the final destination node.
00605 {
00606     BdbTreeNode theNode;
00607     BdbHandle(BdbTreeNodeP) theNodeP;
00608     char        theFragment[256];
00609     const char* fragmentStart = thePath;
00610     const char* fragmentEnd   = thePath;
00611     size_t      fragmentLength;
00612     BdbStatus   result = BdbcSuccess;
00613 
00614     if ( NULL != thePath ) {
00615         if ( ! isNull( ) ) {
00616             theNode = *this;
00617             setNull( );
00618         }
00619         result = BdbcError;
00620         if ( BdbPathName::separator() == *thePath ) {
00621 
00622             // Absolute path - Look to see whether the new path is
00623             // identical to this one
00624             if ( ! theNode.isNull( ) && ( 0 == strcmp( thePath, theNode.fullName( ) ) ) ) {
00625 
00626                 // It's identical - no movement or creation is necessary
00627                 COUT1 << "BdbTreeNode::makeTo: Cached path" << endl;
00628                 result = BdbcSuccess;
00629             } else {
00630 
00631                 // It's not identical - Locate & create if necessary the
00632                 // root tree-node.
00633                 theNode.makeRoot( );
00634                 fragmentStart++;
00635             }
00636         }
00637         if ( BdbcSuccess != result ) {
00638 
00639             // Traverse and create the path
00640             result = BdbcSuccess;
00641             while ( ( BdbcSuccess == result ) && 
00642                     ( NULL != ( fragmentEnd = strchr( fragmentStart, BdbPathName::separator() ) ) ) ) {
00643                 fragmentLength = fragmentEnd - fragmentStart;
00644                 if ( 0 < fragmentLength ) {
00645                     strncpy( theFragment, fragmentStart, fragmentLength );
00646                     theFragment[fragmentLength] = '\0';
00647                     result = theNode.moveOneLevel( theFragment, createIntermediate );
00648                }
00649                 fragmentStart = fragmentEnd + 1;
00650             }
00651             if ( BdbcSuccess == result ) {
00652 
00653                 // Deal with last fragment
00654                 fragmentLength = strlen( fragmentStart );
00655                 if ( 0 < fragmentLength ) {
00656                     result = theNode.moveOneLevel( fragmentStart, d_True );
00657                 }
00658             }
00659         }
00660         if ( BdbcSuccess == result ) {
00661             *this = theNode;
00662         }
00663     }
00664     return result;
00665 }
00666 
00667 BdbStatus 
00668 BdbTreeNode::makeRoot( const char* const theRootName, 
00669                        const char* const placementContName )
00670 // Locate & create if necessary the root tree node with the specified
00671 // name. The default is "main".
00672 {
00673     BdbStatus result = BdbcSuccess;
00674     BdbApplicationOrDomain* theApp = BdbApplicationOrDomain::activeInstance( );
00675 
00676     result = moveToRoot( theRootName );
00677     if ( BdbcSuccess != result ) {
00678 
00679         // Root tree node doesn't already exist. Close the current transaction
00680         // and start a new one to try to get sole access to the root container.
00681         theApp->commit("makeRoot") ;
00682         theApp->startUpdate("makeRoot") ;
00683 
00684         BdbHandle(BdbDBObj) dbH;
00685         BdbDbAccessMgr dbAccessMgr;
00686         dbAccessMgr.openManagementDb( dbH, BdbcUpdate );
00687 
00688         BdbContAccessMgr contAccessMgr;
00689         BdbHandle(BdbContObj) contH;
00690         result = contAccessMgr.createContainer(dbH, contH, 
00691                                                placementContName, 1, 10, 10);
00692         if ( BdbcSuccess == result ) {
00693 
00694             // Now have guaranteed sole access to the root node container.
00695             // Check that the root node hasn't been created by someone else
00696             if ( BdbcSuccess != moveToRoot( theRootName ) ) {
00697                 BdbHandle(BdbTreeNodeP) theRootP;
00698                 theRootP = new(contH) BdbTreeNodeP( theRootName );
00699                 if ( ! BdbIsNull( theRootP ) ) {
00700                     const char* theSysName = lowerRootName( theRootName );
00701                     BdbHandle(BdbFDObj) theFD = BdbApplicationOrDomain::activeInstance()->fd( );
00702                     result = theRootP.nameObj( theFD, theSysName );
00703                     if ( BdbcSuccess == result ) {
00704                         setPersistent( theRootP );
00705                     } else {
00706                         BdbSignal( BdbcUserError, BdbTreesErrUnableToNameRootTreeNode, 0, 
00707                                    "BdbTreeNode::makeRoot", theRootName );
00708                     }
00709                 } else {
00710                     BdbSignal( BdbcUserError, BdbTreesErrUnableToCreateRootTreeNode, 0, 
00711                                "BdbTreeNode::makeRoot", theRootName );
00712                     result = BdbcError;
00713                 }
00714             }
00715         }
00716         theApp->commit("makeRoot") ;
00717         theApp->startUpdate("makeRoot") ;
00718     }
00719     if ( BdbcSuccess != result ) {
00720         result = moveToRoot( theRootName );
00721     }
00722     return result;
00723 }
00724     
00725 BdbStatus
00726 BdbTreeNode::makeRootChild( const char* const theChildName,
00727                             const char* const theRootName )
00728 // Locate and create if necessary the tree node having the specified name as a
00729 // child of the named root tree node. This is a convenience function. The
00730 // default root is "main".
00731 {
00732     BdbStatus result = makeRoot( theRootName);
00733     if ( BdbcSuccess == result ) {
00734         result = makeTo( theChildName );
00735     }
00736     return result;
00737 }
00738 
00739 BdbStatus
00740 BdbTreeNode::makeRootChild( const char* const theName,
00741                            const char* const theRootName,
00742                            BdbHandleAny& placement )
00743 {
00744     BdbStatus result = moveToRoot(theRootName) ;
00745     if ( result != BdbcSuccess ) {
00746         return BdbSignal(BdbcUserError, BdbTreesErrFunctionFailed, 0, "BdbTreeNode::makeRootChild", "in moveToRoot") ;
00747     }
00748 
00749     const char* useName = theName;
00750 
00751     // Deal with <user> as special (replaced by real user name
00752     if ( 0 == strcmp( useName, "<user>" ) ) {
00753          useName = BdbDomain::userName( );
00754     }
00755     BdbHandle(BdbTreeNodeP) theParentP = persistent( );
00756     result = child( *this, useName );
00757     if ( BdbcSuccess != result) {
00758 
00759         // Child doesn't exist - create it
00760         BdbApplicationOrDomain* theApp = BdbApplicationOrDomain::activeInstance( );
00761         result = theApp->updateAndWait( placement, "BdbTreeNode" );
00762         if ( BdbcSuccess == result ) {
00763             BdbHandle(BdbTreeNodeP) theNodeP;
00764             theNodeP = new(placement) BdbTreeNodeP( theParentP, useName );
00765             if ( ! BdbIsNull( theNodeP ) ) {
00766                 setPersistent( theNodeP );
00767                 result = theParentP->replace( theNodeP, useName );
00768             }
00769         } else {
00770             BdbSignal( BdbcUserError, BdbTreesErrUpdateFailed, 0, 
00771                        "BdbTreeNode::makeRootChild" );
00772         }
00773     }
00774     return result;
00775 }
00776 
00777 BdbStatus 
00778 BdbTreeNode::fetchMetaData( BdbMetaData& theData )
00779 {
00780     BdbHandle(BdbMetaDataP) theDataP;
00781     BdbStatus result = updateAndWait( );
00782     if (BdbcSuccess == result ) {
00783         result = persistent( )->fetchMetaData( theDataP );
00784         if ( BdbcSuccess == result ) {
00785             theData.setPersistent( theDataP );
00786         }
00787     }
00788     return result;
00789 }
00790 
00791 BdbStatus 
00792 BdbTreeNode::metaData( BdbMetaData& theData ) const
00793 {
00794     BdbHandle(BdbMetaDataP) theDataP;
00795     BdbStatus result = persistent( )->metaData( theDataP );
00796     theData.setPersistent( theDataP );
00797     return result;
00798 }
00799 
00800 BdbHandle(BdbTreeNodeP) 
00801 BdbTreeNode::persistent( ) const
00802 {
00803     BdbHandle(BdbTreeNodeP) h = (BdbHandle(BdbTreeNodeP)&) object( );
00804     
00805     assert( ! BdbIsNull( h ) );
00806 
00807     if ( BdbcSuccess != h.open(oocRead) ) {
00808         BdbApplicationOrDomain* theApp = BdbApplicationOrDomain::activeInstance();
00809         d_Long oldWait = theApp->lockWait( );
00810         d_ULong lw = (oldWait<300 ? 300 : oldWait); // wait up to 5 min
00811         ErrMsg( warning ) << "Problems with opening " << h.sprint() 
00812                           << " for reading, retrying once"
00813                           << " (lockWait = " << lw << " sec)" << endmsg;
00814         theApp->setLockWait(lw);
00815         if ( BdbcSuccess != h.open(oocRead) ) {
00816             ErrMsg( fatal ) << "Unable to lock " << h.sprint() 
00817                             << " for reading, fd "
00818                             << theApp->fd().sprint() << endmsg;
00819         }
00820         theApp->setLockWait( oldWait );
00821     }
00822     ooRef(ooObj) r = h;
00823     _tnLock->add(r);
00824 
00825     return h;
00826 }
00827 
00828 //-------------
00829 // Operators --
00830 //-------------
00831 
00832 BdbTreeNode& 
00833 BdbTreeNode::operator=( const BdbTreeNode& theOther )
00834 {
00835     BdbHandleAny theObj = theOther.object( );
00836     setObject( theObj );
00837     return *this;
00838 }
00839 
00840 //      -------------------------------------------
00841 //      -- Protected Function Member Definitions --
00842 //      -------------------------------------------
00843 
00844 const char* 
00845 BdbTreeNode::lowerRootName( const char* const theRootName )
00846 // Return the root name in lower case.
00847 {
00848     static BdbTString theSysName;
00849     char lowerName[256];
00850     size_t len = strlen( theRootName );
00851     for ( size_t i = 0; i < len; i++ ) {
00852         lowerName[i] = tolower( theRootName[i] );
00853     }
00854     lowerName[len] = '\0';
00855     theSysName     = "BdbTreeNodeP::";
00856     theSysName    += lowerName;
00857     return theSysName.data( );
00858 }
00859 
00860 BdbStatus
00861 BdbTreeNode::moveOneLevel( const char* const theName,
00862                            d_Boolean createIfNeeded )
00863 {
00864     BdbTreeNode theNode;
00865     BdbStatus result = BdbcError;
00866     const char* useName = theName;
00867 
00868     if ( 0 == strcmp( useName, ".." ) ) {
00869 
00870         // Move up to parent
00871         result = parent( theNode );
00872     } else {
00873 
00874         // Deal with <user> as special (replaced by real user name)
00875          if ( 0 == strcmp( useName, "<user>" ) ) {
00876              useName = BdbDomain::userName( );
00877         }
00878 
00879         // Test whether the child node already exists
00880         result = child( theNode, useName );
00881         if ( ( BdbcSuccess != result ) && createIfNeeded ) {
00882 
00883             // The child node doesn't exist - Check whether the name is used
00884             if ( ! hasChild( useName ) ) {
00885 
00886                 BdbHandleAny theHint = BdbTreeNodeP::clustering.updatedHint( );
00887                 if( theHint.isNull() ) {
00888                    return( BdbcError );
00889                 }
00890  
00891                 // Make sure that we have update locks on both the
00892                 // placement and parent node.
00893                 BdbHandle(BdbTreeNodeP) parentHandle( persistent() );
00894                 if ( BdbcSuccess != parentHandle.update() ) {
00895                    return( BdbcError );
00896                 }
00897 
00898                 if ( BdbcSuccess != theHint.update() ) {
00899                    return( BdbcError );
00900                 }
00901 
00902                 // Now that we have an update lock on the tree node,
00903                 // check again that the requested child doesn't exist in
00904                 // case someone else got there while we were waiting for
00905                 // the lock.
00906                 result = child( theNode, useName );
00907                 if ( BdbcSuccess != result ) {
00908 
00909                    // Child still doesn't exist - create it and add it
00910                    // to the node
00911                    BdbHandle(BdbTreeNodeP) theNodeP;
00912                    theNodeP = new(theHint) BdbTreeNodeP( parentHandle,
00913                                                          useName );
00914                    if( theNodeP.isNull() ) {
00915                       return( BdbcError );
00916                    }
00917 
00918                    theNode.setPersistent( theNodeP );
00919                    result = parentHandle->replace( theNodeP, useName );
00920                 }
00921             }
00922         }
00923     }
00924     if ( BdbcSuccess == result ) {
00925         *this = theNode;
00926     }
00927     return result;
00928 }
00929 
00930 void
00931 BdbTreeNode::setPersistent( BdbHandle(BdbTreeNodeP)& aNode )
00932 {
00933     setObject( aNode );
00934 }
00935 
00936 BdbStatus
00937 BdbTreeNode::updateAndWait( )
00938 // Lock the node for sole access. In order to avoid deadlocks
00939 // do not wait indefinitely for the lock, but try for up to a default
00940 // timeout period.
00941 {
00942     BdbApplicationOrDomain* theApp = BdbApplicationOrDomain::activeInstance( );
00943     BdbHandle(BdbTreeNodeP) theNodeP = persistent( );
00944     BdbStatus result = theApp->updateAndWait( theNodeP, "update" );
00945     if ( BdbcSuccess != result ) {
00946         BdbSignal( BdbcUserError, BdbTreesErrTreeUnableToUpdate, 0, 
00947                    "BdbTreeNode::updateAndWait", name( ) );
00948     }
00949     return result;
00950 }
00951 
00952 
00953 void 
00954 BdbTreeNode::startRecordingRLocks()
00955 {
00956     _tnLock->startRecording();
00957 }
00958 
00959 
00960 void
00961 BdbTreeNode::dropRecordedRLocks()
00962 {
00963     _tnLock->stopRecordingAndUnlock();
00964 }
00965 

 


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

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