23#include <tbb/concurrent_queue.h>
25#include <ThreadLocalStorage.h>
34#include <unordered_map>
44 using pool_string = std::basic_string<char, std::char_traits<char>, LocalAlloc<char>>;
47 std::unique_ptr<DataObject> m_data;
48 std::unique_ptr<IOpaqueAddress> m_addr;
49 pool_string m_identifierStorage;
50 mutable std::optional<std::string> m_identifier;
51 static IDataProviderSvc* s_svc;
54 using allocator_type = LocalAlloc<char>;
55 static void setDataProviderSvc( IDataProviderSvc* p ) { s_svc = p; }
57 Entry( std::string_view
id, std::unique_ptr<DataObject> data, std::unique_ptr<IOpaqueAddress> addr,
58 allocator_type alloc ) noexcept
59 : m_data{ std::move( data ) }, m_addr{ std::move( addr ) }, m_identifierStorage{
id, alloc } {
60 if ( m_data ) m_data->setRegistry(
this );
61 if ( m_addr ) m_addr->setRegistry(
this );
63 Entry(
const Entry& ) =
delete;
64 Entry& operator=(
const Entry& rhs ) =
delete;
65 Entry( Entry&& rhs ) =
delete;
66 Entry& operator=( Entry&& rhs ) =
delete;
69 unsigned long addRef()
override {
return -1; }
70 unsigned long release()
override {
return -1; }
71 const name_type&
name()
const override {
73 if ( !m_identifier ) m_identifier.emplace( m_identifierStorage );
76 const id_type& identifier()
const override {
77 if ( !m_identifier ) m_identifier.emplace( m_identifierStorage );
80 std::string_view identifierView()
const {
return m_identifierStorage; }
81 IDataProviderSvc* dataSvc()
const override {
return s_svc; }
83 IOpaqueAddress* address()
const override {
return m_addr.get(); }
84 void setAddress( IOpaqueAddress* iAddr )
override {
85 m_addr.reset( iAddr );
86 if ( m_addr ) m_addr->setRegistry(
this );
92 std::unordered_map<std::string_view, Entry, std::hash<std::string_view>, std::equal_to<std::string_view>,
93 LocalAlloc<std::pair<const std::string_view, Entry>>>;
94 using OrderedMap = std::map<std::string_view, Entry>;
96 template <
typename Map = UnorderedMap>
98 LocalArena m_resource;
99 std::size_t m_est_size;
101 std::optional<Map> m_store{ std::in_place, &m_resource };
102 static_assert( std::is_same_v<typename Map::key_type, std::string_view> );
104 const auto& emplace( std::string_view k, std::unique_ptr<DataObject> d, std::unique_ptr<IOpaqueAddress> a = {} ) {
107 auto [i, b] = m_store->try_emplace( k, k, std::move( d ), std::move( a ), &m_resource );
108 if ( !b )
throw std::runtime_error(
"failed to insert " + std::string{ k } );
109 auto nh = m_store->extract( i );
110 nh.key() = nh.mapped().identifierView();
111 auto r = m_store->insert( std::move( nh ) );
112 if ( !r.inserted )
throw std::runtime_error(
"failed to insert " + std::string{ k } );
113 return r.position->second;
117 Store( std::size_t est_size, std::size_t pool_size ) : m_resource{ pool_size }, m_est_size{ est_size } {}
118 [[nodiscard]]
bool empty()
const {
return m_store->empty(); }
119 [[nodiscard]] std::size_t
size()
const {
return m_store->size(); }
120 [[nodiscard]] std::size_t used_bytes() const noexcept {
return m_resource.size(); }
121 [[nodiscard]] std::size_t used_blocks() const noexcept {
return m_resource.num_blocks(); }
122 [[nodiscard]] std::size_t used_buckets()
const {
return m_store->bucket_count(); }
123 [[nodiscard]] std::size_t num_allocations() const noexcept {
return m_resource.num_allocations(); }
128 m_store.emplace( m_est_size, &m_resource );
131 const DataObject*
put( std::string_view k, std::unique_ptr<DataObject> data,
132 std::unique_ptr<IOpaqueAddress> addr = {} ) {
133 return emplace( k, std::move( data ), std::move( addr ) ).object();
136 const Entry* d = find( k );
137 return d ? d->object() :
nullptr;
139 const Entry* find( std::string_view k )
const noexcept {
140 auto i = m_store->find( k );
141 return i != m_store->end() ? &( i->second ) :
nullptr;
144 [[nodiscard]]
auto begin() const noexcept {
return m_store->begin(); }
145 [[nodiscard]]
auto end() const noexcept {
return m_store->end(); }
146 void clear() noexcept { m_store->clear(); }
147 auto erase( std::string_view k ) {
return m_store->erase( k ); }
148 template <
typename Predicate>
149 void erase_if( Predicate p ) {
150 auto i = m_store->begin();
151 auto end = m_store->end();
153 if ( std::invoke( p, std::as_const( *i ) ) )
154 i = m_store->erase( i );
164 throw std::logic_error{
"Unsupported Function Called: " +
s +
"\n" + trace };
168 std::string_view normalize_path( std::string_view path, std::string_view prefix ) {
171 if ( !
path.empty() &&
path.front() ==
'/' )
path.remove_prefix( 1 );
177 auto status = cnv.
createObj( &addr, pObject );
178 auto object = std::unique_ptr<DataObject>( pObject );
179 if ( status.isFailure() )
object.reset();
184 struct Partition final {
188 std::optional<Store<>> store;
189 int eventNumber = -1;
190 std::string_view onlyThisID{};
194 TTHREAD_TLS( SynchronizedPartition* ) s_current =
nullptr;
196 template <
typename Fun>
198 return s_current ? s_current->with_lock( std::forward<Fun>( f ) )
215 Gaudi::Concurrency::ConcurrencyManager> {
219 "force creation of default leaves on registerObject" };
225 "Estimated number of buckets in the store" };
234 auto n_allocs = p.store->num_allocations();
265 "InhibitedPathPrefixes",
267 "Prefixes of TES locations that will not be loaded by the persistency service " };
269 this,
"FollowLinksToAncestors",
true,
270 "Load objects which reside in files other than the one corresponding to the root of the event store" };
273 using extends::extends;
275 CLID rootCLID()
const override;
276 const std::string& rootName()
const override;
279 size_t allocateStore(
int evtnumber )
override;
280 StatusCode freeStore(
size_t partition )
override;
282 StatusCode selectStore(
size_t partition )
override;
284 StatusCode clearStore(
size_t partition )
override;
285 StatusCode setNumberOfStores(
size_t slots )
override;
287 size_t getPartitionNumber(
int eventnumber )
const override;
290 return findObject(
id.fullKey(), pObject ).isSuccess();
299 StatusCode clearSubTree( std::string_view )
override;
318 StatusCode registerObject( std::string_view parentPath, std::string_view objectPath,
DataObject* pObject )
override;
321 StatusCode unregisterObject( std::string_view )
override;
354 Entry::setDataProviderSvc(
this );
355 extends::initialize().ignore();
363 synced_p.with_lock( [
this]( Partition& p ) {
initStore( p ); } );
377 info() <<
"Mean memory pool usage: " << float( 1e-3f *
float(
m_usedPoolSize.mean() ) ) <<
" KiB serving "
383 return extends::finalize();
401 size_t slot = std::string::npos;
403 assert( slot != std::string::npos );
405 [[maybe_unused]]
auto prev =
m_partitions[slot].with_lock(
406 [evtnumber]( Partition& p ) {
return std::exchange( p.eventNumber, evtnumber ); } );
407 assert( prev == -1 );
413 if ( slots <
size_t{ 1 } ) {
414 error() <<
"Invalid number of slots (" << slots <<
")" <<
endmsg;
418 error() <<
"Too late to change the number of slots!" <<
endmsg;
427 auto i = std::find_if(
429 Gaudi::cxx::with_lock( [eventnumber](
const Partition& p ) {
return p.eventNumber == eventnumber; } ) );
440 auto prev =
m_partitions[partition].with_lock( []( Partition& p ) {
return std::exchange( p.eventNumber, -1 ); } );
447 return m_partitions[partition].with_lock( [
this]( Partition& p ) {
455 top = normalize_path( top,
rootName() );
456 return fwd( [&]( Partition& p ) {
457 p.store->erase_if( [top](
const auto& value ) {
return value.first.starts_with( top ); } );
462 return fwd( [
this]( Partition& p ) {
470 return fwd( [&]( Partition& p ) {
471 top = normalize_path( top,
rootName() );
472 unsigned int nbSlashesInRootName = std::count(
rootName().begin(),
rootName().end(),
'/' );
473 auto cmp = [](
const Entry* lhs,
const Entry* rhs ) {
return lhs->identifier() < rhs->identifier(); };
474 std::set<
const Entry*,
decltype( cmp )> keys{ std::move( cmp ) };
475 for (
const auto& v : *p.store ) {
476 if ( v.second.identifier().starts_with( top ) ) keys.insert( &v.second );
478 auto k = keys.begin();
479 while ( k != keys.end() ) {
480 const auto&
id = ( *k )->identifier();
481 int level = std::count(
id.begin(),
id.end(),
'/' ) + nbSlashesInRootName;
482 bool accept = pAgent->
analyse(
const_cast<Entry*
>( *( k++ ) ), level );
484 k = std::find_if_not( k, keys.end(), [&
id](
const auto& e ) { return e->identifier().starts_with( id ); } );
492 debug() <<
"setRoot( " << root_path <<
", (DataObject*)" << (
void*)pObject <<
" )" <<
endmsg;
494 if ( !fwd( []( Partition& p ) {
502 auto rootAddr = std::unique_ptr<IOpaqueAddress>( pRootAddr );
504 debug() <<
"setRoot( " << root_path <<
", (IOpaqueAddress*)" << rootAddr.get();
505 if ( rootAddr )
debug() <<
"[ " << rootAddr->par()[0] <<
", " << rootAddr->par()[1] <<
" ]";
508 if ( !fwd( []( Partition& p ) {
513 if ( !rootAddr )
return Status::INVALID_OBJ_ADDR;
515 fwd( [&]( Partition& p ) {
516 p.onlyThisID = rootAddr->par()[0];
521 if ( !
object )
return Status::INVALID_OBJECT;
523 LocalArena dummy_arena{ root_path.size() + 1 };
524 auto dummy = Entry{ root_path, {}, {}, &dummy_arena };
525 object->setRegistry( &dummy );
526 rootAddr->setRegistry( &dummy );
527 auto status =
m_dataLoader->fillObjRefs( rootAddr.get(),
object.get() );
528 if ( status.isSuccess() ) {
529 auto pObject =
object.get();
539 auto addr = std::unique_ptr<IOpaqueAddress>( pAddr );
540 if ( !addr )
return Status::INVALID_OBJ_ADDR;
542 debug() <<
"registerAddress( (IRegistry*)" << (
void*)pReg <<
", " << path <<
", (IOpaqueAddress*)" << addr.get()
543 <<
"[ " << addr->
par()[0] <<
", " << addr->
par()[1] <<
" ]"
547 const auto onlyThisID =
548 s_current ? s_current->with_lock( [](
const Partition& p ) {
return p.onlyThisID; } ) : std::string_view{};
549 if ( !onlyThisID.empty() && addr->
par()[0] != onlyThisID ) {
551 debug() <<
"Attempt to load " << addr->
par()[1] <<
" from file " << addr->
par()[0] <<
" blocked -- different file"
557 [addrPath = addr->
par()[1]]( std::string_view prefix ) { return addrPath.starts_with( prefix ); } ) ) {
559 debug() <<
"Attempt to load " << addr->
par()[1] <<
" from file " << addr->
par()[0] <<
" blocked -- path inhibited"
565 if ( !
object )
return Status::INVALID_OBJECT;
568 LocalArena dummy_arena{ fullpath.size() + 1 };
569 auto dummy = Entry{ fullpath, {}, {}, &dummy_arena };
570 object->setRegistry( &dummy );
572 auto status =
m_dataLoader->fillObjRefs( addr.get(),
object.get() );
573 if ( !status.isSuccess() )
return status;
578 auto ptr =
object.get();
579 debug() <<
"registerAddress: " << std::quoted( normalize_path( fullpath,
rootName() ) ) <<
" (DataObject*)"
580 <<
static_cast<void*
>( ptr ) << ( ptr ?
" -> " +
System::typeinfoName(
typeid( *ptr ) ) : std::string{} )
583 fwd( [&]( Partition& p ) {
584 p.store->put( normalize_path( fullpath,
rootName() ), std::move(
object ), std::move( addr ) );
591 return parentPath.empty()
593 :
registerObject(
nullptr, std::string{ parentPath }.append(
"/" ).append( objectPath ), pObject );
597 return fwd( [&,
object = std::unique_ptr<DataObject>( pObject ),
598 path = normalize_path( path,
rootName() )]( Partition& p )
mutable {
601 for (
auto i = dir.rfind(
'/' ); i != std::string_view::npos; i = dir.rfind(
'/' ) ) {
602 dir = dir.substr( 0, i );
603 if ( !p.store->find( dir ) ) {
605 debug() <<
"registerObject: adding directory " << std::quoted( dir ) <<
endmsg;
607 p.store->put( dir, std::unique_ptr<DataObject>{} );
612 auto ptr =
object.get();
613 debug() <<
"registerObject: " << std::quoted( path ) <<
" (DataObject*)" <<
static_cast<void*
>( ptr )
616 p.store->put( path, std::move(
object ) );
622 return fwd( [&]( Partition& p ) {
623 path = normalize_path( path,
rootName() );
624 pObject =
const_cast<DataObject*
>( p.store->get( path ) );
626 debug() <<
"retrieveObject: " << std::quoted( path ) <<
" (DataObject*)" << (
void*)pObject
639 sr = normalize_path( sr,
rootName() );
unsigned int CLID
Class ID definition.
TTHREAD_TLS(SynchronizedPartition *) s_current
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
#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.
IRegistry * registry() const
Get pointer to Registry.
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
void fillStats(Partition &p) const
StatusCode setNumberOfStores(size_t slots) override
Set the number of event slots (copies of DataSvc objects).
std::vector< SynchronizedPartition > m_partitions
The actual store(s).
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.
static void setNumConcEvents(const std::size_t &nE)
Set the number of concurrent events (for MT).
Implementation of property with value of concrete type.
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...
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
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Small smart pointer class with automatic reference counting for IInterface.
This class is used for returning status codes from appropriate routines.
void ignore() const
Allow discarding a StatusCode without warning.
constexpr static const auto SUCCESS
constexpr static const auto FAILURE
Base class used to extend a class implementing other interfaces.
::Gaudi::Allocator::Arena<::Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >, T, DefaultResource > MonotonicArena
auto put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
GAUDI_API std::string path(const AIDA::IBaseHistogram *aida)
get the path in THS for AIDA histogram
AttribStringParser::Iterator begin(const AttribStringParser &parser)
get
decorate the vector of properties
GAUDI_API int backTrace(void **addresses, const int depth)
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
constexpr auto size(const T &, Args &&...) noexcept
A counter aiming at computing sum and average.