The Gaudi Framework  v29r0 (ff2e7097)
TESSerializer.cpp
Go to the documentation of this file.
2 
3 // Framework include files
11 #include "GaudiKernel/System.h"
12 
13 #include "GaudiKernel/ClassID.h"
17 
18 #include "GaudiKernel/MsgStream.h"
19 
20 // ROOT include files
21 #include "TBufferFile.h"
22 #include "TClass.h"
23 #include "TInterpreter.h"
24 #include "TROOT.h"
25 
26 #include <map>
27 
28 // a constant to guard against seg-faults in loadBuffer
29 #define SERIALIZER_END "EOF"
30 
31 namespace
32 {
33  struct DataObjectPush {
34  DataObjectPush( DataObject*& p ) { Gaudi::pushCurrentDataObject( &p ); }
35  ~DataObjectPush() { Gaudi::popCurrentDataObject(); }
36  };
37 }
38 
39 using namespace std;
40 
42 {
43  if ( level < m_currentItem->depth() ) {
44  if ( dir->object() != 0 ) {
45  m_objects.push_back( dir->object() );
46  return true;
47  }
48  }
49  return false;
50 }
51 
54  : m_TES( svc )
55  , m_TESMgr( dynamic_cast<IDataManagerSvc*>( svc ) )
56  , m_currentItem( 0 )
57  , m_verifyItems( false )
58  , m_strict( false )
59  , m_addressCreator( ac )
60 {
61 }
62 
64 void GaudiMP::TESSerializer::dumpBuffer( TBufferFile& buffer )
65 {
66  //
67  // Write all valid objects to the TBufferFile provided in the argument
68  // As objects are collected, the member variable m_classMap is filled
69  // with ROOT Class data, and is kept by the Serializer for future
70  // reference
71  //
72  // @paramTBufferFile& buffer : TBufferFile passed by reference
73  // Cannot be declared inside the method, as repeated calls
74  // can cause confusion and buffer wiping.
75  //
76  StatusCode status;
77  DataObject* obj;
78 
79  // Clear current selection
81 
82  // Traverse the tree and collect the requested objects
83  for ( Items::iterator i = m_itemList.begin(); i != m_itemList.end(); i++ ) {
84  m_currentItem = ( *i );
85  // cout << "Retrieving Mandatory Object : " << m_currentItem->path() << endl;
86  status = m_TES->retrieveObject( m_currentItem->path(), obj );
87  if ( status.isSuccess() ) {
88  m_TESMgr->traverseSubTree( obj, this );
89  } else {
90  string text( "WARNING: Cannot retrieve TES object(s) for serialisation: " );
91  text += m_currentItem->path();
92  if ( m_strict ) {
93  throw GaudiException( text + m_currentItem->path(), "", status );
94  } else {
95  cout << text << endl;
96  // return StatusCode::FAILURE;
97  }
98  }
99  }
100  // Traverse the tree and collect the requested objects (tolerate missing items here)
101  for ( Items::iterator i = m_optItemList.begin(); i != m_optItemList.end(); i++ ) {
102  m_currentItem = ( *i );
103  // cout << "Retrieving Optional Object : " << m_currentItem->path() << endl;
104  status = m_TES->retrieveObject( m_currentItem->path(), obj );
105  if ( status.isSuccess() ) {
106  m_TESMgr->traverseSubTree( obj, this );
107  }
108  }
109 
110  // cout << "TESSerializer : Beginning loop to write to TBufferFile for nObjects : " << m_objects.size() << endl;
111  buffer.WriteInt( m_objects.size() );
112 
113  for ( Objects::iterator i = m_objects.begin(); i != m_objects.end(); ++i ) {
114  DataObject* pObj = ( *i ); /* define pointer !pObj! to a data object */
115  DataObjectPush p( pObj ); /* add the data object to the list... */
116 
117  // We build a map so gROOT has to access the whole class database as little as possible
118  TClass* cl; /* announce a TClass */
119  const type_info& objClass = typeid( *pObj ); /* get the type of the data object */
120  // cout << "TES Object : " << pObj->registry()->identifier() << endl;
121  string objClassName = System::typeinfoName( objClass ); /* and then get the descriptive string from System */
122 
123  /* First go : populate the class map
124  Subsequent : refer to class map */
125  if ( m_classMap[objClassName] ) {
126  cl = m_classMap[objClassName];
127  } else {
128  /* Map new object : pull the class name from the objects c_str() method */
129  const char* clName = objClassName.c_str();
130  /* Find the relevant Tclass (cl) in gROOT, and fill the map entry */
131  cl = gROOT->GetClass( clName );
132  m_classMap[objClassName] = cl;
133  }
134 
135  /* Now, check if clname was valid... */
136  if ( cl == 0 ) {
137  if ( m_strict ) {
138  throw GaudiException( "gROOT->GetClass cannot find clName", objClassName, StatusCode::FAILURE );
139  } else {
140  cout << "WARNING: gROOT->GetClass fails for clname : " << objClassName.c_str() << endl;
141  cout << "WARNING: Disregarding " << objClassName.c_str() << "erasing from object list" << endl;
142  m_objects.erase( i );
143  continue;
144  }
145  }
146 
147  // write object to buffer in order location-name-object
148  std::string loc = pObj->registry()->identifier();
149  buffer.WriteString( loc.c_str() );
150  buffer.WriteString( cl->GetName() );
151  cl->Streamer( pObj, buffer );
152 
153  /* take care of links */
154  LinkManager* linkMgr = pObj->linkMgr();
155  int numLinks = linkMgr->size();
156  buffer.WriteInt( numLinks );
157  // now write each link
158  for ( int it = 0; it != numLinks; it++ ) {
159  const string& link = linkMgr->link( it )->path();
160  buffer.WriteString( link.c_str() );
161  }
162 
163  // now do the thing with the opaqueAddress
164  // to go from string->object when recovering, will need svc_type, and clid, aswell as the string version
165  IOpaqueAddress* iop = pObj->registry()->address();
166  if ( iop ) {
167  buffer.WriteInt( 1 );
168  const string* par = iop->par();
169  long svcType = iop->svcType();
170  long clid = iop->clID();
171  buffer.WriteLong( svcType );
172  buffer.WriteLong( clid );
173  buffer.WriteString( par->c_str() );
174  } else {
175  buffer.WriteInt( 0 );
176  }
177  // object complete, continue in for-loop
178  }
179 
180  // Final Actions
181  // Write the End Flag, to avoid potential SegFaults on loadBuffer
182  buffer.WriteString( SERIALIZER_END );
183  // return StatusCode::SUCCESS;
184 }
185 
187 void GaudiMP::TESSerializer::loadBuffer( TBufferFile& buffer )
188 {
189 
190  // reverse mechanism of dumps
191  // buffer is: length of DataObjects vector
192  // location string
193  // type name string
194  // the object itself
195  // count of links
196  // list of links (conditional on count)
197  // flag indicating Opaque Address presence
198  // Opaque Address svcType (conditional on flag)
199  // Opaque Address clID (conditional on flag)
200  // Opaque Address par (conditional on flag)
201 
202  int nObjects;
203  // 3 StatusCodes... for :
204  // general use : registering objects : creating OpaqueAddresses
205  StatusCode sc, registerStat, createAddressStat;
206 
207  // Prepare for Reading
208  buffer.SetReadMode();
209  buffer.SetBufferOffset();
210 
211  buffer.ReadInt( nObjects );
212  for ( int i = 0; i < nObjects; ++i ) {
213  char text[4096];
214  buffer.ReadString( text, sizeof( text ) );
215  string location( text );
216  if ( !location.compare( "EOF" ) ) {
217  /* There was an error in serialization, but the EOF
218  flag marks the endpoint in any case */
219  break;
220  }
221  buffer.ReadString( text, sizeof( text ) );
222  TClass* cl = gROOT->GetClass( text );
223  if ( cl == 0 ) {
224  if ( m_strict ) {
225  throw GaudiException( "gROOT->GetClass cannot find clName", text, StatusCode::FAILURE );
226  } else {
227  cout << "TESSerializer WARNING : gROOT->GetClass fails for clname : " << location.c_str() << endl;
228  continue;
229  }
230  }
231 
233  DataObject* obj = (DataObject*)cl->New();
234  DataObjectPush push( obj ); // This is magic!
235  cl->Streamer( obj, buffer );
236 
237  // now restore links
238  if ( obj ) {
239  int nlink = 0;
240  LinkManager* lnkMgr = obj->linkMgr();
241  buffer.ReadInt( nlink );
242 
243  for ( int j = 0; j < nlink; ++j ) {
244  buffer.ReadString( text, sizeof( text ) );
245  lnkMgr->addLink( text, 0 );
246  }
247  }
248 
249  // Re-register...
250  registerStat = m_TES->registerObject( location, obj );
251  if ( registerStat.isFailure() ) {
252  DataObject* dummy = NULL;
253  if ( location == "/Event" ) {
254  sc = m_TESMgr->setRoot( location, obj );
255  if ( sc.isFailure() ) throw GaudiException( "Cannot set root at location " + location, "", sc );
256  } else {
257  m_TES->findObject( location, dummy );
258  if ( !dummy )
259  m_TES->registerObject( location, obj );
260  else {
261  // skipping to the next object
262  // (flush the remaining metadata in the buffer)
263  int flag( 0 );
264  buffer.ReadInt( flag );
265  if ( flag ) {
266  long svcType;
267  buffer.ReadLong( svcType );
268  long clid;
269  buffer.ReadLong( clid );
270  buffer.ReadString( text, sizeof( text ) );
271  }
272  continue;
273  }
274  }
275  }
276  // next is the opaque address information
277  // create Generic Address using the info from the TBufferFile,
278  // then create an IOpaqueAddress object using the Persistency Svc
279  // IOpaque Address pointer (blank... pass the ref to the createAddress Fn)
280 
281  int flag( 0 );
282  buffer.ReadInt( flag );
283  // flag will be 0 or 1 to indicate OpaqueAddress Info
284  if ( flag == 1 ) {
285  // will need an IOpaqueAddress and its ref
286  IOpaqueAddress* iop;
287  IOpaqueAddress*& iopref = iop;
288  // Read svcType, clID and par from buffer
289  long svcType;
290  buffer.ReadLong( svcType );
291 
292  long clid;
293  buffer.ReadLong( clid );
294  const CLID classid( clid );
295 
296  char* cp;
297  cp = buffer.ReadString( text, sizeof( text ) );
298  const string opaque( cp );
299  // create Generic address
300  // already have svcType, clID, par1.. just make dummy variables for par2, and ipar1 and 2
301  const string& p2 = "";
302  unsigned long ip1( 0 );
303  unsigned long ip2( 0 );
304  GenericAddress gadd( svcType, classid, opaque, p2, ip1, ip2 );
305 
306  // now create the address
307  createAddressStat =
308  m_addressCreator->createAddress( gadd.svcType(), gadd.clID(), gadd.par(), gadd.ipar(), iopref );
309  if ( createAddressStat.isFailure() ) {
310  throw GaudiException( "Failure in creating OpaqueAddress for reconstructed registry", "", createAddressStat );
311  }
312  // And finally, set this address
313  obj->registry()->setAddress( iop );
314  }
315  // all done
316  }
317 }
318 
319 // Protected
321 void GaudiMP::TESSerializer::addItem( Items& itms, const std::string& descriptor )
322 {
323  // supports # notation
324  int level = 0;
325 
326  std::string slevel;
327  std::string obj_path;
328 
329  // Process the incoming string
330  size_t sep = descriptor.rfind( "#" );
331  if ( sep > descriptor.length() ) {
332  // invalid sep case (# not found in string)
333  obj_path = descriptor;
334  slevel = "1";
335  } else {
336  // valid sep case
337  obj_path = descriptor.substr( 0, sep );
338  slevel = descriptor.substr( sep + 1 );
339  }
340 
341  // Convert the level string to an integer
342  if ( slevel == "*" ) {
343  level = 9999999;
344  } else {
345  level = std::stoi( slevel );
346  }
347 
348  // Are we verifying?
349  if ( m_verifyItems ) {
350  size_t idx = obj_path.find( "/", 1 );
351  while ( idx != std::string::npos ) {
352  std::string sub_item = obj_path.substr( 0, idx );
353  if ( 0 == findItem( sub_item ) ) {
354  cout << "... calling addItem with arg : " << sub_item << endl;
355  addItem( itms, sub_item );
356  }
357  idx = obj_path.find( "/", idx + 1 );
358  }
359  }
360  DataStoreItem* item = new DataStoreItem( obj_path, level );
361  // cout << "Adding TESSerializer item " << item->path()
362  // << " with " << item->depth()
363  // << " level(s)." << endl;
364  itms.push_back( item );
365 }
366 
369 {
370  // #notation supported
371  addItem( m_itemList, path );
372 }
373 
376 {
377  // #notation supported
378  addItem( m_optItemList, path );
379 }
380 
383 {
384  cout << "TESSerializer m_itemList : " << m_itemList.size() << " Items" << endl;
385  for ( Items::const_iterator i = m_itemList.begin(); i != m_itemList.end(); ++i ) {
386  cout << "\tItem : " << ( *i )->path() << endl;
387  }
388  cout << "TESSerializer m_optItemList : " << m_optItemList.size() << " Items" << endl;
389  for ( Items::const_iterator i = m_optItemList.begin(); i != m_optItemList.end(); ++i ) {
390  cout << "\tItem : " << ( *i )->path() << endl;
391  }
392 }
393 
396 {
397  for ( Items::const_iterator i = m_itemList.begin(); i != m_itemList.end(); ++i ) {
398  if ( ( *i )->path() == path ) return ( *i );
399  }
400  for ( Items::const_iterator j = m_optItemList.begin(); j != m_optItemList.end(); ++j ) {
401  if ( ( *j )->path() == path ) return ( *j );
402  }
403  return 0;
404 }
void checkItems()
print out the contents of m_itemList and m_optItemList (std::cout)
Define general base for Gaudi exception.
virtual const CLID & clID() const =0
Retrieve class information from link.
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:329
void loadBuffer(TBufferFile &)
Rebuild TES from items in a TBufferFile.
virtual StatusCode createAddress(long svc_type, const CLID &clid, const std::string *par, const unsigned long *ipar, IOpaqueAddress *&refpAddress)=0
Create a Generic address using explicit arguments to identify a single object.
GAUDI_API void popCurrentDataObject()
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:75
TESSerializer(IDataProviderSvc *svc, IAddressCreator *ac)
Constructor.
T rfind(T...args)
T endl(T...args)
IAddressCreator interface definition.
Items m_optItemList
Vector of optional items to be saved to this stream (DataStoreItem ptrs)
Definition: TESSerializer.h:81
STL namespace.
bool m_verifyItems
Boolean Flag as used by GaudiSvc/PersistencySvc/OutputStreamer.
Definition: TESSerializer.h:90
T end(T...args)
Generic Transient Address.
Data provider interface definition.
virtual const std::string * par() const =0
Retrieve String parameters.
Description of the DataStoreItem class.
Definition: DataStoreItem.h:17
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
IAddressCreator * m_addressCreator
IAddress Creator for Opaque Addresses.
Definition: TESSerializer.h:94
IRegistry * registry() const
Get pointer to Registry.
Definition: DataObject.h:72
Items m_itemList
Vector of items to be saved to this stream (DataStoreItem ptrs)
Definition: TESSerializer.h:77
bool m_strict
Boolean Flag used to determine error tolerance.
Definition: TESSerializer.h:92
LinkManager * linkMgr() const
Retrieve Link manager.
Definition: DataObject.h:74
const std::string & path() const
Accessor: Retrieve load path.
Definition: DataStoreItem.h:58
STL class.
T push_back(T...args)
IDataManagerSvc * m_TESMgr
TES pointer.
Definition: TESSerializer.h:73
virtual StatusCode findObject(IRegistry *pDirectory, const std::string &path, DataObject *&pObject)=0
Find object identified by its directory entry.
bool analyse(IRegistry *dir, int level) override
Analysis callback.
virtual const id_type & identifier() const =0
Full identifier (or key)
void dumpBuffer(TBufferFile &)
Dump TES contents listed in m_itemList/m_optItemList to a TBufferFile.
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:28
const unsigned long * ipar() const override
Retrieve integer parameters.
const std::string * par() const override
Retrieve string parameters.
T erase(T...args)
The IRegistry represents the entry door to the environment any data object residing in a transient da...
Definition: IRegistry.h:22
virtual long svcType() const =0
Retrieve service type.
void addItem(const std::string &path)
add an item to the TESSerializer&#39;s list (#notation)
unsigned int CLID
Class ID definition.
Definition: ClassID.h:8
GAUDI_API void pushCurrentDataObject(DataObject **pobjAddr)
long svcType() const override
Access : retrieve the storage type of the class id.
virtual StatusCode setRoot(std::string root_name, DataObject *pObject)=0
Initialize data store for new event by giving new event path.
virtual DataObject * object() const =0
Retrieve object behind the link.
T find(T...args)
T size(T...args)
T begin(T...args)
virtual void setAddress(IOpaqueAddress *pAddress)=0
Set/Update Opaque storage address.
Objects m_objects
Selected list of Objects to be serialized (DataObject ptrs)
Definition: TESSerializer.h:85
T c_str(T...args)
T substr(T...args)
void addOptItem(const std::string &path)
add an item to the TESSerializer&#39;s optional list (#notation)
DataStoreItem * findItem(const std::string &path)
Find single item identified by its path (exact match)
Opaque address interface definition.
virtual StatusCode registerObject(const std::string &fullPath, DataObject *pObject)=0
Register object with the data store.
DataStoreItem * m_currentItem
Current item while traversing the TES tree.
Definition: TESSerializer.h:83
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
const CLID & clID() const override
Access : Retrieve class ID of the link.
virtual StatusCode traverseSubTree(const std::string &sub_path, IDataStoreAgent *pAgent)=0
Analyse by traversing all data objects below the sub tree identified by its full path name...
#define SERIALIZER_END
A DataObject is the base class of any identifiable object on any data store.
Definition: DataObject.h:29
T stoi(T...args)
IDataProviderSvc * m_TES
TES pointer.
Definition: TESSerializer.h:71
T compare(T...args)
std::map< std::string, TClass * > m_classMap
Map of gROOT class information.
Definition: TESSerializer.h:88
virtual StatusCode retrieveObject(IRegistry *pDirectory, const std::string &path, DataObject *&pObject)=0
Retrieve object identified by its directory entry.