![]() |
|
|
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 /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