The Gaudi Framework  v33r0 (d5ea422b)
TESSerializer.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 #include "GaudiMP/TESSerializer.h"
12 
13 // Framework include files
14 #include "GaudiKernel/DataObject.h"
19 #include "GaudiKernel/IRegistry.h"
21 #include "GaudiKernel/System.h"
22 
23 #include "GaudiKernel/ClassID.h"
27 
28 #include "GaudiKernel/MsgStream.h"
29 
30 // ROOT include files
31 #include "TBufferFile.h"
32 #include "TClass.h"
33 #include "TInterpreter.h"
34 #include "TROOT.h"
35 
36 #include <map>
37 
38 // a constant to guard against seg-faults in loadBuffer
39 #define SERIALIZER_END "EOF"
40 
41 namespace {
42  struct DataObjectPush {
43  DataObjectPush( DataObject*& p ) { Gaudi::pushCurrentDataObject( &p ); }
44  ~DataObjectPush() { Gaudi::popCurrentDataObject(); }
45  };
46 } // namespace
47 
48 using namespace std;
49 
51  if ( level < m_currentItem->depth() ) {
52  if ( dir->object() != 0 ) {
53  m_objects.push_back( dir->object() );
54  return true;
55  }
56  }
57  return false;
58 }
59 
62  : m_TES( svc )
63  , m_TESMgr( dynamic_cast<IDataManagerSvc*>( svc ) )
64  , m_currentItem( 0 )
65  , m_verifyItems( false )
66  , m_strict( false )
67  , m_addressCreator( ac ) {}
68 
70 void GaudiMP::TESSerializer::dumpBuffer( TBufferFile& buffer ) {
71  //
72  // Write all valid objects to the TBufferFile provided in the argument
73  // As objects are collected, the member variable m_classMap is filled
74  // with ROOT Class data, and is kept by the Serializer for future
75  // reference
76  //
77  // @paramTBufferFile& buffer : TBufferFile passed by reference
78  // Cannot be declared inside the method, as repeated calls
79  // can cause confusion and buffer wiping.
80  //
81  StatusCode status;
82  DataObject* obj;
83 
84  // Clear current selection
85  m_objects.clear();
86 
87  // Traverse the tree and collect the requested objects
88  for ( Items::iterator i = m_itemList.begin(); i != m_itemList.end(); i++ ) {
89  m_currentItem = ( *i );
90  // cout << "Retrieving Mandatory Object : " << m_currentItem->path() << endl;
91  status = m_TES->retrieveObject( m_currentItem->path(), obj );
92  if ( status.isSuccess() ) {
93  m_TESMgr->traverseSubTree( obj, this );
94  } else {
95  string text( "WARNING: Cannot retrieve TES object(s) for serialisation: " );
96  text += m_currentItem->path();
97  if ( m_strict ) {
98  throw GaudiException( text + m_currentItem->path(), "", status );
99  } else {
100  cout << text << endl;
101  // return StatusCode::FAILURE;
102  }
103  }
104  }
105  // Traverse the tree and collect the requested objects (tolerate missing items here)
106  for ( Items::iterator i = m_optItemList.begin(); i != m_optItemList.end(); i++ ) {
107  m_currentItem = ( *i );
108  // cout << "Retrieving Optional Object : " << m_currentItem->path() << endl;
109  status = m_TES->retrieveObject( m_currentItem->path(), obj );
110  if ( status.isSuccess() ) { m_TESMgr->traverseSubTree( obj, this ); }
111  }
112 
113  // Prepare for serialization:
114  // - find all TClass pointers needed and ignore objects without dictionaries
116  objects.reserve( m_objects.size() );
117  for_each( begin( m_objects ), end( m_objects ), [this, &objects]( auto obj ) {
118  if ( auto cl = getClass( obj ) ) objects.emplace_back( obj, cl );
119  } );
120 
121  // cout << "TESSerializer : Beginning loop to write to TBufferFile for nObjects : " << m_objects.size() << endl;
122  buffer.WriteInt( objects.size() );
123 
124  for ( auto& [pObj, cl] : objects ) {
125  DataObjectPush p( pObj ); /* add the data object to the list... */
126 
127  // write object to buffer in order location-name-object
128  std::string loc = pObj->registry()->identifier();
129  buffer.WriteString( loc.c_str() );
130  buffer.WriteString( cl->GetName() );
131  cl->Streamer( pObj, buffer );
132 
133  /* take care of links */
134  LinkManager* linkMgr = pObj->linkMgr();
135  int numLinks = linkMgr->size();
136  buffer.WriteInt( numLinks );
137  // now write each link
138  for ( int it = 0; it != numLinks; it++ ) {
139  const string& link = linkMgr->link( it )->path();
140  buffer.WriteString( link.c_str() );
141  }
142 
143  // now do the thing with the opaqueAddress
144  // to go from string->object when recovering, will need svc_type, and clid, aswell as the string version
145  IOpaqueAddress* iop = pObj->registry()->address();
146  if ( iop ) {
147  buffer.WriteInt( 1 );
148  const string* par = iop->par();
149  long svcType = iop->svcType();
150  long clid = iop->clID();
151  buffer.WriteLong( svcType );
152  buffer.WriteLong( clid );
153  buffer.WriteString( par->c_str() );
154  } else {
155  buffer.WriteInt( 0 );
156  }
157  // object complete, continue in for-loop
158  }
159 
160  // Final Actions
161  // Write the End Flag, to avoid potential SegFaults on loadBuffer
162  buffer.WriteString( SERIALIZER_END );
163  // return StatusCode::SUCCESS;
164 }
165 
167 void GaudiMP::TESSerializer::loadBuffer( TBufferFile& buffer ) {
168 
169  // reverse mechanism of dumps
170  // buffer is: length of DataObjects vector
171  // location string
172  // type name string
173  // the object itself
174  // count of links
175  // list of links (conditional on count)
176  // flag indicating Opaque Address presence
177  // Opaque Address svcType (conditional on flag)
178  // Opaque Address clID (conditional on flag)
179  // Opaque Address par (conditional on flag)
180 
181  int nObjects;
182  // 3 StatusCodes... for :
183  // general use : registering objects : creating OpaqueAddresses
184  StatusCode sc, registerStat, createAddressStat;
185 
186  // Prepare for Reading
187  buffer.SetReadMode();
188  buffer.SetBufferOffset();
189 
190  buffer.ReadInt( nObjects );
191  for ( int i = 0; i < nObjects; ++i ) {
192  char text[4096];
193  buffer.ReadString( text, sizeof( text ) );
194  string location( text );
195  if ( !location.compare( "EOF" ) ) {
196  /* There was an error in serialization, but the EOF
197  flag marks the endpoint in any case */
198  break;
199  }
200  buffer.ReadString( text, sizeof( text ) );
201  TClass* cl = gROOT->GetClass( text );
202  if ( cl == 0 ) {
203  if ( m_strict ) {
204  throw GaudiException( "gROOT->GetClass cannot find clName", text, StatusCode::FAILURE );
205  } else {
206  cout << "TESSerializer WARNING : gROOT->GetClass fails for clname : " << location.c_str() << endl;
207  continue;
208  }
209  }
210 
212  DataObject* obj = (DataObject*)cl->New();
213  DataObjectPush push( obj ); // This is magic!
214  cl->Streamer( obj, buffer );
215 
216  // now restore links
217  if ( obj ) {
218  int nlink = 0;
219  LinkManager* lnkMgr = obj->linkMgr();
220  buffer.ReadInt( nlink );
221 
222  for ( int j = 0; j < nlink; ++j ) {
223  buffer.ReadString( text, sizeof( text ) );
224  lnkMgr->addLink( text, 0 );
225  }
226  }
227 
228  // Re-register...
229  registerStat = m_TES->registerObject( location, obj );
230  if ( registerStat.isFailure() ) {
231  DataObject* dummy = NULL;
232  if ( location == "/Event" ) {
233  sc = m_TESMgr->setRoot( location, obj );
234  if ( sc.isFailure() ) throw GaudiException( "Cannot set root at location " + location, "", sc );
235  } else {
236  m_TES->findObject( location, dummy );
237  if ( !dummy )
238  m_TES->registerObject( location, obj );
239  else {
240  // skipping to the next object
241  // (flush the remaining metadata in the buffer)
242  int flag( 0 );
243  buffer.ReadInt( flag );
244  if ( flag ) {
245  long svcType;
246  buffer.ReadLong( svcType );
247  long clid;
248  buffer.ReadLong( clid );
249  buffer.ReadString( text, sizeof( text ) );
250  }
251  continue;
252  }
253  }
254  }
255  // next is the opaque address information
256  // create Generic Address using the info from the TBufferFile,
257  // then create an IOpaqueAddress object using the Persistency Svc
258  // IOpaque Address pointer (blank... pass the ref to the createAddress Fn)
259 
260  int flag( 0 );
261  buffer.ReadInt( flag );
262  // flag will be 0 or 1 to indicate OpaqueAddress Info
263  if ( flag == 1 ) {
264  // will need an IOpaqueAddress and its ref
265  IOpaqueAddress* iop;
266  IOpaqueAddress*& iopref = iop;
267  // Read svcType, clID and par from buffer
268  long svcType;
269  buffer.ReadLong( svcType );
270 
271  long clid;
272  buffer.ReadLong( clid );
273  const CLID classid( clid );
274 
275  char* cp;
276  cp = buffer.ReadString( text, sizeof( text ) );
277  const string opaque( cp );
278  // create Generic address
279  // already have svcType, clID, par1.. just make dummy variables for par2, and ipar1 and 2
280  const string& p2 = "";
281  unsigned long ip1( 0 );
282  unsigned long ip2( 0 );
283  GenericAddress gadd( svcType, classid, opaque, p2, ip1, ip2 );
284 
285  // now create the address
286  createAddressStat =
287  m_addressCreator->createAddress( gadd.svcType(), gadd.clID(), gadd.par(), gadd.ipar(), iopref );
288  if ( createAddressStat.isFailure() ) {
289  throw GaudiException( "Failure in creating OpaqueAddress for reconstructed registry", "", createAddressStat );
290  }
291  // And finally, set this address
292  obj->registry()->setAddress( iop );
293  }
294  // all done
295  }
296 }
297 
298 // Protected
300 void GaudiMP::TESSerializer::addItem( Items& itms, const std::string& descriptor ) {
301  // supports # notation
302  int level = 0;
303 
304  std::string slevel;
305  std::string obj_path;
306 
307  // Process the incoming string
308  size_t sep = descriptor.rfind( "#" );
309  if ( sep > descriptor.length() ) {
310  // invalid sep case (# not found in string)
311  obj_path = descriptor;
312  slevel = "1";
313  } else {
314  // valid sep case
315  obj_path = descriptor.substr( 0, sep );
316  slevel = descriptor.substr( sep + 1 );
317  }
318 
319  // Convert the level string to an integer
320  if ( slevel == "*" ) {
321  level = 9999999;
322  } else {
323  level = std::stoi( slevel );
324  }
325 
326  // Are we verifying?
327  if ( m_verifyItems ) {
328  size_t idx = obj_path.find( "/", 1 );
329  while ( idx != std::string::npos ) {
330  std::string sub_item = obj_path.substr( 0, idx );
331  if ( 0 == findItem( sub_item ) ) {
332  cout << "... calling addItem with arg : " << sub_item << endl;
333  addItem( itms, sub_item );
334  }
335  idx = obj_path.find( "/", idx + 1 );
336  }
337  }
338  DataStoreItem* item = new DataStoreItem( obj_path, level );
339  // cout << "Adding TESSerializer item " << item->path()
340  // << " with " << item->depth()
341  // << " level(s)." << endl;
342  itms.push_back( item );
343 }
344 
347  // #notation supported
348  addItem( m_itemList, path );
349 }
350 
353  // #notation supported
354  addItem( m_optItemList, path );
355 }
356 
359  cout << "TESSerializer m_itemList : " << m_itemList.size() << " Items" << endl;
360  for ( Items::const_iterator i = m_itemList.begin(); i != m_itemList.end(); ++i ) {
361  cout << "\tItem : " << ( *i )->path() << endl;
362  }
363  cout << "TESSerializer m_optItemList : " << m_optItemList.size() << " Items" << endl;
364  for ( Items::const_iterator i = m_optItemList.begin(); i != m_optItemList.end(); ++i ) {
365  cout << "\tItem : " << ( *i )->path() << endl;
366  }
367 }
368 
371  for ( Items::const_iterator i = m_itemList.begin(); i != m_itemList.end(); ++i ) {
372  if ( ( *i )->path() == path ) return ( *i );
373  }
374  for ( Items::const_iterator j = m_optItemList.begin(); j != m_optItemList.end(); ++j ) {
375  if ( ( *j )->path() == path ) return ( *j );
376  }
377  return 0;
378 }
virtual const std::string * par() const =0
Retrieve String parameters.
void checkItems()
print out the contents of m_itemList and m_optItemList (std::cout)
Define general base for Gaudi exception.
IRegistry * registry() const
Get pointer to Registry.
Definition: DataObject.h:82
const std::string * par() const override
Retrieve string parameters.
void loadBuffer(TBufferFile &)
Rebuild TES from items in a TBufferFile.
GAUDI_API void popCurrentDataObject()
LinkManager * linkMgr() const
Retrieve Link manager.
Definition: DataObject.h:84
def getClass(name, libs=[])
Definition: Bindings.py:170
TESSerializer(IDataProviderSvc *svc, IAddressCreator *ac)
Constructor.
T rfind(T... args)
T endl(T... args)
IAddressCreator interface definition.
STL namespace.
const CLID & clID() const override
Access : Retrieve class ID of the link.
Generic Transient Address.
Data provider interface definition.
Description of the DataStoreItem class.
Definition: DataStoreItem.h:27
virtual long svcType() const =0
Retrieve service type.
long svcType() const override
Access : retrieve the storage type of the class id.
STL class.
T push_back(T... args)
bool analyse(IRegistry *dir, int level) override
Analysis callback.
virtual const CLID & clID() const =0
Retrieve class information from link.
virtual IRegistry * registry() const =0
Update branch name.
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:61
The IRegistry represents the entry door to the environment any data object residing in a transient da...
Definition: IRegistry.h:32
def end
Definition: IOTest.py:123
void addItem(const std::string &path)
add an item to the TESSerializer's list (#notation)
unsigned int CLID
Class ID definition.
Definition: ClassID.h:18
GAUDI_API void pushCurrentDataObject(DataObject **pobjAddr)
bool isSuccess() const
Definition: StatusCode.h:361
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
virtual DataObject * object() const =0
Retrieve object behind the link.
T find(T... args)
T size(T... args)
STL class.
virtual void setAddress(IOpaqueAddress *pAddress)=0
Set/Update Opaque storage address.
T c_str(T... args)
constexpr static const auto FAILURE
Definition: StatusCode.h:97
T substr(T... args)
const unsigned long * ipar() const override
Retrieve integer parameters.
bool isFailure() const
Definition: StatusCode.h:141
AttribStringParser::Iterator begin(const AttribStringParser &parser)
void addOptItem(const std::string &path)
add an item to the TESSerializer's optional list (#notation)
DataStoreItem * findItem(const std::string &path)
Find single item identified by its path (exact match)
Opaque address interface definition.
T for_each(T... args)
#define SERIALIZER_END
A DataObject is the base class of any identifiable object on any data store.
Definition: DataObject.h:40
T stoi(T... args)
T reserve(T... args)
T emplace_back(T... args)