11 #include "ThreadLocalStorage.h" 13 #include "boost/algorithm/string/predicate.hpp" 15 #include "tbb/concurrent_queue.h" 16 #include "tbb/mutex.h" 17 #include "tbb/recursive_mutex.h" 24 #include <type_traits> 25 #include <unordered_map> 42 if ( m_data ) m_data->setRegistry(
this );
45 Entry(
const Entry& ) =
delete;
46 Entry&
operator=(
const Entry& rhs ) =
delete;
47 Entry( Entry&& rhs ) =
delete;
51 unsigned long addRef()
override {
return -1; }
52 unsigned long release()
override {
return -1; }
53 const name_type&
name()
const override {
return m_identifier; }
54 const id_type&
identifier()
const override {
return m_identifier; }
65 template <
typename Map = UnorderedMap>
68 static_assert( std::is_same_v<typename Map::key_type, std::string_view> );
75 auto nh = m_store.extract( i );
76 nh.key() = nh.mapped().identifier();
77 auto r = m_store.insert(
std::move( nh ) );
79 return r.position->second;
84 return emplace( k,
std::move( data ) ).object();
87 const DataObject*
get( std::string_view k )
const noexcept {
88 const Entry* d =
find( k );
89 return d ? d->object() :
nullptr;
91 const Entry*
find( std::string_view k )
const noexcept {
92 auto i = m_store.find( k );
93 return i != m_store.end() ? &( i->second ) :
nullptr;
96 auto begin() const noexcept {
return m_store.begin(); }
97 auto end() const noexcept {
return m_store.end(); }
98 void clear() noexcept { m_store.clear(); }
99 auto erase( std::string_view k ) {
return m_store.erase( k ); }
100 template <
typename Predicate>
101 void erase_if( Predicate p ) {
102 auto i = m_store.begin();
103 auto end = m_store.end();
105 if ( std::invoke( p, std::as_const( *i ) ) )
106 i = m_store.erase( i );
120 std::string_view normalize_path( std::string_view
path, std::string_view
prefix ) {
121 if ( path.size() >= prefix.size() &&
std::equal( prefix.begin(), prefix.end(), path.begin() ) )
122 path.remove_prefix( prefix.size() );
123 if ( !path.empty() && path.front() ==
'/' ) path.remove_prefix( 1 );
129 auto status = cnv.
createObj( &addr, pObject );
131 if ( status.isFailure() )
object.reset();
136 struct Partition final {
138 int eventNumber = -1;
141 template <
typename T,
typename Mutex = tbb::recursive_mutex,
typename ReadLock =
typename Mutex::scoped_lock,
142 typename WriteLock = ReadLock>
148 template <
typename F>
149 decltype(
auto ) with_lock( F&& f ) {
150 WriteLock
lock{m_mtx};
153 template <
typename F>
154 decltype(
auto ) with_lock( F&& f )
const {
155 ReadLock
lock{m_mtx};
160 template <
typename Fun>
161 auto with_lock( Fun&& f ) {
162 return [f = std::forward<Fun>( f )](
auto& p ) -> decltype(
auto ) {
return p.with_lock( f ); };
165 TTHREAD_TLS( Synced<Partition>* ) s_current =
nullptr;
167 template <typename Fun>
169 return s_current ? s_current->with_lock( std::forward<Fun>( f ) )
188 Gaudi::Property<bool> m_forceLeaves{
this,
"ForceLeaves",
false,
"force creation of default leaves on registerObject"};
203 using extends::extends;
205 CLID rootCLID()
const override;
209 size_t allocateStore(
int evtnumber )
override;
210 StatusCode freeStore(
size_t partition )
override;
211 size_t freeSlots()
override {
return m_freeSlots.unsafe_size(); }
212 StatusCode selectStore(
size_t partition )
override;
214 StatusCode clearStore(
size_t partition )
override;
215 StatusCode setNumberOfStores(
size_t slots )
override;
217 size_t getPartitionNumber(
int eventnumber )
const override;
220 return findObject(
id.fullKey(), pObject ).isSuccess();
228 StatusCode clearSubTree( std::string_view )
override;
247 StatusCode registerObject( std::string_view parentPath, std::string_view objectPath,
DataObject* pObject )
override;
250 StatusCode unregisterObject( std::string_view )
override;
255 return !obj ? unregisterObject( sr )
283 Entry::setDataProviderSvc(
this );
284 extends::initialize().ignore();
285 if ( !setNumberOfStores( m_slots ).isSuccess() ) {
286 error() <<
"Cannot set number of slots" <<
endmsg;
290 for (
size_t i = 0; i < m_slots; i++ ) { m_freeSlots.push( i ); }
291 selectStore( 0 ).
ignore();
295 error() <<
"Cannot get IConversionSvc " << m_loader.value() <<
endmsg;
298 return setDataLoader(
loader,
nullptr );
301 setDataLoader(
nullptr,
nullptr ).
ignore();
302 return extends::finalize();
313 m_dataLoader = pDataLoader;
320 size_t slot = std::string::npos;
321 if ( m_freeSlots.try_pop( slot ) ) {
322 assert( slot != std::string::npos );
323 assert( slot < m_partitions.size() );
324 [[maybe_unused]]
auto prev = m_partitions[slot].with_lock(
325 [evtnumber]( Partition& p ) {
return std::exchange( p.eventNumber, evtnumber ); } );
326 assert( prev == -1 );
332 if ( slots <
size_t{1} ) {
333 error() <<
"Invalid number of slots (" << slots <<
")" <<
endmsg;
337 error() <<
"Too late to change the number of slots!" <<
endmsg;
347 with_lock( [eventnumber](
const Partition& p ) {
return p.eventNumber == eventnumber; } ) );
352 s_current = &m_partitions[partition];
357 assert( partition < m_partitions.size() );
358 auto prev = m_partitions[partition].with_lock( []( Partition& p ) {
return std::exchange( p.eventNumber, -1 ); } );
360 m_freeSlots.push( partition );
365 return m_partitions[partition].with_lock( []( Partition& p ) {
371 top = normalize_path( top, rootName() );
372 return fwd( [&]( Partition& p ) {
373 p.store.erase_if( [top](
const auto& value ) {
return boost::algorithm::starts_with( value.first, top ); } );
378 return fwd( []( Partition& p ) {
384 return fwd( [&]( Partition& p ) {
385 top = normalize_path( top, rootName() );
386 auto cmp = [](
const Entry* lhs,
const Entry* rhs ) {
return lhs->identifier() < rhs->identifier(); };
388 for (
const auto& v : p.store ) {
389 if ( boost::algorithm::starts_with( v.second.identifier(), top ) ) keys.insert( &v.second );
391 auto k = keys.begin();
392 while ( k != keys.end() ) {
393 const auto&
id = ( *k )->identifier();
394 always() <<
"analyzing " <<
id <<
endmsg;
396 bool accept = pAgent->
analyse( const_cast<Entry*>( *( k++ ) ), level );
398 while ( k != keys.end() && boost::algorithm::starts_with( ( *k )->identifier(), id ) ) {
399 always() <<
"skipping " << ( *k )->identifier() <<
endmsg;
409 debug() <<
"setRoot( " << root_path <<
", (DataObject*)" << (
void*)pObject <<
" )" <<
endmsg;
411 clearStore().ignore();
412 return registerObject(
nullptr, root_path, pObject );
417 debug() <<
"setRoot( " << root_path <<
", (IOpaqueAddress*)" << (
void*)rootAddr.get() <<
" )" <<
endmsg;
419 clearStore().ignore();
420 if ( !rootAddr )
return Status::INVALID_OBJ_ADDR;
423 debug() <<
"par[0]=" << par[0] <<
endmsg;
424 debug() <<
"par[1]=" << par[1] <<
endmsg;
426 auto object = createObj( *m_dataLoader, *rootAddr );
427 if ( !
object )
return Status::INVALID_OBJECT;
428 if ( msgLevel(
MSG::DEBUG ) ) { debug() <<
"Root Object " << root_path <<
" created " <<
endmsg; }
429 auto dummy = Entry{root_path, {},
std::move( rootAddr )};
430 object->setRegistry( &dummy );
431 auto status = m_dataLoader->fillObjRefs( dummy.address(),
object.get() );
432 return status.isSuccess() ? registerObject(
nullptr, root_path,
object.release() ) : status;
435 return registerAddress(
nullptr, path, pAddr );
440 debug() <<
"registerAddress( (IRegistry*)" << (
void*)pReg <<
", " << path <<
", (IOpaqueAddress*)" << addr.get()
441 <<
"[ " << addr->
par()[0] <<
", " << addr->
par()[1] <<
" ]" 444 if ( !addr )
return Status::INVALID_OBJ_ADDR;
446 auto object = createObj( *m_dataLoader, *addr );
447 if ( !
object )
return Status::INVALID_OBJECT;
450 auto dummy = Entry{fullpath, {},
std::move( addr )};
451 object->setRegistry( &dummy );
452 auto status = m_dataLoader->fillObjRefs( dummy.address(),
object.get() );
453 if ( !status.isSuccess() )
return status;
458 debug() <<
"registerAddress: " << std::quoted( normalize_path( fullpath, rootName() ) ) <<
" (DataObject*)" 462 fwd( [&]( Partition& p ) {
463 p.store.put( normalize_path( fullpath, rootName() ),
std::move(
object ) );
471 debug() <<
"registerObject( " << parentPath <<
", " << objectPath <<
", " << (
void*)pObject <<
" )" <<
endmsg;
473 return parentPath.empty()
474 ? registerObject(
nullptr, objectPath, pObject )
475 : registerObject(
nullptr,
std::string{parentPath}.
append(
"/" ).append( objectPath ), pObject );
479 return fwd( [&]( Partition& p ) {
480 path = normalize_path( path, rootName() );
481 if ( m_forceLeaves ) {
483 for (
auto i = dir.rfind(
'/' ); i != std::string_view::npos; i = dir.rfind(
'/' ) ) {
484 dir = dir.substr( 0, i );
485 if ( !p.store.find( dir ) ) {
487 debug() <<
"registerObject: adding directory " << std::quoted( dir ) <<
endmsg;
489 p.store.put( dir, std::make_unique<DataObject>() );
494 debug() <<
"registerObject: " << std::quoted( path ) <<
" (DataObject*)" << (
void*)pObject
503 return fwd( [&]( Partition& p ) {
504 path = normalize_path( path, rootName() );
505 pObject =
const_cast<DataObject*
>( p.store.get( path ) );
507 debug() <<
"retrieveObject: " << std::quoted( path ) <<
" (DataObject*)" << (
void*)pObject
514 return retrieveObject( pDirectory, path, pObject );
517 return retrieveObject(
nullptr, fullPath, pObject );
523 auto i =
std::find( m_preLoads.begin(), m_preLoads.begin(), item );
524 if ( i == m_preLoads.end() ) m_preLoads.push_back( item );
528 auto i =
std::remove( m_preLoads.begin(), m_preLoads.begin(), item );
529 m_preLoads.erase( i, m_preLoads.end() );
533 for (
const auto& i : m_preLoads ) {
535 if ( msgLevel(
MSG::DEBUG ) ) debug() <<
"Preloading " << i.path() <<
endmsg;
536 retrieveObject(
nullptr, i.path(), pObj ).ignore();
StatusCode setNumberOfStores(size_t slots) override
Set the number of event slots (copies of DataSvc objects).
const std::string & rootName() const override
StatusCode setDataLoader(IConversionSvc *svc, IDataProviderSvc *dpsvc) override
virtual StatusCode createObj(IOpaqueAddress *pAddress, DataObject *&refpObject)=0
Create the transient representation of an object.
Implementation of property with value of concrete type.
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
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
std::vector< DataStoreItem > m_preLoads
Items to be pre-loaded.
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
StatusCode removePreLoadItem(const DataStoreItem &) override
StatusCode traverseSubTree(std::string_view, IDataStoreAgent *) override
StatusCode retrieveObject(IRegistry *pDirectory, std::string_view path, DataObject *&pObject) override
StatusCode traverseTree(IDataStoreAgent *pAgent) override
Data provider interface definition.
virtual const std::string * par() const =0
Retrieve String parameters.
Description of the DataStoreItem class.
GAUDI_API int backTrace(void **addresses, const int depth)
size_t freeSlots() override
IRegistry * registry() const
Get pointer to Registry.
bool exists(const DataObjID &id) override
size_t getNumberOfStores() const override
StatusCode objectParent(const DataObject *, IRegistry *&) override
Invalid root path object cannot be retrieved or stored.
PropertyMgr & operator=(const PropertyMgr &)=delete
StatusCode linkObject(std::string_view, DataObject *) override
#define DECLARE_COMPONENT(type)
StatusCode preLoad() override
virtual const id_type & identifier() const =0
Full identifier (or key)
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.
StatusCode updateObject(DataObject *) override
StatusCode finalize() override
virtual unsigned long addRef()=0
Add reference to object.
size_t allocateStore(int evtnumber) override
Allocate a store partition for a given event number.
virtual IDataProviderSvc * dataSvc() const =0
Retrieve pointer to Transient Store.
The IRegistry represents the entry door to the environment any data object residing in a transient da...
unsigned int CLID
Class ID definition.
StatusCode unlinkObject(DataObject *, std::string_view) override
StatusCode unregisterObject(std::string_view) override
virtual DataObject * object() const =0
Retrieve object behind the link.
StatusCode objectParent(const IRegistry *, IRegistry *&) override
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
StatusCode unregisterObject(DataObject *obj) override
StatusCode linkObject(IRegistry *, std::string_view, DataObject *) override
StatusCode clearStore() override
StatusCode selectStore(size_t partition) override
Activate a partition object. The identifies the partition uniquely.
Generic data agent interface.
Base class used to extend a class implementing other interfaces.
virtual unsigned long release()=0
release reference to object
virtual void setAddress(IOpaqueAddress *pAddress)=0
Set/Update Opaque storage address.
StatusCode freeStore(size_t partition) override
Free a store partition.
Out1 * put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
const StatusCode & ignore() const
Ignore/check StatusCode.
StatusCode registerAddress(std::string_view fullPath, IOpaqueAddress *pAddress) override
StatusCode objectLeaves(const DataObject *, std::vector< IRegistry * > &) override
StatusCode unlinkObject(IRegistry *, std::string_view) override
StatusCode setRoot(std::string root_name, DataObject *pObject) override
constexpr static const auto FAILURE
StatusCode unregisterAddress(std::string_view) override
size_t getPartitionNumber(int eventnumber) const override
Get the partition number corresponding to a given event.
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
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
A DataObject is the base class of any identifiable object on any data store.
KeyedObjectManager< map > Map
Forward declaration of specialized std::map-like object manager.
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.
StatusCode addPreLoadItem(const DataStoreItem &) override
StatusCode findObject(IRegistry *pDirectory, std::string_view path, DataObject *&pObject) override
static GAUDI_API void setNumConcEvents(const std::size_t &nE)
StatusCode traverseSubTree(DataObject *obj, IDataStoreAgent *pAgent) override
StatusCode unlinkObject(std::string_view) override