Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012

TESSerializer.cpp

Go to the documentation of this file.
00001 #include "GaudiMP/TESSerializer.h"
00002 
00003 // Framework include files
00004 #include "GaudiKernel/IRegistry.h"
00005 #include "GaudiKernel/IDataManagerSvc.h"
00006 #include "GaudiKernel/IDataProviderSvc.h"
00007 #include "GaudiKernel/LinkManager.h"
00008 #include "GaudiKernel/DataObject.h"
00009 #include "GaudiKernel/DataStoreItem.h"
00010 #include "GaudiKernel/System.h"
00011 #include "GaudiKernel/GaudiException.h"
00012 
00013 
00014 #include "GaudiKernel/IOpaqueAddress.h"
00015 #include "GaudiKernel/GenericAddress.h"
00016 #include "GaudiKernel/ClassID.h"
00017 #include "GaudiKernel/KeyedContainer.h"
00018 
00019 #include "GaudiKernel/MsgStream.h"
00020 
00021 // ROOT include files
00022 #include "TROOT.h"
00023 #include "TClass.h"
00024 #include "TInterpreter.h"
00025 #include "TBufferFile.h"
00026 
00027 #include <map>
00028 
00029 // a constant to guard against seg-faults in loadBuffer
00030 #define SERIALIZER_END "EOF"
00031 
00032 namespace {
00033   struct DataObjectPush {
00034     DataObjectPush(DataObject*& p) {
00035       Gaudi::pushCurrentDataObject(&p);
00036     }
00037     ~DataObjectPush() {
00038       Gaudi::popCurrentDataObject();
00039     }
00040   };
00041 }
00042 
00043 using namespace std;
00044 
00045 bool GaudiMP::TESSerializer::analyse(IRegistry* dir, int level)   {
00046   if ( level < m_currentItem->depth() )   {
00047     if ( dir->object() != 0 )   {
00048       m_objects.push_back(dir->object());
00049       return true;
00050     }
00051   }
00052   return false;
00053 }
00054 
00056 GaudiMP::TESSerializer::TESSerializer( IDataProviderSvc* svc, IAddressCreator* ac )
00057   : m_TES(svc)
00058   , m_TESMgr(dynamic_cast<IDataManagerSvc*>(svc))
00059   , m_currentItem(0)
00060   , m_verifyItems(false)
00061   , m_strict(false)
00062   , m_addressCreator(ac)
00063 {
00064 }
00065 
00067 void GaudiMP::TESSerializer::dumpBuffer(TBufferFile& buffer) {
00068   //
00069   //  Write all valid objects to the TBufferFile provided in the argument
00070   //  As objects are collected, the member variable m_classMap is filled
00071   //  with ROOT Class data, and is kept by the Serializer for future
00072   //  reference
00073   //
00074   //  @paramTBufferFile& buffer : TBufferFile passed by reference
00075   //          Cannot be declared inside the method, as repeated calls
00076   //          can cause confusion and buffer wiping.
00077   //
00078   StatusCode status;
00079   DataObject* obj;
00080 
00081   // Clear current selection
00082   m_objects.erase(m_objects.begin(), m_objects.end());
00083 
00084   // Traverse the tree and collect the requested objects
00085   for ( Items::iterator i = m_itemList.begin(); i != m_itemList.end(); i++ )    {
00086     m_currentItem = (*i);
00087     // cout << "Retrieving Mandatory Object : " << m_currentItem->path() << endl;
00088     status = m_TES->retrieveObject(m_currentItem->path(), obj);
00089     if ( status.isSuccess() )  {
00090       m_TESMgr->traverseSubTree(obj, this);
00091     }
00092     else  {
00093       string text("WARNING: Cannot retrieve TES object(s) for serialisation: ");
00094       text += m_currentItem->path();
00095       if ( m_strict ) {
00096         throw GaudiException(text + m_currentItem->path(), "", status);
00097       } else {
00098         cout << text << endl;
00099         // return StatusCode::FAILURE;
00100       }
00101     }
00102   }
00103   // Traverse the tree and collect the requested objects (tolerate missing items here)
00104   for ( Items::iterator i = m_optItemList.begin(); i != m_optItemList.end(); i++ )    {
00105     m_currentItem = (*i);
00106     // cout << "Retrieving Optional Object : " << m_currentItem->path() << endl;
00107     status= m_TES->retrieveObject(m_currentItem->path(), obj);
00108     if ( status.isSuccess() )  {
00109       m_TESMgr->traverseSubTree(obj, this);
00110     }
00111   }
00112 
00113   // cout << "TESSerializer : Beginning loop to write to TBufferFile for nObjects : " << m_objects.size() << endl;
00114   buffer.WriteInt(m_objects.size());
00115 
00116   for(Objects::iterator i = m_objects.begin(); i != m_objects.end(); ++i) {
00117     DataObject* pObj = (*i);    /* define pointer !pObj! to a data object */
00118     DataObjectPush p(pObj);             /* add the data object to the list... */
00119 
00120     // We build a map so gROOT has to access the whole class database as little as possible
00121     TClass* cl;                                                 /* announce a TClass */
00122     const type_info& objClass = typeid(*pObj);                  /* get the type of the data object */
00123     // cout << "TES Object : " << pObj->registry()->identifier() << endl;
00124     string objClassName = System::typeinfoName(objClass);       /* and then get the descriptive string from System */
00125 
00126     /* First go   : populate the class map
00127        Subsequent : refer to class map     */
00128     if (m_classMap[objClassName])   {
00129       cl=m_classMap[objClassName];
00130     } else {
00131       /* Map new object : pull the class name from the objects c_str() method */
00132       const char* clName = objClassName.c_str();
00133       /* Find the relevant Tclass (cl) in gROOT, and fill the map entry */
00134       cl = gROOT->GetClass(clName);
00135       m_classMap[objClassName]=cl;
00136     }
00137 
00138     /* Now, check if clname was valid... */
00139     if (cl==0){
00140       if ( m_strict ) {
00141         throw GaudiException("gROOT->GetClass cannot find clName", objClassName, StatusCode::FAILURE);
00142       } else  {
00143         cout << "WARNING: gROOT->GetClass fails for clname : "
00144             << objClassName.c_str() << endl;
00145         cout << "WARNING: Disregarding " << objClassName.c_str()
00146             << "erasing from object list" << endl;
00147         m_objects.erase( i );
00148         continue;
00149       }
00150     }
00151 
00152     // write object to buffer in order location-name-object
00153     std::string loc=pObj->registry()->identifier();
00154     buffer.WriteString(loc.c_str());
00155     buffer.WriteString(cl->GetName());
00156     cl->Streamer(pObj,buffer);
00157 
00158     /* take care of links */
00159     LinkManager* linkMgr = pObj->linkMgr();
00160     int numLinks = linkMgr->size();
00161     buffer.WriteInt(numLinks);
00162     // now write each link
00163     for (int it = 0; it != numLinks; it++)        {
00164       const string& link = linkMgr->link(it)->path();
00165       buffer.WriteString(link.c_str());
00166     }
00167 
00168     // now do the thing with the opaqueAddress
00169     // to go from string->object when recovering, will need svc_type, and clid, aswell as the string version
00170     IOpaqueAddress* iop = pObj->registry()->address();
00171     if (iop) {
00172       buffer.WriteInt(1);
00173       const string * par = iop->par();
00174       long svcType       = iop->svcType();
00175       long clid          = iop->clID();
00176       buffer.WriteLong(svcType);
00177       buffer.WriteLong(clid);
00178       buffer.WriteString(par->c_str());
00179     } else {
00180       buffer.WriteInt(0);
00181     }
00182     // object complete, continue in for-loop
00183   }
00184 
00185   // Final Actions
00186   // Write the End Flag, to avoid potential SegFaults on loadBuffer
00187   buffer.WriteString(SERIALIZER_END);
00188   // return StatusCode::SUCCESS;
00189 }
00190 
00192 void GaudiMP::TESSerializer::loadBuffer(TBufferFile& buffer) {
00193 
00194   // reverse mechanism of dumps
00195   // buffer is: length of DataObjects vector
00196   //            location string
00197   //            type name string
00198   //            the object itself
00199   //            count of links
00200   //            list of links (conditional on count)
00201   //            flag indicating Opaque Address presence
00202   //            Opaque Address svcType (conditional on flag)
00203   //            Opaque Address clID    (conditional on flag)
00204   //            Opaque Address par     (conditional on flag)
00205 
00206   int nObjects;
00207   // 3 StatusCodes... for :
00208   //   general use : registering objects : creating OpaqueAddresses
00209   StatusCode sc, registerStat, createAddressStat;
00210 
00211   // Prepare for Reading
00212   buffer.SetReadMode();
00213   buffer.SetBufferOffset();
00214 
00215   buffer.ReadInt(nObjects);
00216   for (int i=0; i<nObjects; ++i) {
00217     char text[4096];
00218     buffer.ReadString(text,sizeof(text));
00219     string location(text);
00220     if (!location.compare("EOF")) {
00221       /* There was an error in serialization, but the EOF
00222          flag marks the endpoint in any case */
00223       break;
00224     }
00225     buffer.ReadString(text,sizeof(text));
00226     TClass* cl = gROOT->GetClass(text);
00227     if (cl==0){
00228       if ( m_strict ) {
00229         throw GaudiException("gROOT->GetClass cannot find clName", text, StatusCode::FAILURE);
00230       } else {
00231         cout << "TESSerializer WARNING : gROOT->GetClass fails for clname : " << location.c_str() << endl;
00232         continue;
00233       }
00234     }
00235 
00237     DataObject* obj = (DataObject*)cl->New();
00238     DataObjectPush push(obj); // This is magic!
00239     cl->Streamer(obj, buffer);
00240 
00241 
00242     // now restore links
00243     if ( obj ) {
00244       int nlink = 0;
00245       LinkManager* lnkMgr = obj->linkMgr();
00246       buffer.ReadInt(nlink);
00247 
00248       for (int j = 0; j < nlink; ++j) {
00249         buffer.ReadString(text,sizeof(text));
00250         lnkMgr->addLink(text,0);
00251       }
00252     }
00253 
00254     // Re-register...
00255     registerStat = m_TES->registerObject(location, obj);
00256     if (registerStat.isFailure()) {
00257       DataObject* dummy = NULL;
00258       if ( location == "/Event" ) {
00259           sc = m_TESMgr->setRoot(location, obj);
00260           if(sc.isFailure())
00261              throw GaudiException("Cannot set root at location " + location, "", sc);
00262           }
00263       else {
00264           m_TES->findObject(location, dummy);
00265           if(!dummy)
00266             m_TES->registerObject(location, obj);
00267           else {
00268             // skipping to the next object
00269             // (flush the remaining metadata in the buffer)
00270             int flag(0);
00271             buffer.ReadInt(flag);
00272             if (flag) {
00273               long svcType;
00274               buffer.ReadLong(svcType);
00275               long clid;
00276               buffer.ReadLong(clid);
00277               buffer.ReadString(text, sizeof(text));
00278             }
00279             continue;
00280           }
00281         }
00282     }
00283     // next is the opaque address information
00284     // create Generic Address using the info from the TBufferFile,
00285     // then create an IOpaqueAddress object using the Persistency Svc
00286     // IOpaque Address pointer (blank... pass the ref to the createAddress Fn)
00287 
00288     int flag(0);
00289     buffer.ReadInt(flag);
00290     // flag will be 0 or 1 to indicate OpaqueAddress Info
00291     if (flag==1) {
00292       // will need an IOpaqueAddress and its ref
00293       IOpaqueAddress* iop;
00294       IOpaqueAddress*& iopref = iop;
00295       // Read svcType, clID and par from buffer
00296       long svcType;
00297       buffer.ReadLong(svcType);
00298 
00299       long clid;
00300       buffer.ReadLong(clid);
00301       const CLID classid(clid);
00302 
00303       char * cp;
00304       cp = buffer.ReadString(text, sizeof(text));
00305       const string opaque(cp);
00306       // create Generic address
00307       // already have svcType, clID, par1.. just make dummy variables for par2, and ipar1 and 2
00308       const string& p2="";
00309       unsigned long ip1(0);
00310       unsigned long ip2(0);
00311       GenericAddress gadd(svcType, classid, opaque, p2, ip1, ip2);
00312 
00313       // now create the address
00314       createAddressStat = m_addressCreator->createAddress( gadd.svcType(), gadd.clID(), gadd.par(), gadd.ipar(), iopref );
00315       if (createAddressStat.isFailure()) {
00316         throw GaudiException("Failure in creating OpaqueAddress for reconstructed registry", "", createAddressStat);
00317       }
00318       // And finally, set this address
00319       obj->registry()->setAddress(iop);
00320     }
00321     // all done
00322   }
00323 }
00324 
00325 // Protected
00327 void GaudiMP::TESSerializer::addItem(Items& itms, const std::string& descriptor)   {
00328   // supports # notation
00329   int level = 0;
00330 
00331   std::string slevel;
00332   std::string obj_path;
00333 
00334   // Process the incoming string
00335   size_t sep = descriptor.rfind("#");
00336   if (sep > descriptor.length()) {
00337     // invalid sep case (# not found in string)
00338     obj_path = descriptor;
00339     slevel   = "1";
00340   } else {
00341     // valid sep case
00342     obj_path = descriptor.substr(0,sep);
00343     slevel   = descriptor.substr(sep+1);
00344   }
00345 
00346   // Convert the level string to an integer
00347   if ( slevel == "*" )  {
00348     level = 9999999;
00349   }
00350   else   {
00351     level = atoi(slevel.c_str());
00352   }
00353 
00354   // Are we verifying?
00355   if ( m_verifyItems )  {
00356     size_t idx = obj_path.find("/",1);
00357     while(idx != std::string::npos)  {
00358       std::string sub_item = obj_path.substr(0,idx);
00359       if ( 0 == findItem(sub_item) )   {
00360         cout << "... calling addItem with arg : " << sub_item << endl;
00361         addItem(itms, sub_item);
00362       }
00363       idx = obj_path.find("/",idx+1);
00364     }
00365   }
00366   DataStoreItem* item = new DataStoreItem(obj_path, level);
00367   //cout << "Adding TESSerializer item " << item->path()
00368   //   << " with " << item->depth()
00369   //   << " level(s)." << endl;
00370   itms.push_back( item );
00371 }
00372 
00374 void GaudiMP::TESSerializer::addItem(const std::string& path)   {
00375   // #notation supported
00376   addItem( m_itemList, path );
00377 }
00378 
00380 void GaudiMP::TESSerializer::addOptItem(const std::string& path)   {
00381   // #notation supported
00382   addItem( m_optItemList, path);
00383 }
00384 
00386 void GaudiMP::TESSerializer::checkItems( )  {
00387   cout << "TESSerializer m_itemList : " << m_itemList.size() << " Items"<< endl;
00388   for(Items::const_iterator i=m_itemList.begin(); i != m_itemList.end(); ++i)  {
00389     cout << "\tItem : " << (*i)->path() << endl;
00390   }
00391   cout << "TESSerializer m_optItemList : " << m_optItemList.size() << " Items" << endl;
00392   for(Items::const_iterator i=m_optItemList.begin(); i != m_optItemList.end(); ++i)  {
00393     cout << "\tItem : " << (*i)->path() << endl;
00394   }
00395 }
00396 
00398 DataStoreItem*
00399 GaudiMP::TESSerializer::findItem(const std::string& path)  {
00400   for(Items::const_iterator i=m_itemList.begin(); i != m_itemList.end(); ++i)  {
00401     if ( (*i)->path() == path )  return (*i);
00402   }
00403   for(Items::const_iterator j=m_optItemList.begin(); j != m_optItemList.end(); ++j)  {
00404     if ( (*j)->path() == path )  return (*j);
00405   }
00406   return 0;
00407 }
00408 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Mon Sep 17 2012 13:49:35 for Gaudi Framework, version v23r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004