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  

/BdbApplMgmt/BdbContextPool.cc

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00002 // File:
00003 //      BdbContextPool.hh
00004 //
00005 // Description:
00006 //      Class BdbContextPool
00007 //
00008 //      The class manages a pool of ooContext objects and associated
00009 //      information.
00010 //
00011 // Environment:
00012 //      Software developed for the BaBar Detector at the SLAC B-Factory
00013 //
00014 // Author List:
00015 //      Igor Gaponenko          Original Author
00016 //
00017 // Copyright Information:
00018 //      Copyright (C) 1999      Lowrence Berkeley National Laboratory
00019 //
00020 //------------------------------------------------------------------------------
00021 
00022 //---------------
00023 // C++ headers --
00024 //---------------
00025 
00026 #include <iostream.h>
00027 #include <stdlib.h>
00028 #include <sys/time.h>
00029 #include <sys/resource.h>
00030 #include <stropts.h>
00031 #include <assert.h>
00032 
00033 //-----------------------
00034 // This Class's Header --
00035 //-----------------------
00036 
00037 #include "BdbApplMgmt/BdbContextPool.hh"
00038 
00039 // ------------------------------
00040 // Collaborating Class Headers --
00041 // ------------------------------
00042 
00043 #include "BdbApplMgmt/BdbApplicationErrors.hh"
00044 #include "BdbDomainOODB/BdbDomainOODB.hh"
00045 #include "BdbDomainOODB/BdbHandleCacheMgr.hh"
00046 
00047 extern void BaBarObjyMessageHandler(char*) ;
00048 extern ooStatus BaBarObjyErrorHandler(ooErrorLevel, ooError&, ooHandle(ooObj)*, char*) ;
00049 
00050 ///////////////////////////////////////////
00051 // Nested class Context:: implementation //
00052 ///////////////////////////////////////////
00053 
00054 BdbContextPool::Context::Context( d_ULong id,
00055                                   d_ULong nPages,
00056                                   d_ULong nMaxPages ) :
00057     _next(0),
00058     _prev(0),
00059     _prevInTransStack(0),
00060     _used(0),
00061     _reloaded(0),
00062     _need2reload(d_False),
00063     _transID( 0 ),
00064     _handleCache( 0 ),
00065     _id(id),
00066     _isAllocated(d_False),
00067     _transIsActive(d_False)
00068 {
00069 }
00070 
00071 BdbContextPool::Context::~Context( )
00072 {
00073     delete _theContext;
00074     delete _handleCache;
00075 }
00076 
00077 ////////////////////////////////
00078 // Evaluate reload conditions //
00079 ////////////////////////////////
00080 
00081 BdbStatus
00082 BdbContextPool::evaluateReloadConditions( )
00083 {
00084     struct rlimit rlp;
00085     int cur;
00086     int max;
00087     int use = 0;
00088     int fd;
00089 
00090   // STEP I: Obtain current limits of the number of file descriptors
00091   //         and current usage of the descriptors.
00092  
00093     if( 0 != getrlimit( RLIMIT_NOFILE, &rlp )) {
00094         return BdbcError;
00095     }
00096  
00097     cur = rlp.rlim_cur;
00098     max = rlp.rlim_max;
00099 
00100     for( fd = 0; fd < cur; fd++ ) {
00101 
00102         int state = isastream( fd );
00103  
00104         switch( state ) {
00105         case 0:
00106             use++;
00107             break;
00108         case 1:
00109             use++;
00110             break;
00111         }
00112     }
00113 
00114   // STEP II: increase the current limit if (both):
00115   //
00116   //    - it's required (75% CURRENT limit is reached)
00117   //    - it's possible (50% MAXIMUM limit is NOT reached)
00118   //
00119   //    NOTE: We will increase this limit by 25% of CURRENT limit
00120   //          but no more the
00121   //
00122 
00123 
00124     float usage = 100.0 * (float) use / (float) cur;
00125 
00126     if( usage < 75.0 ) {
00127         return BdbcSuccess;     // Not required.
00128     }
00129     
00130     float occupancy = 100.0 * (float) cur / (float) max;
00131     
00132     if( occupancy < 50.0 ) {
00133     
00134         int limit = (int) ( 0.5 * max );
00135         int increment = (int) ( 0.25 * cur );
00136 
00137         if(( cur + increment ) > limit ) {
00138             increment = limit - cur;
00139         }
00140 
00141         if( increment > 0 ) {
00142 
00143             rlp.rlim_cur = rlp.rlim_cur + increment;
00144 
00145             if( 0 != setrlimit( RLIMIT_NOFILE, &rlp )) {
00146                 return BdbcError;
00147             } else {
00148                 return BdbcSuccess;
00149             }
00150         } else {
00151             ;   // Proceed on the next step.
00152         }
00153     }
00154 
00155   // STEP II: We are running out of limit. IN this case we should
00156   //          turn on contexts reloading (delete/new) operation.
00157   //
00158   //    NOTE_1: In a current implementation of algorithm we will
00159   //            tell each context to reload himself just once.
00160   //
00161   //    NOTE_2: The context is told to be reloaded if it was ever
00162   //            been used.
00163 
00164     Context* ptr = _first;
00165 
00166     while( ptr != (Context*) 0 ) {
00167         if( 0 != ptr->_used ) {
00168             ptr->_need2reload = d_True;
00169         }
00170         ptr = ptr->_next;
00171     }
00172 
00173     return BdbcSuccess;
00174 }
00175 
00176 /////////////////////////////////////////////////
00177 // Print some context and fds usage statistics //
00178 /////////////////////////////////////////////////
00179 
00180 void
00181 BdbContextPool::printStatistics( const char* prefix, d_ULong level )
00182 {
00183     int status;
00184     struct rlimit rlp;
00185     int cur;
00186     int max;
00187     int nstreams = 0;   // Number of FDs associated with streams.
00188     int nothers = 0;    // Number of FDs associated with something else.
00189     int fd;
00190 
00191   // Just do nothing if the statistics monitor is not enabled.
00192 
00193     if( ! _statMonIsEnabled ) {
00194         return;
00195     }
00196 
00197     status = getrlimit( RLIMIT_NOFILE, &rlp );
00198  
00199     cur = rlp.rlim_cur;
00200     max = rlp.rlim_max;
00201   
00202     for( fd = 0; fd < cur; fd++ ) {
00203 
00204         int state = isastream( fd );
00205  
00206         switch( state ) {
00207         case 0:
00208             nothers++;
00209             break;
00210         case 1:
00211             nstreams++;
00212             break;
00213         }
00214     }
00215     
00216     cout << "BdbContextPool::printStatistics() - " << level << ":" << prefix << endl
00217          << "    max:" << max
00218          << " cur:" << cur
00219          << " ava:" << ( cur - nstreams - nothers )
00220          << " str:" << nstreams
00221          << " oth:" << nothers
00222          << endl;
00223 
00224     cout << "    used:";
00225 
00226     Context* ptr;
00227 
00228     ptr = _first;
00229     while( ptr != (Context*) 0 ) {
00230         cout << " " << ptr->_used;
00231         ptr = ptr->_next;
00232     }
00233     cout << endl;
00234 
00235     cout << "    contexts reloaded:";
00236 
00237     ptr = _first;
00238     while( ptr != (Context*) 0 ) {
00239         cout << " " << ptr->_reloaded;
00240         ptr = ptr->_next;
00241     }
00242     cout << endl;
00243 
00244     cout << "    need to reload contexts:";
00245 
00246     ptr = _first;
00247     while( ptr != (Context*) 0 ) {
00248         if( ptr->_need2reload ) {
00249             cout << " 1";
00250         } else {
00251             cout << " 0";
00252         }
00253         ptr = ptr->_next;
00254     }
00255     cout << endl;
00256 
00257 }
00258 
00259 /////////////////
00260 // Constructor //
00261 /////////////////
00262 
00263 BdbContextPool::BdbContextPool( d_ULong nContexts,
00264                                 d_ULong nPages,
00265                                 d_ULong nMaxPages) :
00266     _elements(0),
00267     _first(0),
00268     _current(0),
00269     _last(0),
00270     _depth(0),
00271     _nPages(nPages),
00272     _nMaxPages(nMaxPages),
00273     _statMonIsEnabled(d_False)
00274 {
00275     for( d_ULong i = 0; i < nContexts; i++ ) {
00276         allocate( );
00277     }
00278 
00279     char* str = getenv( "BDBCONTEXTPOOL_ENABLE_STATMON" );
00280 
00281     if( str != (char*) 0 ) {
00282         _statMonIsEnabled = d_True;
00283     }
00284 }
00285 
00286 ////////////////
00287 // Destructor //
00288 ////////////////
00289 
00290 BdbContextPool::~BdbContextPool()
00291 {
00292     Context* ptr = _first;
00293 
00294     while( ptr != (Context*) 0 ) {
00295         delete ptr;
00296         ptr = ptr->_next;
00297     }
00298 }
00299 
00300 d_ULong
00301 BdbContextPool::depth( )
00302 {
00303     return _depth;
00304 }
00305 
00306 ooHandle(ooFDObj)&
00307 BdbContextPool::fd( )
00308 {
00309     assert( 0 != _depth );
00310     return _current->_fdb;
00311 }
00312 
00313 d_ULong
00314 BdbContextPool::transID( )
00315 {
00316     assert( 0 != _depth );
00317     return _current->_transID;
00318 }
00319 
00320 BdbHandleCacheMgr*
00321 BdbContextPool::handleCache( )
00322 {
00323     assert( 0 != _depth );
00324     return _current->_handleCache;
00325 }
00326 
00327 void
00328 BdbContextPool::allocate( )
00329 {
00330   // Create an instance of a context object.
00331 
00332    // the '+ 1' means that 0 is NOT a valid ID for a context.
00333     Context* ptr = new Context( _elements + 1, _nPages, _nMaxPages );
00334     ptr->_theContext  = new ooContext( _nPages, _nMaxPages);
00335     ptr->_handleCache = new BdbHandleCacheMgr( );
00336 
00337   // Append a new element by the end of the list.
00338 
00339     if( _last != (Context*) 0 ) {
00340         _last->_next = ptr;
00341     }
00342     ptr->_prev = _last;
00343     ptr->_next = (Context*) 0;
00344 
00345   // Tune a "last" pointer to point onto the new element.
00346 
00347     _last = ptr;
00348 
00349   // If the first was not set yet - the set it
00350   // to point onto this (presumably) first element in the list.
00351     
00352     if( _first == (Context*) 0 ) {
00353         _first = _last;
00354     }
00355 
00356   // Increment the number of elements in a list
00357 
00358     _elements++;
00359 }
00360 
00361 BdbStatus
00362 BdbContextPool::allocate( d_ULong& id )
00363 {
00364   // Find out a spare (not allocated) context or allocate
00365   // a new one if not found.
00366 
00367     Context* ptr = _first;
00368 
00369     while( ptr != (Context*) 0 ) {
00370         if( ! ptr->_isAllocated ) {
00371 
00372             ptr->_isAllocated = d_True;
00373             id = ptr->_id;
00374 
00375             return BdbcSuccess;
00376         }
00377         ptr = ptr->_next;
00378     }
00379 
00380   // Alocate one more context.
00381 
00382     allocate( );
00383 
00384     _last->_isAllocated = d_True;
00385     id = _last->_id;
00386 
00387     return BdbcSuccess;
00388 }
00389 
00390 BdbStatus
00391 BdbContextPool::release( d_ULong id )
00392 {
00393   // Find out a spare (not allocated) context or allocate
00394   // a new one if not found.
00395 
00396     Context* ptr = _first;
00397 
00398     while( ptr != (Context*) 0 ) {
00399         if( id == ptr->_id ) {
00400 
00401             if( ! ptr->_isAllocated ) {
00402                 cout << "BdbContextPool::release() -- error." << endl
00403                      << "    The context with ID = " << id << " is not allocated." << endl;
00404                 return BdbcError;
00405             }
00406             if( ptr->_transIsActive ) {
00407                 cout << "BdbContextPool::release() -- error." << endl
00408                      << "    There is an active transaction for the context ID = " << id << endl;
00409                 return BdbcError;
00410             }
00411 
00412             ptr->_isAllocated = d_False;
00413             return BdbcSuccess;
00414         }
00415         ptr = ptr->_next;
00416     }
00417 
00418   // Print error because such a context was not found.
00419 
00420     cout << "BdbContextPool::release() -- error." << endl
00421          << "    The context with ID = " << id << " does not exists." << endl;
00422 
00423     return BdbcError;
00424 }
00425 
00426 BdbStatus
00427 BdbContextPool::start( d_ULong id, BdbMode theMode, ooIndexMode theIndexMode )
00428 {
00429     BdbStatus status = BdbcError;
00430 
00431   // Find out if such an id is in the list and it's marked as current.
00432 
00433     Context* ptr = _first;
00434 
00435     while( ptr != (Context*) 0 ) {
00436         if( id == ptr->_id ) {
00437 
00438             if( ! ptr->_isAllocated ) {
00439                 cout << "BdbContextPool::start() -- error." << endl
00440                      << "    The context with ID = " << id << " is not allocated." << endl;
00441                 return BdbcError;
00442             }
00443             if( ptr->_transIsActive ) {
00444                 cout << "BdbContextPool::start() -- error." << endl
00445                      << "    There is an active transaction for the context ID = " << id << endl;
00446                 return BdbcError;
00447             }
00448 
00449           // OK. We've got this.
00450 
00451             status = BdbcSuccess;
00452             break;
00453         }
00454         ptr = ptr->_next;
00455     }
00456     if( BdbcSuccess != status ) {
00457         cout << "BdbContextPool::start() -- error." << endl
00458              << "    The context with ID = " << id << " does not exists." << endl;
00459     }
00460 
00461   // Push the stack of nested transactions..
00462 
00463     ptr->_prevInTransStack = _current;
00464     _current = ptr;
00465 
00466   // Update use counter for this context.
00467   
00468     _current->_used++;
00469 
00470   // Switch context
00471 
00472     _current->_oldContext = ooContext::current( );
00473 
00474     ooContext::setCurrent( 0 );
00475     ooContext::setCurrent( _current->_theContext );
00476 
00477     ooRegMsgHandler( BaBarObjyMessageHandler );
00478     ooRegErrorHandler( BaBarObjyErrorHandler );
00479 
00480   // Start transction with first two parameters set
00481   // to default values and the third one - to a value
00482   // specified by a user.
00483   // Then open FDB in specified mode.
00484   // And finally increment the corresponding transaction ID.
00485 
00486     _current->_theTransaction.start( oocNoMROW, oocTransNoWait, theIndexMode );
00487     _current->_fdb.open( BdbDomainOODB::activeDomainOODB()->bootName(), theMode );
00488 
00489     (_current->_transID)++;
00490     _current->_transIsActive = d_True;
00491 
00492   // Increase current depth of the nested stack of transactions. Later on this value
00493   // will be decreased by "::stop".
00494 
00495     _depth++;
00496 
00497   // Print some statistics
00498 
00499     printStatistics( "START", _depth );
00500 
00501     return BdbcSuccess;
00502 }
00503 
00504 BdbStatus
00505 BdbContextPool::stop( d_ULong id, Action action )
00506 {
00507   // Remember a reference to the current context.
00508   // We will use this reference in the end of the procedure
00509   // in order to reload context (if desired).
00510     
00511     Context* cxt = _current;
00512 
00513   // Check if the current context is non-zero and if it has
00514   // the same identifier.
00515 
00516     if(( 0 == _depth ) || ( _current == (Context*) 0 )) {
00517         cout << "BdbContextPool::stop() -- error." << endl
00518              << "    No active transaction for context ID = " << id << endl;
00519         return BdbcError;
00520     }
00521     if( id != _current->_id ) {
00522         cout << "BdbContextPool::stop() -- error." << endl
00523              << "    Internal bug for the context ID = " << id << endl;
00524         return BdbcError;
00525     }
00526     
00527   // Check if the transaction is active.
00528 
00529     if( ! _current->_transIsActive ) {
00530         cout << "BdbContextPool::stop() -- error." << endl
00531              << "    No active transaction for the context ID = " << id << endl;
00532         return BdbcError;
00533     }
00534 
00535   // Finish current transaction.
00536 
00537     switch( action ) {
00538     case commitTransaction:
00539 
00540         _current->_theTransaction.commit( );
00541         break;
00542 
00543     case abortTransaction:
00544 
00545         _current->_theTransaction.abort( );
00546         break;
00547     }
00548 
00549   // Close federation
00550 
00551     _current->_fdb.close( );
00552 
00553   // Set back a previous context.
00554 
00555     ooContext::setCurrent( 0 );
00556     ooContext::setCurrent( _current->_oldContext );
00557 
00558   // Roll back the stack of transactions.
00559 
00560     _current->_transIsActive = d_False;
00561     _current = _current->_prevInTransStack;
00562 
00563     _depth--;
00564 
00565   // Print some statistics before evaluation and possible context reload.
00566   
00567     printStatistics( "STOP - before context reload", _depth + 1 );
00568 
00569   // Evaluare reload conditions and reload context if needed.
00570   
00571     BdbStatus status;
00572 
00573     status = evaluateReloadConditions( );
00574     if( BdbcSuccess != status ) {
00575         cout << "BdbContextPool::stop() - failed to evaluate reload conditions." << endl;
00576         return status;
00577     }
00578     
00579     if( cxt->_need2reload ) {
00580 
00581         delete cxt->_theContext;
00582         delete cxt->_handleCache;
00583 
00584         cxt->_theContext  = new ooContext( _nPages, _nMaxPages );
00585         cxt->_handleCache = new BdbHandleCacheMgr( );
00586 
00587         cxt->_reloaded++;
00588         cxt->_need2reload = d_False;
00589     }
00590 
00591   // Print some statistics after evaluation and possible context reload.
00592   
00593     printStatistics( "STOP - after  context reload", _depth + 1 );
00594    
00595     return BdbcSuccess;
00596 }
00597 
00598 /////////////////
00599 // End Of File //
00600 /////////////////

 


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

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