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

CdbBdbObjectProfilerImpl.cc

Go to the documentation of this file.
00001 // File and Version Information:
00002 //      $Id: CdbBdbObjectProfilerImpl.cc,v 1.5 2004/10/21 20:35:50 gapon Exp $
00003 #include "BaBar/BaBar.hh"
00004 
00005 /// The implementation of the CdbBdbObjectProfilerImpl.
00006 /**
00007   * @see CdbBdbObjectProfilerImpl
00008   */
00009 
00010 #include "BaBar/BaBar.hh"
00011 
00012 #include "CdbBdb/CdbBdbObjectProfilerImpl.hh"
00013 
00014 #include "CdbBdb/CdbBdbObjectProfilerUserAction.hh"
00015 #include "CdbBdb/CdbBdbSimpleCache.hh"
00016 
00017 #include <assert.h>
00018 
00019 #include <iostream>     // Use STD I/O streams to avoid conflicts with
00020                         // Objectivity/DB Active Schema API caused by a bug
00021                         // in its header file at version 7.
00022 
00023 #include <ooMap.h>      // Objectivity/DB core API for the Map Dictionary class
00024 using std::cerr;
00025 using std::cout;
00026 using std::endl;
00027 
00028 
00029 //////////////////////////////////////
00030 // CdbBdbObjectProfilerImpl::Prefix //
00031 //////////////////////////////////////
00032 
00033 CdbBdbObjectProfilerImpl::Prefix::Prefix(               int& theLevel,
00034                                          const std::string& theStep ) :
00035     _level(theLevel),
00036     _str  ("")
00037 {
00038     ++_level;
00039     for( int i = 0; i < _level; ++i ) _str += theStep;
00040 }
00041 
00042 CdbBdbObjectProfilerImpl::Prefix::~Prefix( )
00043 {
00044     --_level;
00045 }
00046         
00047 const char*
00048 CdbBdbObjectProfilerImpl::Prefix::c_str( ) const
00049 {
00050     return _str.c_str( );
00051 }
00052 
00053 ///////////////////////
00054 // CdbBdbObjectProfiler //
00055 ///////////////////////
00056 
00057 CdbBdbObjectProfilerImpl::CdbBdbObjectProfilerImpl( CdbBdbObjectProfilerUserAction* theUserAction,
00058                                                                                bool verboseMode,
00059                                                                                bool debugMode ) :
00060     _verboseMode(verboseMode),
00061     _debugMode  (debugMode),
00062     _userAction (theUserAction),
00063     _dictionary (new CdbBdbSimpleCache( )),
00064     _level      (0),
00065     _size       (0),
00066     _topObjects (0)
00067 {
00068     if( 0 == theUserAction ) {
00069         cerr << "CdbBdbObjectProfilerImpl::CdbBdbObjectProfilerImpl() -- a null pointer instead of a user action object" << endl
00070              << "passed to the method." << endl;
00071         ::abort( );
00072     }
00073 
00074   // Force verbose mode if the debug mode is srequired
00075 
00076     if( _debugMode ) _verboseMode = true;
00077 }
00078 
00079 CdbBdbObjectProfilerImpl::~CdbBdbObjectProfilerImpl( )
00080 {
00081     if( 0 != _dictionary ) {
00082         delete _dictionary;
00083         _dictionary = 0;
00084     }
00085 }
00086 
00087 bool
00088 CdbBdbObjectProfilerImpl::profile( const ooHandle(ooObj)& theInputH )
00089 {
00090     const char* context = "CdbBdbObjectProfilerImpl::profile() : ";
00091 
00092   // Accept only valid objects to begin with
00093 
00094     if( !theInputH.isValid( )) {
00095         cerr << context << "ERROR: invalid object passed to the procedure: " << theInputH.sprint( ) << endl;
00096         return false;
00097     }
00098 
00099   // Reset the profiler's context
00100 
00101     _level = 0;
00102 
00103   // Proceed with the copy
00104 
00105     return profileObject( theInputH );
00106 }
00107 
00108 CdbBdbObjectProfilerUserAction*
00109 CdbBdbObjectProfilerImpl::setUserAction( CdbBdbObjectProfilerUserAction* theUserAction )
00110 {
00111     if( 0 == theUserAction ) {
00112         cerr << "CdbBdbObjectProfilerImpl::setUserAction() -- a null pointer instead of a user action object" << endl
00113              << "passed to the method." << endl;
00114         ::abort( );
00115     }
00116     CdbBdbObjectProfilerUserAction* previousAction = _userAction;
00117     _userAction = theUserAction;
00118 
00119     return previousAction;
00120 }
00121 
00122 uint64
00123 CdbBdbObjectProfilerImpl::getSize( ) const
00124 {
00125     return _size;
00126 }
00127 
00128 uint64
00129 CdbBdbObjectProfilerImpl::getTopObjects( ) const
00130 {
00131     return _topObjects;
00132 }
00133 
00134 bool
00135 CdbBdbObjectProfilerImpl::profileObject( const ooHandle(ooObj)& theInputH )
00136 {
00137     const char* context = "CdbBdbObjectProfilerImpl::profileObject() : ";
00138 
00139     Prefix prefix( _level );
00140 
00141 ////////////////////////////////////////////////////////////////
00142 if( _verboseMode ) {
00143     std::string  inStr = theInputH.sprint( );
00144     cout << prefix.c_str( ) << inStr.c_str( ) << " >> " << endl;
00145 }
00146 ////////////////////////////////////////////////////////////////
00147 
00148   // Simply ignore the null objects. It's not a error conditions since its quite
00149   // normal for persistent objects to have null references.
00150 
00151     if( theInputH == 0 ) {
00152 
00153 /////////////////////////////////////////////////////////////////////////////////////////////////////
00154 if( _verboseMode ) {
00155     std::string  inStr = theInputH.sprint( );
00156     cout << prefix.c_str( ) << inStr.c_str( ) << " (NULL) \"\"" << endl;
00157 }
00158 /////////////////////////////////////////////////////////////////////////////////////////////////////
00159 
00160     } else {
00161 
00162       // Find an object in the transient cache first if the cache is present
00163       // in the current test's environment.
00164 
00165         if( 0 != _dictionary->findObject( theInputH )) {
00166 
00167 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00168 if( _verboseMode ) {
00169     std::string  inStr = theInputH.sprint( );
00170     cout << prefix.c_str( ) << inStr.c_str( ) << " (CACHED) \"" << theInputH.typeName( ) << "\"" << endl;
00171 }
00172 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00173 
00174         } else {
00175 
00176           // Engage a user action to see what has to be done next
00177 
00178             switch( _userAction->action( theInputH )) {
00179 
00180             default :
00181 
00182                 cerr << context << "ERROR: unrecognized user action for: " << theInputH.sprint( ) << endl;
00183                 ::abort( );
00184 
00185             case CdbBdbObjectProfilerUserAction::ACTION_ERROR :
00186 
00187                 cerr << context << "ERROR: user action failed for: " << theInputH.sprint( ) << endl;
00188                 return false;
00189 
00190             case CdbBdbObjectProfilerUserAction::ACTION_STOP :
00191 
00192                 _dictionary->addObject( theInputH, theInputH );
00193 
00194 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00195 if( _verboseMode ) {
00196     std::string  inStr = theInputH.sprint( );
00197     cout << prefix.c_str( ) << inStr.c_str( ) << " (STOP BY USER ACTION)" << endl;
00198 }
00199 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00200 
00201                 break;
00202 
00203             case CdbBdbObjectProfilerUserAction::ACTION_PROCEED :
00204 
00205                 {
00206                   // Now we're diving into another object which has been successfully
00207                   // validated by the user action.
00208 
00209 
00210                   // Check for special case of the ooMap class. Use regular (as opposed to the Active
00211                   // Schema API) to browse the map.
00212                   //
00213                   // IMPLEMENTATION NOTE: In theory this operation could also be resolved for
00214                   //                      user defined subclasses of the ooMap class. Besides we have
00215                   //                      a set of other internal classes defined by Objectivity itself
00216                   //                      (containers, sets, B-Trees, etc.) It's unclear whether they
00217                   //                      can also be browsed in this way.
00218 
00219                     ooTypeNumber typeN = theInputH.typeN( );
00220 
00221                     if( ooTypeN(ooMap) == typeN ) {
00222 
00223                         ooHandle(ooMap) inputMapH;      // non-const handle is needed to set up an iterator
00224                         inputMapH = (ooHandle(ooMap))theInputH;
00225 
00226                       // ATTENTION: update the cache _before_ copying the object to prevent
00227                       //            "profile self" loop. This may cause crashes in the algorithm.
00228 
00229                         _dictionary->addObject( theInputH, theInputH );
00230 
00231 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00232 if( _verboseMode ) {
00233     std::string  inStr = theInputH.sprint( );
00234     cout << prefix.c_str( ) << inStr.c_str( ) << " (PROFILE) \"" << theInputH.typeName( ) << "\"" << endl;
00235 }
00236 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00237 
00238                         {
00239                             ooMapItr itr( inputMapH );
00240                             while( itr.next( )) {
00241 
00242                                 ooRef(ooObj) inputRef = itr->oid( );
00243 
00244                                 ooHandle(ooObj) inputH;
00245                                 inputH = inputRef;
00246 
00247                                 if( ! profileObject( inputH )) return false;
00248                             }
00249                         }
00250 
00251                     } else {
00252 
00253                       // Profile the persisten object using recursive algorithm.
00254                       //
00255                       // NOTE: The cast is needed as a workaround of the buggy interface
00256                       //       of the "ooas::Class_Object" class. It does not really need
00257                       //       non-const handle.
00258 
00259                         ooas::Class_Object classObj((ooHandle(ooObj)&)theInputH );
00260                         if( !classObj ) {
00261                             cerr << context << "ERROR: no ooas::Class_Object for the input object reference: " << theInputH.sprint( ) << endl;
00262                             ::abort( );
00263                         }
00264 
00265                       // ATTENTION: update the cache _before_ prifiling the object to prevent
00266                       //            "copy self" loop. This may cause crashes in the code.
00267 
00268                         _dictionary->addObject( theInputH, theInputH );
00269 
00270 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00271 if( _verboseMode ) {
00272     std::string  inStr = theInputH.sprint( );
00273     cout << prefix.c_str( ) << inStr.c_str( ) << " (PROFILE) \"" << theInputH.typeName( ) << "\"" << endl;
00274 }
00275 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00276 
00277                         if( !profileObjectContents( classObj, prefix )) return false;
00278 
00279                       // Update the counter of 'top-level' objects processed by the current
00280                       // object contents profiler.
00281                       //
00282                       // Note, that the constructor of Prefix class called at the begining
00283                       // of the current method would always increment the current level. That's
00284                       // why we're using '1' in the comparision expression below.
00285 
00286                         if( 1 == _level ) ++_topObjects;
00287                     }
00288                 }
00289             }
00290         }
00291     }
00292 
00293 ////////////////////////////////////////////////////////////////
00294 if( _verboseMode ) {
00295     std::string  inStr = theInputH.sprint( );
00296     cout << prefix.c_str( ) << inStr.c_str( ) << " << " << endl;
00297 }
00298 ////////////////////////////////////////////////////////////////
00299 
00300     return true;
00301 }
00302 
00303 bool
00304 CdbBdbObjectProfilerImpl::profileObjectContents( const ooas::Class_Object& theClassObject,
00305                                                              const Prefix& thePrefix )
00306 {
00307     if( !theClassObject ) {
00308         cerr << "CdbBdbObjectProfilerImpl::profileObjectContents() -- invalid class object passed to the method." << endl;
00309         ::abort( );
00310     }
00311 
00312   // Get the class object
00313 
00314     const ooas::d_Class& classDsc = theClassObject.type_of( );
00315 
00316   // We're only interested in a user defined (non-internal) classes.
00317 
00318     if( !classDsc.is_class   ( )) return true;
00319     if(  classDsc.is_internal( )) return true;
00320 
00321   // Browse all attributes
00322 
00323     {
00324         attribute_iterator itr = classDsc.defines_attribute_begin( );
00325         while( classDsc.defines_attribute_end( ) != itr ) {
00326 
00327             const ooas::d_Attribute& attrDsc = *itr;
00328 
00329             if( attrDsc.is_base_class( )) {
00330 
00331 ///////////////////////////////////////////////////////
00332 if( _debugMode ) {
00333     cout << thePrefix.c_str( ) << "BASE CLASS" << endl;
00334 }
00335 ///////////////////////////////////////////////////////
00336 
00337                 ooas::Class_Object inputClassObj = theClassObject.get_class_obj( attrDsc.position( ));
00338 
00339                 profileObjectContents( inputClassObj, thePrefix );
00340 
00341             } else if( attrDsc.is_relationship( )) {
00342 
00343                 const d_Relationship&     relDsc          = (const d_Relationship&)attrDsc;
00344                 ooas::Relationship_Object relationshipObj =  theClassObject.get_relationship( attrDsc.position( ));
00345                 assert( relationshipObj );  // an inconsistency bug in the Objectivity/DB Active Schema API
00346 
00347                 if( relDsc.is_to_many( )) {
00348 
00349 ///////////////////////////////////////////////////////////
00350 if( _debugMode ) {
00351     cout << thePrefix.c_str( ) << "n-RELATIONSHIP" << endl;
00352 }
00353 ///////////////////////////////////////////////////////////
00354 
00355                     uint32 num = 0;     // The cardinality of the association
00356 
00357                     ooItr(ooObj) itr;
00358                     relationshipObj.get_iterator( itr );
00359 
00360                     while( itr.next( )) {
00361 
00362                         ooHandle(ooObj) inputH;
00363                         inputH = itr;
00364 
00365                         if( !profileObject( inputH )) return false;
00366 
00367                         ++num;
00368                     }
00369                     if( 0 != num ) _size += num * sizeOfReference( );
00370 
00371                 } else {
00372 
00373 ///////////////////////////////////////////////////////////
00374 if( _debugMode ) {
00375     cout << thePrefix.c_str( ) << "1-RELATIONSHIP" << endl;
00376 }
00377 ///////////////////////////////////////////////////////////
00378 
00379                     ooHandle(ooObj) inputH;
00380                     inputH = relationshipObj.get_ooref( );
00381 
00382                     if( !profileObject(inputH )) return false;
00383 
00384                     _size += sizeOfReference( );
00385                 }
00386 
00387             } else {
00388 
00389                 const ooas::d_Type& typeDsc = attrDsc.type_of( );
00390 
00391                 size_t fixedArraySize = attrDsc.array_size( );
00392 
00393                 if( typeDsc.is_ref_type( )) {
00394 
00395 //////////////////////////////////////////////////////////////////
00396 if( _debugMode ) {
00397     cout << thePrefix.c_str( ) << "REFERENCE";
00398     if( fixedArraySize > 1 ) cout << "[" << fixedArraySize << "]";
00399     cout << endl;
00400 }
00401 //////////////////////////////////////////////////////////////////
00402 
00403                     for( size_t i = 0; i < fixedArraySize; ++i ) {
00404 
00405                         ooHandle(ooObj) inputH;
00406                         inputH = theClassObject.get_ooref( attrDsc.position( ), i );
00407 
00408                         if( !profileObject( inputH )) return false;
00409                     }
00410 
00411                     _size += fixedArraySize * sizeOfReference( );
00412 
00413                 } else if( typeDsc.is_basic_type( )) {
00414 
00415                     _size += fixedArraySize * sizeOfNumericValue( theClassObject.get( attrDsc.position( ), 0 ));
00416 
00417                 } else if( typeDsc.is_string_type( )) {     // It may also be an embedded string class,
00418                                                             // so we make this scheck before the next one.
00419 
00420                     for( size_t i = 0; i < fixedArraySize; ++i ) {
00421                         _size += sizeOfStringValue( theClassObject.get_string( attrDsc.position( ), i ));
00422                     }
00423 
00424                 } else if( typeDsc.is_class( ) && !typeDsc.is_string_type( )) {     // strings may also be represented
00425                                                                                     // by embedded classes.
00426 
00427 //////////////////////////////////////////////////////////////////
00428 if( _debugMode ) {
00429     cout << thePrefix.c_str( ) << "EMBEDDED OBJECT";
00430     if( fixedArraySize > 1 ) cout << "[" << fixedArraySize << "]";
00431     cout << endl;
00432 }
00433 //////////////////////////////////////////////////////////////////
00434 
00435                     for( size_t i = 0; i < fixedArraySize; ++i ) {
00436 
00437                         ooas::Class_Object inputClassObj = theClassObject.get_class_obj( attrDsc.position( ), i );
00438 
00439                         if( !profileObjectContents( inputClassObj, thePrefix )) return false;
00440                     }
00441 
00442                 } else if( typeDsc.is_varray_type( )) {
00443 
00444                     ooas::VArray_Object inputVArrayObject = theClassObject.get_varray( attrDsc.position( ));
00445 
00446                     uint32 varraySize = inputVArrayObject.size( );
00447 
00448                     if( typeDsc.is_varray_basic_type( )) {
00449 
00450 ///////////////////////////////////////////////
00451 if( _debugMode ) {
00452     cout << thePrefix.c_str( )
00453          << "V-ARRAY OF BASIC OBJECTS" << endl;
00454 }
00455 ///////////////////////////////////////////////
00456 
00457                       // Measure the size of the very first element only if there is at least one.
00458 
00459                         if( 0 != varraySize ) _size += varraySize * sizeOfNumericValue( inputVArrayObject.get( 0 ));
00460 
00461                     } else if( typeDsc.is_varray_ref_type( )) {
00462 
00463 ////////////////////////////////////////////
00464 if( _debugMode ) {
00465     cout << thePrefix.c_str( )
00466          << "V-ARRAY OF REFERENCES" << endl;
00467 }
00468 ////////////////////////////////////////////
00469 
00470                         for( uint32 i = 0; i < varraySize; ++i ) {
00471 
00472                             ooHandle(ooObj) inputH;
00473                             inputH = inputVArrayObject.get_ooref( i );
00474 
00475                             if( !profileObject( inputH )) return false;
00476                         }
00477 
00478                         _size += varraySize * sizeOfReference( );
00479 
00480 
00481                     } else if( typeDsc.is_string_type( )) {     // It may also be an embedded string class,
00482                                                                 // so we make this scheck before the next one.
00483 
00484 /////////////////////////////////////
00485 if( _debugMode ) {
00486 cout << thePrefix.c_str( )
00487      << "V-ARRAY OF STRINGS" << endl;
00488 }
00489 /////////////////////////////////////
00490 
00491                       // Measure each string's size
00492                       //
00493                       // NOTE: We know that in reality there is no such thing as "v-array of strings",
00494                       //       however we have to be consistent with the Objy API.
00495 
00496                         for( uint32 i = 0; i < varraySize; ++i )
00497                             _size += sizeOfStringValue( inputVArrayObject.get_string( i ));
00498 
00499                     } else if(  typeDsc.is_varray_embedded_class_type( ) &&
00500                                !typeDsc.is_string_type( )) {
00501 
00502 //////////////////////////////////////////////////
00503 if( _debugMode ) {
00504     cout << thePrefix.c_str( )
00505          << "V-ARRAY OF EMBEDDED OBJECTS" << endl;
00506 }
00507 //////////////////////////////////////////////////
00508 
00509                       // NOTE: In theory embedded objects should have the same size, so we could
00510                       //       speed up the profiling. Unfortunatelly it's hard to get this size
00511                       //       of these objects are of a hierarhical class and/or if these objects
00512                       //       have external references.
00513                       //
00514                       //       Therefore we're using the bruit force method when profiling these
00515                       //       objects.
00516 
00517                         for( uint32 i = 0; i < varraySize; ++i )
00518                             if( !profileObjectContents(  inputVArrayObject.get_class_obj( i ),
00519                                                          thePrefix )) return false;
00520 
00521                     } else {
00522 
00523                         bool isKnownTypeOfVarrayElements = false;
00524                         assert( isKnownTypeOfVarrayElements );
00525                     }
00526 
00527                 } else {
00528 
00529                     bool isKnownElementType = false;
00530                     assert( isKnownElementType );
00531                 }
00532             }
00533             ++itr;
00534         }
00535     }
00536     return true;
00537 }
00538 
00539 uint64
00540 CdbBdbObjectProfilerImpl::sizeOfNumericValue( const Numeric_Value& theNumericValue )
00541 {
00542     uint64 result = 0;
00543 
00544     ooBaseType baseType = theNumericValue.type( );
00545 
00546     switch( baseType ) {
00547 
00548     case ooCHAR    : result = 1; break;
00549     case ooINT8    : result = 1; break;
00550     case ooUINT8   : result = 1; break;
00551     case ooINT16   : result = 2; break;
00552     case ooUINT16  : result = 2; break;
00553     case ooINT32   : result = 4; break;
00554     case ooUINT32  : result = 4; break;
00555     case ooINT64   : result = 8; break;
00556     case ooUINT64  : result = 8; break;
00557     case ooFLOAT32 : result = 4; break;
00558     case ooFLOAT64 : result = 8; break;
00559     case ooPTR     : result = sizeof( void* );  break;
00560 
00561     default:
00562         {
00563             bool isKnownNumericType = false;
00564             assert( isKnownNumericType );
00565         }
00566     }
00567 
00568     return result;
00569 }
00570 
00571 uint64
00572 CdbBdbObjectProfilerImpl::sizeOfStringValue( String_Value theStringValue )
00573 {
00574     const char* context = "CdbBdbObjectProfilerImpl::sizeOfStringValue()";
00575 
00576   // Note, that when a null string is found then we're returning 1 byte
00577   // as the string size since this can also be treated as "user data".
00578 
00579     uint64 result = 0;
00580 
00581     switch( theStringValue.type( )) {
00582 
00583     case ooAsStringVSTRING:
00584         {
00585             ooVString* vStr = theStringValue;
00586             const char* str = (const char*)(*vStr);
00587             result = 1 + ( 0 == str ? 0 : strlen( str ));
00588             break;
00589         }
00590 
00591     case ooAsStringUTF8:
00592         {
00593             ooUtf8String* utf8Str = theStringValue;
00594             const char* str = (const char*)(*utf8Str);
00595             result = 1 + ( 0 == str ? 0 : strlen( str ));
00596             break;
00597         }
00598 
00599     case ooAsStringOPTIMIZED:
00600         {
00601           // NOTE: get_copy() allocates new string
00602 
00603             char* str = Optimized_String_Value(theStringValue).get_copy( );
00604             result = 1 + ( 0 == str ? 0 : strlen( str ));
00605             delete [] str;
00606             break;
00607         }
00608 
00609     case ooAsStringST:
00610         {
00611             cerr << context << " - a Smalltalk string found in an object. These strings can't be measured." << endl;
00612             ::exit( 1 );
00613         }
00614 
00615     default:
00616         {
00617             bool isKnownStringClass = false;
00618             assert( isKnownStringClass );
00619         }
00620     }
00621 
00622     return result;
00623 }
00624 
00625 uint64
00626 CdbBdbObjectProfilerImpl::sizeOfReference( )
00627 {
00628     return 8;
00629 }
00630 
00631 /////////////////
00632 // End Of File //
00633 /////////////////

Generated on Mon Dec 5 18:22:00 2005 for CDB by doxygen1.3-rc3