| # Gaudi Framework, version v23r1 |

Home |  | Generated: Wed Feb 29 2012

# 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