The Gaudi Framework  v33r1 (b1225454)
EvtStoreSvc.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 "Gaudi/Accumulators.h"
12 #include "Gaudi/Arena/Monotonic.h"
19 #include "GaudiKernel/IRegistry.h"
20 #include "GaudiKernel/Service.h"
21 #include "GaudiKernel/System.h"
22 
23 #include "ThreadLocalStorage.h"
24 
25 #include "boost/algorithm/string/predicate.hpp"
26 
27 #include "tbb/concurrent_queue.h"
28 #include "tbb/tbb_stddef.h"
29 #if TBB_INTERFACE_VERSION_MAJOR < 12
30 # include "tbb/recursive_mutex.h"
31 #endif // TBB_INTERFACE_VERSION_MAJOR < 12
32 
33 #include <algorithm>
34 #include <iomanip>
35 #include <iterator>
36 #include <map>
37 #include <mutex>
38 #include <stdexcept>
39 #include <type_traits>
40 #include <unordered_map>
41 #include <utility>
42 #include <vector>
43 
44 namespace {
45  using LocalArena = Gaudi::Arena::Monotonic<>;
46 
47  template <typename T>
48  using LocalAlloc = Gaudi::Allocator::MonotonicArena<T>;
49 
50  using pool_string = std::basic_string<char, std::char_traits<char>, LocalAlloc<char>>;
51 
52  class Entry final : public IRegistry {
55  pool_string m_identifierStorage;
56  mutable std::optional<std::string> m_identifier;
57  static IDataProviderSvc* s_svc;
58 
59  public:
60  using allocator_type = LocalAlloc<char>;
61  static void setDataProviderSvc( IDataProviderSvc* p ) { s_svc = p; }
62 
63  Entry( std::string_view id, std::unique_ptr<DataObject> data, std::unique_ptr<IOpaqueAddress> addr,
64  allocator_type alloc ) noexcept
65  : m_data{std::move( data )}, m_addr{std::move( addr )}, m_identifierStorage{id, alloc} {
66  if ( m_data ) m_data->setRegistry( this );
67  if ( m_addr ) m_addr->setRegistry( this );
68  }
69  Entry( const Entry& ) = delete;
70  Entry& operator=( const Entry& rhs ) = delete;
71  Entry( Entry&& rhs ) = delete;
72  Entry& operator=( Entry&& rhs ) = delete;
73 
74  // required by IRegistry...
75  unsigned long addRef() override { return -1; }
76  unsigned long release() override { return -1; }
77  const name_type& name() const override {
78  // should really be from last '/' onward...
79  if ( !m_identifier ) m_identifier.emplace( m_identifierStorage );
80  return *m_identifier;
81  }
82  const id_type& identifier() const override {
83  if ( !m_identifier ) m_identifier.emplace( m_identifierStorage );
84  return *m_identifier;
85  }
86  std::string_view identifierView() const { return m_identifierStorage; }
87  IDataProviderSvc* dataSvc() const override { return s_svc; }
88  DataObject* object() const override { return const_cast<DataObject*>( m_data.get() ); }
89  IOpaqueAddress* address() const override { return m_addr.get(); }
90  void setAddress( IOpaqueAddress* iAddr ) override {
91  m_addr.reset( iAddr );
92  if ( m_addr ) m_addr->setRegistry( this );
93  }
94  };
95  IDataProviderSvc* Entry::s_svc = nullptr;
96 
97  using UnorderedMap =
99  LocalAlloc<std::pair<const std::string_view, Entry>>>;
100  using OrderedMap = std::map<std::string_view, Entry>;
101 
102  template <typename Map = UnorderedMap>
103  class Store {
104  LocalArena m_resource;
105  std::size_t m_est_size;
106  // Optional purely to make [re]construction simpler, should "always" be valid
107  std::optional<Map> m_store{std::in_place, &m_resource};
108  static_assert( std::is_same_v<typename Map::key_type, std::string_view> );
109 
110  const auto& emplace( std::string_view k, std::unique_ptr<DataObject> d, std::unique_ptr<IOpaqueAddress> a = {} ) {
111  // tricky way to insert a string_view key which points to the
112  // string contained in the mapped type...
113  auto [i, b] = m_store->try_emplace( k, k, std::move( d ), std::move( a ), &m_resource );
114  if ( !b ) throw std::runtime_error( "failed to insert " + std::string{k} );
115  auto nh = m_store->extract( i );
116  nh.key() = nh.mapped().identifierView(); // "re-point" key to the string contained in the Entry
117  auto r = m_store->insert( std::move( nh ) );
118  if ( !r.inserted ) throw std::runtime_error( "failed to insert " + std::string{k} );
119  return r.position->second;
120  }
121 
122  public:
123  Store( std::size_t est_size, std::size_t pool_size ) : m_resource{pool_size}, m_est_size{est_size} {}
124  [[nodiscard]] bool empty() const { return m_store->empty(); }
125  [[nodiscard]] std::size_t size() const { return m_store->size(); }
126  [[nodiscard]] std::size_t used_bytes() const noexcept { return m_resource.size(); }
127  [[nodiscard]] std::size_t used_blocks() const noexcept { return m_resource.num_blocks(); }
128  [[nodiscard]] std::size_t used_buckets() const { return m_store->bucket_count(); }
129  [[nodiscard]] std::size_t num_allocations() const noexcept { return m_resource.num_allocations(); }
130 
131  void reset() {
132  m_store.reset(); // kill the old map
133  m_resource.reset(); // tell the memory pool it can start re-using its resources
134  m_store.emplace( m_est_size, &m_resource ); // initialise the new map with a sane number of buckets
135  }
136 
137  const DataObject* put( std::string_view k, std::unique_ptr<DataObject> data,
138  std::unique_ptr<IOpaqueAddress> addr = {} ) {
139  return emplace( k, std::move( data ), std::move( addr ) ).object();
140  }
141  const DataObject* get( std::string_view k ) const noexcept {
142  const Entry* d = find( k );
143  return d ? d->object() : nullptr;
144  }
145  const Entry* find( std::string_view k ) const noexcept {
146  auto i = m_store->find( k );
147  return i != m_store->end() ? &( i->second ) : nullptr;
148  }
149 
150  [[nodiscard]] auto begin() const noexcept { return m_store->begin(); }
151  [[nodiscard]] auto end() const noexcept { return m_store->end(); }
152  void clear() noexcept { m_store->clear(); }
153  auto erase( std::string_view k ) { return m_store->erase( k ); }
154  template <typename Predicate>
155  void erase_if( Predicate p ) {
156  auto i = m_store->begin();
157  auto end = m_store->end();
158  while ( i != end ) {
159  if ( std::invoke( p, std::as_const( *i ) ) )
160  i = m_store->erase( i );
161  else
162  ++i;
163  }
164  }
165  };
166 
167  StatusCode dummy( std::string s ) {
168  std::string trace;
169  System::backTrace( trace, 6, 2 );
170  throw std::logic_error{"Unsupported Function Called: " + s + "\n" + trace};
171  return StatusCode::FAILURE;
172  }
173 
174  std::string_view normalize_path( std::string_view path, std::string_view prefix ) {
175  if ( path.size() >= prefix.size() && std::equal( prefix.begin(), prefix.end(), path.begin() ) )
176  path.remove_prefix( prefix.size() );
177  if ( !path.empty() && path.front() == '/' ) path.remove_prefix( 1 );
178  return path;
179  }
180 
182  DataObject* pObject = nullptr;
183  auto status = cnv.createObj( &addr, pObject ); // Call data loader
184  auto object = std::unique_ptr<DataObject>( pObject );
185  if ( status.isFailure() ) object.reset();
186  return object;
187  }
188 
189  // HiveWhiteBoard helpers
190  struct Partition final {
191  // Use optional to allow re-constructing in-place without an ugly
192  // exception-unsafe placement-new conconction, and also to make it easier
193  // to pass constructor arguments to Store<>.
194  std::optional<Store<>> store;
195  int eventNumber = -1;
196  };
197 
198 #if TBB_INTERFACE_VERSION_MAJOR < 12
199  template <typename T, typename Mutex = tbb::recursive_mutex, typename ReadLock = typename Mutex::scoped_lock,
200 
201 #else
202  template <typename T, typename Mutex = std::recursive_mutex,
203  typename ReadLock = std::scoped_lock<std::recursive_mutex>,
204 #endif // TBB_INTERFACE_VERSION_MAJOR < 12
205  typename WriteLock = ReadLock>
206  class Synced {
207  T m_obj;
208  mutable Mutex m_mtx;
209 
210  public:
211  template <typename F>
212  decltype( auto ) with_lock( F&& f ) {
213  WriteLock lock{m_mtx};
214  return f( m_obj );
215  }
216  template <typename F>
217  decltype( auto ) with_lock( F&& f ) const {
218  ReadLock lock{m_mtx};
219  return f( m_obj );
220  }
221  };
222  // transform an f(T) into an f(Synced<T>)
223  template <typename Fun>
224  auto with_lock( Fun&& f ) {
225  return [f = std::forward<Fun>( f )]( auto& p ) -> decltype( auto ) { return p.with_lock( f ); };
226  }
227 
228  TTHREAD_TLS( Synced<Partition>* ) s_current = nullptr;
229 
230  template <typename Fun>
231  StatusCode fwd( Fun&& f ) {
232  return s_current ? s_current->with_lock( std::forward<Fun>( f ) )
234  }
235 
236 } // namespace
237 
248 class GAUDI_API EvtStoreSvc : public extends<Service, IDataProviderSvc, IDataManagerSvc, IHiveWhiteBoard> {
249  Gaudi::Property<CLID> m_rootCLID{this, "RootCLID", 110 /*CLID_Event*/, "CLID of root entry"};
250  Gaudi::Property<std::string> m_rootName{this, "RootName", "/Event", "name of root entry"};
251  Gaudi::Property<bool> m_forceLeaves{this, "ForceLeaves", false, "force creation of default leaves on registerObject"};
252  Gaudi::Property<std::string> m_loader{this, "DataLoader", "EventPersistencySvc"};
253  Gaudi::Property<size_t> m_slots{this, "EventSlots", 1, "number of event slots"};
254  Gaudi::Property<bool> m_printPoolStats{this, "PrintPoolStats", false, "Print memory pool statistics"};
255  Gaudi::Property<std::size_t> m_poolSize{this, "PoolSize", 1024, "Initial per-event memory pool size [KiB]"};
256  Gaudi::Property<std::size_t> m_estStoreBuckets{this, "StoreBuckets", 100, "Estimated number of buckets in the store"};
257  mutable Gaudi::Accumulators::AveragingCounter<std::size_t> m_usedPoolSize, m_servedPoolAllocations,
258  m_usedPoolAllocations, m_storeEntries, m_storeBuckets;
259 
260  // Convert to bytes
261  std::size_t poolSize() const { return m_poolSize * 1024; }
262 
263  void fillStats( Partition& p ) const {
264  if ( LIKELY( !m_printPoolStats ) ) return;
265  auto n_allocs = p.store->num_allocations();
266  if ( n_allocs ) {
267  m_storeEntries += p.store->size();
268  m_usedPoolSize += p.store->used_bytes();
269  m_storeBuckets += p.store->used_buckets();
270  m_usedPoolAllocations += p.store->used_blocks();
271  m_servedPoolAllocations += n_allocs;
272  }
273  }
274 
275  void initStore( Partition& p ) const {
276  if ( p.store ) {
277  // re-use the existing memory pool
278  p.store->reset();
279  } else {
280  p.store.emplace( m_estStoreBuckets, poolSize() );
281  }
282  }
283 
285 
288 
291 
292  tbb::concurrent_queue<size_t> m_freeSlots;
293 
295  this,
296  "InhibitedPathPrefixes",
297  {},
298  "Prefixes of TES locations that will not be loaded by the persistency service "};
299  Gaudi::Property<bool> m_followLinksToAncestors{
300  this, "FollowLinksToAncestors", true,
301  "Load objects which reside in files other than the one corresponding to the root of the event store"};
302  std::string_view m_onlyThisID; // let's be a bit risky... we 'know' when the underlying string goes out of scope...
303 
304 public:
305  using extends::extends;
306 
307  CLID rootCLID() const override;
308  const std::string& rootName() const override;
309  StatusCode setDataLoader( IConversionSvc* svc, IDataProviderSvc* dpsvc ) override;
310 
311  size_t allocateStore( int evtnumber ) override;
312  StatusCode freeStore( size_t partition ) override;
313  size_t freeSlots() override { return m_freeSlots.unsafe_size(); }
314  StatusCode selectStore( size_t partition ) override;
315  StatusCode clearStore() override;
316  StatusCode clearStore( size_t partition ) override;
317  StatusCode setNumberOfStores( size_t slots ) override;
318  size_t getNumberOfStores() const override { return m_slots; }
319  size_t getPartitionNumber( int eventnumber ) const override;
320  bool exists( const DataObjID& id ) override {
321  DataObject* pObject{nullptr};
322  return findObject( id.fullKey(), pObject ).isSuccess();
323  }
324 
325  StatusCode objectParent( const DataObject*, IRegistry*& ) override { return dummy( __FUNCTION__ ); }
326  StatusCode objectParent( const IRegistry*, IRegistry*& ) override { return dummy( __FUNCTION__ ); }
327  StatusCode objectLeaves( const DataObject*, std::vector<IRegistry*>& ) override { return dummy( __FUNCTION__ ); }
328  StatusCode objectLeaves( const IRegistry*, std::vector<IRegistry*>& ) override { return dummy( __FUNCTION__ ); }
329 
330  StatusCode clearSubTree( std::string_view ) override;
331  StatusCode clearSubTree( DataObject* obj ) override {
332  return obj && obj->registry() ? clearSubTree( obj->registry()->identifier() ) : StatusCode::FAILURE;
333  }
334 
335  StatusCode traverseSubTree( std::string_view, IDataStoreAgent* ) override;
337  return ( obj && obj->registry() ) ? traverseSubTree( obj->registry()->identifier(), pAgent ) : StatusCode::FAILURE;
338  }
339  StatusCode traverseTree( IDataStoreAgent* pAgent ) override { return traverseSubTree( std::string_view{}, pAgent ); }
340 
341  StatusCode setRoot( std::string root_name, DataObject* pObject ) override;
342  StatusCode setRoot( std::string root_path, IOpaqueAddress* pRootAddr ) override;
343 
344  StatusCode unregisterAddress( std::string_view ) override { return dummy( __FUNCTION__ ); };
345  StatusCode unregisterAddress( IRegistry*, std::string_view ) override { return dummy( __FUNCTION__ ); };
346 
347  StatusCode registerAddress( std::string_view fullPath, IOpaqueAddress* pAddress ) override;
348  StatusCode registerAddress( IRegistry* parentObj, std::string_view objectPath, IOpaqueAddress* pAddress ) override;
349  StatusCode registerObject( std::string_view parentPath, std::string_view objectPath, DataObject* pObject ) override;
350  StatusCode registerObject( DataObject* parentObj, std::string_view objectPath, DataObject* pObject ) override;
351 
352  StatusCode unregisterObject( std::string_view ) override;
354  return ( obj && obj->registry() ) ? unregisterObject( obj->registry()->identifier() ) : StatusCode::FAILURE;
355  }
356  StatusCode unregisterObject( DataObject* obj, std::string_view sr ) override {
357  return !obj ? unregisterObject( sr )
358  : obj->registry() ? unregisterObject( ( obj->registry()->identifier() + '/' ).append( sr ) )
360  };
361 
362  StatusCode retrieveObject( IRegistry* pDirectory, std::string_view path, DataObject*& pObject ) override;
363 
364  StatusCode findObject( IRegistry* pDirectory, std::string_view path, DataObject*& pObject ) override;
365  StatusCode findObject( std::string_view fullPath, DataObject*& pObject ) override;
366 
367  StatusCode updateObject( IRegistry* ) override { return dummy( __FUNCTION__ ); }
368  StatusCode updateObject( DataObject* ) override { return dummy( __FUNCTION__ ); }
369 
370  StatusCode addPreLoadItem( const DataStoreItem& ) override;
371  StatusCode removePreLoadItem( const DataStoreItem& ) override;
373  m_preLoads.clear();
374  return StatusCode::SUCCESS;
375  }
376  StatusCode preLoad() override;
377 
378  StatusCode linkObject( IRegistry*, std::string_view, DataObject* ) override { return dummy( __FUNCTION__ ); }
379  StatusCode linkObject( std::string_view, DataObject* ) override { return dummy( __FUNCTION__ ); }
380  StatusCode unlinkObject( IRegistry*, std::string_view ) override { return dummy( __FUNCTION__ ); }
381  StatusCode unlinkObject( DataObject*, std::string_view ) override { return dummy( __FUNCTION__ ); }
382  StatusCode unlinkObject( std::string_view ) override { return dummy( __FUNCTION__ ); }
383 
384  StatusCode initialize() override {
385  Entry::setDataProviderSvc( this );
386  extends::initialize().ignore();
387  if ( !setNumberOfStores( m_slots ).isSuccess() ) {
388  error() << "Cannot set number of slots" << endmsg;
389  return StatusCode::FAILURE;
390  }
391  m_partitions = std::vector<Synced<Partition>>( m_slots );
392  // m_partitions is now full of empty std::optionals, fill them now.
393  for ( auto& synced_p : m_partitions ) {
394  synced_p.with_lock( [this]( Partition& p ) { initStore( p ); } );
395  }
396  for ( size_t i = 0; i < m_slots; i++ ) { m_freeSlots.push( i ); }
397  selectStore( 0 ).ignore();
398 
399  auto loader = serviceLocator()->service( m_loader ).as<IConversionSvc>().get();
400  if ( !loader ) {
401  error() << "Cannot get IConversionSvc " << m_loader.value() << endmsg;
402  return StatusCode::FAILURE;
403  }
404  return setDataLoader( loader, nullptr );
405  }
406  StatusCode finalize() override {
407  if ( m_printPoolStats ) {
408  info() << "Mean memory pool usage: " << float( 1e-3f * m_usedPoolSize.mean() ) << " KiB serving "
409  << float( m_servedPoolAllocations.mean() ) << " allocations from " << float( m_usedPoolAllocations.mean() )
410  << " to produce " << float( m_storeEntries.mean() ) << " entries in " << float( m_storeBuckets.mean() )
411  << " buckets" << endmsg;
412  }
413  setDataLoader( nullptr, nullptr ).ignore(); // release
414  return extends::finalize();
415  }
416 };
417 
418 // Instantiation of a static factory class used by clients to create
419 // instances of this service
421 
422 CLID EvtStoreSvc::rootCLID() const { return m_rootCLID; }
423 const std::string& EvtStoreSvc::rootName() const { return m_rootName; }
425  m_dataLoader = pDataLoader;
426  if ( m_dataLoader ) m_dataLoader->setDataProvider( dpsvc ? dpsvc : this ).ignore();
427  return StatusCode::SUCCESS;
428 }
430 size_t EvtStoreSvc::allocateStore( int evtnumber ) {
431  // take next free slot in the list
432  size_t slot = std::string::npos;
433  if ( m_freeSlots.try_pop( slot ) ) {
434  assert( slot != std::string::npos );
435  assert( slot < m_partitions.size() );
436  [[maybe_unused]] auto prev = m_partitions[slot].with_lock(
437  [evtnumber]( Partition& p ) { return std::exchange( p.eventNumber, evtnumber ); } );
438  assert( prev == -1 ); // or whatever value represents 'free'
439  }
440  return slot;
441 }
444  if ( slots < size_t{1} ) {
445  error() << "Invalid number of slots (" << slots << ")" << endmsg;
446  return StatusCode::FAILURE;
447  }
449  error() << "Too late to change the number of slots!" << endmsg;
450  return StatusCode::FAILURE;
451  }
452  m_slots = slots;
454  return StatusCode::SUCCESS;
455 }
457 size_t EvtStoreSvc::getPartitionNumber( int eventnumber ) const {
459  with_lock( [eventnumber]( const Partition& p ) { return p.eventNumber == eventnumber; } ) );
460  return i != end( m_partitions ) ? std::distance( begin( m_partitions ), i ) : std::string::npos;
461 }
464  s_current = &m_partitions[partition];
465  return StatusCode::SUCCESS;
466 }
468 StatusCode EvtStoreSvc::freeStore( size_t partition ) {
469  assert( partition < m_partitions.size() );
470  auto prev = m_partitions[partition].with_lock( []( Partition& p ) { return std::exchange( p.eventNumber, -1 ); } );
471  if ( UNLIKELY( prev == -1 ) ) return StatusCode::FAILURE; // double free -- should never happen!
472  m_freeSlots.push( partition );
473  return StatusCode::SUCCESS;
474 }
476 StatusCode EvtStoreSvc::clearStore( size_t partition ) {
477  m_onlyThisID = {};
478  return m_partitions[partition].with_lock( [this]( Partition& p ) {
479  fillStats( p );
480  initStore( p ); // replace with a clean store
481  return StatusCode::SUCCESS;
482  } );
483 }
484 StatusCode EvtStoreSvc::clearSubTree( std::string_view top ) {
485  top = normalize_path( top, rootName() );
486  return fwd( [&]( Partition& p ) {
487  p.store->erase_if( [top]( const auto& value ) { return boost::algorithm::starts_with( value.first, top ); } );
488  return StatusCode::SUCCESS;
489  } );
490 }
492  m_onlyThisID = {};
493  return fwd( [this]( Partition& p ) {
494  fillStats( p );
495  initStore( p ); // replace with a clean store
496  return StatusCode::SUCCESS;
497  } );
498 }
499 StatusCode EvtStoreSvc::traverseSubTree( std::string_view top, IDataStoreAgent* pAgent ) {
500  return fwd( [&]( Partition& p ) {
501  top = normalize_path( top, rootName() );
502  auto cmp = []( const Entry* lhs, const Entry* rhs ) { return lhs->identifier() < rhs->identifier(); };
503  std::set<const Entry*, decltype( cmp )> keys{std::move( cmp )};
504  for ( const auto& v : *p.store ) {
505  if ( boost::algorithm::starts_with( v.second.identifier(), top ) ) keys.insert( &v.second );
506  }
507  auto k = keys.begin();
508  while ( k != keys.end() ) {
509  const auto& id = ( *k )->identifier();
510  int level = std::count( id.begin(), id.end(), '/' );
511  bool accept = pAgent->analyse( const_cast<Entry*>( *( k++ ) ), level );
512  if ( !accept ) {
513  k = std::find_if_not( k, keys.end(),
514  [&id]( const auto& e ) { return boost::algorithm::starts_with( e->identifier(), id ); } );
515  }
516  }
517  return StatusCode::SUCCESS;
518  } );
519 }
521  if ( msgLevel( MSG::DEBUG ) ) {
522  debug() << "setRoot( " << root_path << ", (DataObject*)" << (void*)pObject << " )" << endmsg;
523  }
524  if ( UNLIKELY( !fwd( []( Partition& p ) {
525  return p.store->empty() ? StatusCode::SUCCESS : StatusCode::FAILURE;
526  } ).isSuccess() ) ) {
527  throw GaudiException{"setRoot called with non-empty store", "EvtStoreSvc", StatusCode::FAILURE};
528  }
529  return registerObject( nullptr, root_path, pObject );
530 }
532  auto rootAddr = std::unique_ptr<IOpaqueAddress>( pRootAddr );
533  if ( msgLevel( MSG::DEBUG ) ) {
534  debug() << "setRoot( " << root_path << ", (IOpaqueAddress*)" << rootAddr.get();
535  if ( rootAddr ) debug() << "[ " << rootAddr->par()[0] << ", " << rootAddr->par()[1] << " ]";
536  debug() << " )" << endmsg;
537  }
538  if ( UNLIKELY( !fwd( []( Partition& p ) {
539  return p.store->empty() ? StatusCode::SUCCESS : StatusCode::FAILURE;
540  } ).isSuccess() ) ) {
541  throw GaudiException{"setRoot called with non-empty store", "EvtStoreSvc", StatusCode::FAILURE};
542  }
543  if ( !rootAddr ) return Status::INVALID_OBJ_ADDR; // Precondition: Address must be valid
544  if ( !m_followLinksToAncestors ) m_onlyThisID = rootAddr->par()[0];
545  auto object = createObj( *m_dataLoader, *rootAddr ); // Call data loader
546  if ( !object ) return Status::INVALID_OBJECT;
547  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Root Object " << root_path << " created " << endmsg; }
548  LocalArena dummy_arena{root_path.size() + 1};
549  auto dummy = Entry{root_path, {}, {}, &dummy_arena};
550  object->setRegistry( &dummy );
551  rootAddr->setRegistry( &dummy );
552  auto status = m_dataLoader->fillObjRefs( rootAddr.get(), object.get() );
553  if ( status.isSuccess() ) {
554  auto pObject = object.get();
555  status = registerObject( nullptr, root_path, object.release() );
556  if ( status.isSuccess() ) pObject->registry()->setAddress( rootAddr.release() );
557  }
558  return status;
559 }
561  return registerAddress( nullptr, path, pAddr );
562 }
564  auto addr = std::unique_ptr<IOpaqueAddress>( pAddr );
565  if ( !addr ) return Status::INVALID_OBJ_ADDR; // Precondition: Address must be valid
566  if ( msgLevel( MSG::DEBUG ) ) {
567  debug() << "registerAddress( (IRegistry*)" << (void*)pReg << ", " << path << ", (IOpaqueAddress*)" << addr.get()
568  << "[ " << addr->par()[0] << ", " << addr->par()[1] << " ]"
569  << " )" << endmsg;
570  }
571  if ( path.empty() || path[0] != '/' ) return StatusCode::FAILURE;
572  if ( !m_onlyThisID.empty() && addr->par()[0] != m_onlyThisID ) {
573  if ( msgLevel( MSG::DEBUG ) )
574  debug() << "Attempt to load " << addr->par()[1] << " from file " << addr->par()[0] << " blocked -- different file"
575  << endmsg;
576  return StatusCode::SUCCESS;
577  }
578  if ( std::any_of( m_inhibitPrefixes.begin(), m_inhibitPrefixes.end(),
579  [addrPath = addr->par()[1]]( std::string_view prefix ) {
580  return boost::algorithm::starts_with( addrPath, prefix );
581  } ) ) {
582  if ( msgLevel( MSG::DEBUG ) )
583  debug() << "Attempt to load " << addr->par()[1] << " from file " << addr->par()[0] << " blocked -- path inhibited"
584  << endmsg;
585  return StatusCode::SUCCESS;
586  }
587 
588  auto object = createObj( *m_dataLoader, *addr ); // Call data loader
589  if ( !object ) return Status::INVALID_OBJECT;
590  auto fullpath = ( pReg ? pReg->identifier() : m_rootName.value() ) + std::string{path};
591  // the data loader expects the path _including_ the root
592  LocalArena dummy_arena{fullpath.size() + 1};
593  auto dummy = Entry{fullpath, {}, {}, &dummy_arena};
594  object->setRegistry( &dummy );
595  addr->setRegistry( &dummy );
596  auto status = m_dataLoader->fillObjRefs( addr.get(), object.get() );
597  if ( !status.isSuccess() ) return status;
598  // note: put will overwrite the registry in pObject to point at the
599  // one actually used -- so we do not dangle, pointing at dummy beyond its
600  // lifetime
601  if ( msgLevel( MSG::DEBUG ) ) {
602  auto ptr = object.get();
603  debug() << "registerAddress: " << std::quoted( normalize_path( fullpath, rootName() ) ) << " (DataObject*)"
604  << static_cast<void*>( ptr ) << ( ptr ? " -> " + System::typeinfoName( typeid( *ptr ) ) : std::string{} )
605  << endmsg;
606  }
607  fwd( [&]( Partition& p ) {
608  p.store->put( normalize_path( fullpath, rootName() ), std::move( object ), std::move( addr ) );
609  return StatusCode::SUCCESS;
610  } ).ignore();
611  return status;
612 }
613 StatusCode EvtStoreSvc::registerObject( std::string_view parentPath, std::string_view objectPath,
614  DataObject* pObject ) {
615  return parentPath.empty()
616  ? registerObject( nullptr, objectPath, pObject )
617  : registerObject( nullptr, std::string{parentPath}.append( "/" ).append( objectPath ), pObject );
618 }
619 StatusCode EvtStoreSvc::registerObject( DataObject* parentObj, std::string_view path, DataObject* pObject ) {
620  if ( parentObj ) return StatusCode::FAILURE;
621  return fwd( [&, object = std::unique_ptr<DataObject>( pObject ),
622  path = normalize_path( path, rootName() )]( Partition& p ) mutable {
623  if ( m_forceLeaves ) {
624  auto dir = path;
625  for ( auto i = dir.rfind( '/' ); i != std::string_view::npos; i = dir.rfind( '/' ) ) {
626  dir = dir.substr( 0, i );
627  if ( !p.store->find( dir ) ) {
628  if ( msgLevel( MSG::DEBUG ) ) {
629  debug() << "registerObject: adding directory " << std::quoted( dir ) << endmsg;
630  }
631  p.store->put( dir, std::unique_ptr<DataObject>{} );
632  }
633  }
634  }
635  if ( msgLevel( MSG::DEBUG ) ) {
636  auto ptr = object.get();
637  debug() << "registerObject: " << std::quoted( path ) << " (DataObject*)" << static_cast<void*>( ptr )
638  << ( ptr ? " -> " + System::typeinfoName( typeid( *ptr ) ) : std::string{} ) << endmsg;
639  }
640  p.store->put( path, std::move( object ) );
641  return StatusCode::SUCCESS;
642  } );
643 }
644 StatusCode EvtStoreSvc::retrieveObject( IRegistry* pDirectory, std::string_view path, DataObject*& pObject ) {
645  if ( pDirectory ) return StatusCode::FAILURE;
646  return fwd( [&]( Partition& p ) {
647  path = normalize_path( path, rootName() );
648  pObject = const_cast<DataObject*>( p.store->get( path ) );
649  if ( msgLevel( MSG::DEBUG ) ) {
650  debug() << "retrieveObject: " << std::quoted( path ) << " (DataObject*)" << (void*)pObject
651  << ( pObject ? " -> " + System::typeinfoName( typeid( *pObject ) ) : std::string{} ) << endmsg;
652  }
653  return pObject ? StatusCode::SUCCESS : StatusCode::FAILURE;
654  } );
655 }
656 StatusCode EvtStoreSvc::findObject( IRegistry* pDirectory, std::string_view path, DataObject*& pObject ) {
657  return retrieveObject( pDirectory, path, pObject );
658 }
659 StatusCode EvtStoreSvc::findObject( std::string_view fullPath, DataObject*& pObject ) {
660  return retrieveObject( nullptr, fullPath, pObject );
661 }
663  return fwd( [&]( Partition& p ) { return p.store->erase( sr ) != 0 ? StatusCode::SUCCESS : StatusCode::FAILURE; } );
664 }
666  auto i = std::find( m_preLoads.begin(), m_preLoads.begin(), item );
667  if ( i == m_preLoads.end() ) m_preLoads.push_back( item );
668  return StatusCode::SUCCESS;
669 }
671  auto i = std::remove( m_preLoads.begin(), m_preLoads.begin(), item );
672  m_preLoads.erase( i, m_preLoads.end() );
673  return StatusCode::SUCCESS;
674 }
676  for ( const auto& i : m_preLoads ) {
677  DataObject* pObj;
678  if ( msgLevel( MSG::DEBUG ) ) debug() << "Preloading " << i.path() << endmsg;
679  retrieveObject( nullptr, i.path(), pObj ).ignore();
680  }
681  return StatusCode::SUCCESS;
682 }
virtual const std::string * par() const =0
Retrieve String parameters.
#define UNLIKELY(x)
Definition: Kernel.h:106
constexpr auto size(const T &, Args &&...) noexcept
Out1 * put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
constexpr double sr
StatusCode setNumberOfStores(size_t slots) override
Set the number of event slots (copies of DataSvc objects).
Define general base for Gaudi exception.
std::size_t poolSize() const
T distance(T... args)
StatusCode setDataLoader(IConversionSvc *svc, IDataProviderSvc *dpsvc) override
IRegistry * registry() const
Get pointer to Registry.
Definition: DataObject.h:82
virtual StatusCode createObj(IOpaqueAddress *pAddress, DataObject *&refpObject)=0
Create the transient representation of an object.
Implementation of property with value of concrete type.
Definition: Property.h:370
Gaudi::StateMachine::State FSMState() const override
Definition: Service.h:62
Gaudi::Property< bool > m_followLinksToAncestors
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:308
virtual bool analyse(IRegistry *pObject, int level)=0
Analyse the data object.
StatusCode resetPreLoad() override
StatusCode updateObject(IRegistry *) override
StatusCode initialize() override
SmartIF< IConversionSvc > m_dataLoader
virtual StatusCode setDataProvider(IDataProviderSvc *pService)=0
Set Data provider service.
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
std::vector< DataStoreItem > m_preLoads
Items to be pre-loaded.
Gaudi::Property< std::string > m_rootName
virtual const name_type & name() const =0
Name of the directory (or key)
StatusCode clearSubTree(DataObject *obj) override
tbb::concurrent_queue< size_t > m_freeSlots
T end(T... args)
StatusCode removePreLoadItem(const DataStoreItem &) override
StatusCode traverseSubTree(std::string_view, IDataStoreAgent *) override
StatusCode retrieveObject(IRegistry *pDirectory, std::string_view path, DataObject *&pObject) override
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
StatusCode traverseTree(IDataStoreAgent *pAgent) override
Data provider interface definition.
T remove(T... args)
Description of the DataStoreItem class.
Definition: DataStoreItem.h:27
STL class.
Gaudi::Property< size_t > m_slots
GAUDI_API int backTrace(void **addresses, const int depth)
size_t freeSlots() override
bool exists(const DataObjID &id) override
StatusCode objectParent(const DataObject *, IRegistry *&) override
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
Invalid root path object cannot be retrieved or stored.
StatusCode linkObject(std::string_view, DataObject *) override
#define DECLARE_COMPONENT(type)
Gaudi::Property< bool > m_forceLeaves
T push_back(T... args)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
StatusCode preLoad() override
std::vector< Synced< Partition > > m_partitions
The actual store(s)
StatusCode clearSubTree(std::string_view) override
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:61
StatusCode updateObject(DataObject *) override
T append(T... args)
StatusCode finalize() override
virtual unsigned long addRef()=0
Add reference to object.
T erase(T... args)
size_t allocateStore(int evtnumber) override
Allocate a store partition for a given event number.
T lock(T... args)
The IRegistry represents the entry door to the environment any data object residing in a transient da...
Definition: IRegistry.h:32
string prefix
Definition: gaudirun.py:343
size_t getNumberOfStores() const override
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
T reset(T... args)
def end
Definition: IOTest.py:123
unsigned int CLID
Class ID definition.
Definition: ClassID.h:18
StatusCode unlinkObject(DataObject *, std::string_view) override
T clear(T... args)
StatusCode unregisterObject(std::string_view) override
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
T move(T... args)
virtual DataObject * object() const =0
Retrieve object behind the link.
StatusCode objectParent(const IRegistry *, IRegistry *&) override
T count(T... args)
TTHREAD_TLS(Synced< Partition > *) s_current
StatusCode unregisterAddress(IRegistry *, std::string_view) override
StatusCode objectLeaves(const IRegistry *, std::vector< IRegistry * > &) override
StatusCode unregisterObject(DataObject *obj, std::string_view sr) override
#define LIKELY(x)
Definition: Kernel.h:105
T get(T... args)
StatusCode unregisterObject(DataObject *obj) override
StatusCode linkObject(IRegistry *, std::string_view, DataObject *) override
StatusCode clearStore() override
T find(T... args)
T size(T... args)
const StatusCode & ignore() const
Ignore/check StatusCode.
Definition: StatusCode.h:168
STL class.
virtual StatusCode fillObjRefs(IOpaqueAddress *pAddress, DataObject *pObject)=0
Resolve the references of the created transient object.
StatusCode selectStore(size_t partition) override
Activate a partition object. The identifies the partition uniquely.
STL class.
Generic data agent interface.
size_t getPartitionNumber(int eventnumber) const override
Get the partition number corresponding to a given event.
std::string_view m_onlyThisID
Base class used to extend a class implementing other interfaces.
Definition: extends.h:20
T begin(T... args)
virtual unsigned long release()=0
release reference to object
virtual void setAddress(IOpaqueAddress *pAddress)=0
Set/Update Opaque storage address.
Gaudi::Accumulators::AveragingCounter< std::size_t > m_usedPoolSize
StatusCode freeStore(size_t partition) override
Free a store partition.
T any_of(T... args)
StatusCode registerAddress(std::string_view fullPath, IOpaqueAddress *pAddress) override
StatusCode objectLeaves(const DataObject *, std::vector< IRegistry * > &) override
StatusCode unlinkObject(IRegistry *, std::string_view) override
string s
Definition: gaudirun.py:328
StatusCode setRoot(std::string root_name, DataObject *pObject) override
constexpr static const auto FAILURE
Definition: StatusCode.h:101
virtual IDataProviderSvc * dataSvc() const =0
Retrieve pointer to Transient Store.
StatusCode unregisterAddress(std::string_view) override
void initStore(Partition &p) const
virtual const id_type & identifier() const =0
Full identifier (or key)
AttribStringParser::Iterator begin(const AttribStringParser &parser)
virtual void setRegistry(IRegistry *r)=0
Update directory pointer.
Opaque address interface definition.
StatusCode registerObject(std::string_view parentPath, std::string_view objectPath, DataObject *pObject) override
#define GAUDI_API
Definition: Kernel.h:81
A DataObject is the base class of any identifiable object on any data store.
Definition: DataObject.h:40
A fast memory arena that does not track deallocations.
Definition: Monotonic.h:46
T equal(T... args)
Use a minimal event store implementation, and adds everything required to satisfy the IDataProviderSv...
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
StatusCode addPreLoadItem(const DataStoreItem &) override
Gaudi::Property< std::vector< std::string > > m_inhibitPrefixes
StatusCode findObject(IRegistry *pDirectory, std::string_view path, DataObject *&pObject) override
static GAUDI_API void setNumConcEvents(const std::size_t &nE)
const std::string & rootName() const override
StatusCode traverseSubTree(DataObject *obj, IDataStoreAgent *pAgent) override
void fillStats(Partition &p) const
StatusCode unlinkObject(std::string_view) override