Gaudi Framework, version v22r0

Home   Generated: 9 Feb 2011

TESSerializer.cpp

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

Generated at Wed Feb 9 16:24:58 2011 for Gaudi Framework, version v22r0 by Doxygen version 1.6.2 written by Dimitri van Heesch, © 1997-2004