22#include <tbb/concurrent_queue.h>
24#include <ThreadLocalStorage.h>
33#include <unordered_map>
43 using pool_string = std::basic_string<char, std::char_traits<char>, LocalAlloc<char>>;
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;
53 using allocator_type = LocalAlloc<char>;
54 static void setDataProviderSvc( IDataProviderSvc* p ) { s_svc = p; }
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 );
62 Entry(
const Entry& ) =
delete;
63 Entry& operator=(
const Entry& rhs ) =
delete;
64 Entry( Entry&& rhs ) =
delete;
65 Entry& operator=( Entry&& rhs ) =
delete;
68 unsigned long addRef()
override {
return -1; }
69 unsigned long release()
override {
return -1; }
70 const name_type&
name()
const override {
72 if ( !m_identifier ) m_identifier.emplace( m_identifierStorage );
75 const id_type& identifier()
const override {
76 if ( !m_identifier ) m_identifier.emplace( m_identifierStorage );
79 std::string_view identifierView()
const {
return m_identifierStorage; }
80 IDataProviderSvc* dataSvc()
const override {
return s_svc; }
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 );
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>;
95 template <
typename Map = UnorderedMap>
97 LocalArena m_resource;
98 std::size_t m_est_size;
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> );
103 const auto& emplace( std::string_view k, std::unique_ptr<DataObject> d, std::unique_ptr<IOpaqueAddress> a = {} ) {
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();
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;
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(); }
127 m_store.emplace( m_est_size, &m_resource );
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();
135 const Entry* d = find( k );
136 return d ? d->object() :
nullptr;
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;
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();
152 if ( std::invoke( p, std::as_const( *i ) ) )
153 i = m_store->erase( i );
163 throw std::logic_error{
"Unsupported Function Called: " +
s +
"\n" + trace };
167 std::string_view normalize_path( std::string_view path, std::string_view prefix ) {
170 if ( !
path.empty() &&
path.front() ==
'/' )
path.remove_prefix( 1 );
176 auto status = cnv.
createObj( &addr, pObject );
177 auto object = std::unique_ptr<DataObject>( pObject );
178 if ( status.isFailure() )
object.reset();
183 struct Partition final {
187 std::optional<Store<>> store;
188 int eventNumber = -1;
191 template <
typename T,
typename Mutex = std::recursive_mutex,
typename ReadLock = std::scoped_lock<Mutex>,
192 typename WriteLock = ReadLock>
198 template <
typename F>
200 WriteLock lock{ m_mtx };
203 template <
typename F>
204 decltype( auto )
with_lock( F&& f )
const {
205 ReadLock lock{ m_mtx };
210 template <
typename Fun>
212 return [f = std::forward<Fun>( f )](
auto& p ) ->
decltype(
auto ) {
return p.with_lock( f ); };
215 TTHREAD_TLS( Synced<Partition>* ) s_current =
nullptr;
217 template <
typename Fun>
219 return s_current ? s_current->with_lock( std::forward<Fun>( f ) )
239 "force creation of default leaves on registerObject" };
245 "Estimated number of buckets in the store" };
254 auto n_allocs = p.store->num_allocations();
285 "InhibitedPathPrefixes",
287 "Prefixes of TES locations that will not be loaded by the persistency service " };
289 this,
"FollowLinksToAncestors",
true,
290 "Load objects which reside in files other than the one corresponding to the root of the event store" };
294 using extends::extends;
297 const std::string&
rootName()
const override;
303 StatusCode selectStore(
size_t partition )
override;
305 StatusCode clearStore(
size_t partition )
override;
306 StatusCode setNumberOfStores(
size_t slots )
override;
308 size_t getPartitionNumber(
int eventnumber )
const override;
311 return findObject(
id.fullKey(), pObject ).isSuccess();
320 StatusCode clearSubTree( std::string_view )
override;
339 StatusCode registerObject( std::string_view parentPath, std::string_view objectPath,
DataObject* pObject )
override;
342 StatusCode unregisterObject( std::string_view )
override;
375 Entry::setDataProviderSvc(
this );
376 extends::initialize().ignore();
384 synced_p.with_lock( [
this]( Partition& p ) {
initStore( p ); } );
398 info() <<
"Mean memory pool usage: " << float( 1e-3f *
float(
m_usedPoolSize.mean() ) ) <<
" KiB serving "
404 return extends::finalize();
422 size_t slot = std::string::npos;
424 assert( slot != std::string::npos );
426 [[maybe_unused]]
auto prev =
m_partitions[slot].with_lock(
427 [evtnumber]( Partition& p ) {
return std::exchange( p.eventNumber, evtnumber ); } );
428 assert( prev == -1 );
434 if ( slots <
size_t{ 1 } ) {
435 error() <<
"Invalid number of slots (" << slots <<
")" <<
endmsg;
439 error() <<
"Too late to change the number of slots!" <<
endmsg;
449 with_lock( [eventnumber](
const Partition& p ) {
return p.eventNumber == eventnumber; } ) );
460 auto prev =
m_partitions[partition].with_lock( []( Partition& p ) {
return std::exchange( p.eventNumber, -1 ); } );
468 return m_partitions[partition].with_lock( [
this]( Partition& p ) {
475 top = normalize_path( top,
rootName() );
476 return fwd( [&]( Partition& p ) {
477 p.store->erase_if( [top](
const auto& value ) {
return value.first.starts_with( top ); } );
483 return fwd( [
this]( Partition& p ) {
490 return fwd( [&]( Partition& p ) {
491 top = normalize_path( top,
rootName() );
492 unsigned int nbSlashesInRootName = std::count(
rootName().begin(),
rootName().end(),
'/' );
493 auto cmp = [](
const Entry* lhs,
const Entry* rhs ) {
return lhs->identifier() < rhs->identifier(); };
494 std::set<
const Entry*,
decltype( cmp )> keys{ std::move( cmp ) };
495 for (
const auto& v : *p.store ) {
496 if ( v.second.identifier().starts_with( top ) ) keys.insert( &v.second );
498 auto k = keys.begin();
499 while ( k != keys.end() ) {
500 const auto&
id = ( *k )->identifier();
501 int level = std::count(
id.begin(),
id.end(),
'/' ) + nbSlashesInRootName;
502 bool accept = pAgent->
analyse(
const_cast<Entry*
>( *( k++ ) ), level );
504 k = std::find_if_not( k, keys.end(), [&
id](
const auto& e ) { return e->identifier().starts_with( id ); } );
512 debug() <<
"setRoot( " << root_path <<
", (DataObject*)" << (
void*)pObject <<
" )" <<
endmsg;
514 if ( !fwd( []( Partition& p ) {
522 auto rootAddr = std::unique_ptr<IOpaqueAddress>( pRootAddr );
524 debug() <<
"setRoot( " << root_path <<
", (IOpaqueAddress*)" << rootAddr.get();
525 if ( rootAddr )
debug() <<
"[ " << rootAddr->par()[0] <<
", " << rootAddr->par()[1] <<
" ]";
528 if ( !fwd( []( Partition& p ) {
533 if ( !rootAddr )
return Status::INVALID_OBJ_ADDR;
536 if ( !
object )
return Status::INVALID_OBJECT;
538 LocalArena dummy_arena{ root_path.size() + 1 };
539 auto dummy = Entry{ root_path, {}, {}, &dummy_arena };
540 object->setRegistry( &dummy );
541 rootAddr->setRegistry( &dummy );
542 auto status =
m_dataLoader->fillObjRefs( rootAddr.get(),
object.get() );
543 if ( status.isSuccess() ) {
544 auto pObject =
object.get();
554 auto addr = std::unique_ptr<IOpaqueAddress>( pAddr );
555 if ( !addr )
return Status::INVALID_OBJ_ADDR;
557 debug() <<
"registerAddress( (IRegistry*)" << (
void*)pReg <<
", " << path <<
", (IOpaqueAddress*)" << addr.get()
558 <<
"[ " << addr->
par()[0] <<
", " << addr->
par()[1] <<
" ]"
564 debug() <<
"Attempt to load " << addr->
par()[1] <<
" from file " << addr->
par()[0] <<
" blocked -- different file"
570 [addrPath = addr->
par()[1]]( std::string_view prefix ) { return addrPath.starts_with( prefix ); } ) ) {
572 debug() <<
"Attempt to load " << addr->
par()[1] <<
" from file " << addr->
par()[0] <<
" blocked -- path inhibited"
578 if ( !
object )
return Status::INVALID_OBJECT;
581 LocalArena dummy_arena{ fullpath.size() + 1 };
582 auto dummy = Entry{ fullpath, {}, {}, &dummy_arena };
583 object->setRegistry( &dummy );
585 auto status =
m_dataLoader->fillObjRefs( addr.get(),
object.get() );
586 if ( !status.isSuccess() )
return status;
591 auto ptr =
object.get();
592 debug() <<
"registerAddress: " << std::quoted( normalize_path( fullpath,
rootName() ) ) <<
" (DataObject*)"
593 <<
static_cast<void*
>( ptr ) << ( ptr ?
" -> " +
System::typeinfoName(
typeid( *ptr ) ) : std::string{} )
596 fwd( [&]( Partition& p ) {
597 p.store->put( normalize_path( fullpath,
rootName() ), std::move(
object ), std::move( addr ) );
604 return parentPath.empty()
606 :
registerObject(
nullptr, std::string{ parentPath }.append(
"/" ).append( objectPath ), pObject );
610 return fwd( [&,
object = std::unique_ptr<DataObject>( pObject ),
611 path = normalize_path( path,
rootName() )]( Partition& p )
mutable {
614 for (
auto i = dir.rfind(
'/' ); i != std::string_view::npos; i = dir.rfind(
'/' ) ) {
615 dir = dir.substr( 0, i );
616 if ( !p.store->find( dir ) ) {
618 debug() <<
"registerObject: adding directory " << std::quoted( dir ) <<
endmsg;
620 p.store->put( dir, std::unique_ptr<DataObject>{} );
625 auto ptr =
object.get();
626 debug() <<
"registerObject: " << std::quoted( path ) <<
" (DataObject*)" <<
static_cast<void*
>( ptr )
629 p.store->put( path, std::move(
object ) );
635 return fwd( [&]( Partition& p ) {
636 path = normalize_path( path,
rootName() );
637 pObject =
const_cast<DataObject*
>( p.store->get( path ) );
639 debug() <<
"retrieveObject: " << std::quoted( path ) <<
" (DataObject*)" << (
void*)pObject
652 sr = normalize_path( sr,
rootName() );
unsigned int CLID
Class ID definition.
TTHREAD_TLS(Synced< Partition > *) 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
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
std::string_view m_onlyThisID
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 GAUDI_API void setNumConcEvents(const std::size_t &nE)
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.