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