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