diff --git a/Database/AthenaRoot/RootAuxDynIO/CMakeLists.txt b/Database/AthenaRoot/RootAuxDynIO/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..73bbc3db14ef75a7c836ab6737a8976c5545efa4 --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/CMakeLists.txt @@ -0,0 +1,25 @@ +################################################################################ +# Package: RootAuxDynIO +################################################################################ + +# Declare the package name: +atlas_subdir( RootAuxDynIO ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PRIVATE + AtlasTest/TestTools + Control/AthContainers + Control/AthContainersRoot + Control/AthContainersInterfaces + Database/AthenaRoot/AthenaRootComps + GaudiKernel ) + +find_package( ROOT COMPONENTS Core RIO Tree ) + +# Component(s) in the package: +atlas_add_library( RootAuxDynIO + src/*.cxx + PUBLIC_HEADERS RootAuxDynIO + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} + PRIVATE_LINK_LIBRARIES TestTools AthContainers AthContainersRoot RootUtils GaudiKernel ) diff --git a/Database/AthenaRoot/RootAuxDynIO/RootAuxDynIO/RootAuxDynIO.h b/Database/AthenaRoot/RootAuxDynIO/RootAuxDynIO/RootAuxDynIO.h new file mode 100644 index 0000000000000000000000000000000000000000..99bc9b93e41e0c512fe23e3c3ec62e9e54ca63f8 --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/RootAuxDynIO/RootAuxDynIO.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ROOTAUXDYN_IO_H +#define ROOTAUXDYN_IO_H + +#include <string> + +class TBranch; +class IRootAuxDynReader; + + +namespace RootAuxDynIO { + /// Common post-fix for the names of auxiliary containers in StoreGate + static const std::string AUX_POSTFIX = "Aux."; + static const std::string AUXDYN_POSTFIX = "Dyn."; + + + /** + * @brief Check is a branch holds AuxStore objects + * @param branch TBranch to check + */ + bool isAuxDynBranch(TBranch *branch); + + + /** + * @brief Crate RootAuxDynReader for a given TBranch + * @param branch TBranch in which AuxStore objects are + + Will return nullptr in case of problems + */ + IRootAuxDynReader* getReaderForBranch(TBranch *branch); + + /** + * @brief Construct branch name for a given dynamic attribute + * @param attr_name the name of the attribute + * @param baseBranchName branch name for the main AuxStore object + */ + std::string auxBranchName(const std::string& attr_name, const std::string& baseBranchName); + + +} + + +class IRootAuxDynReader +{ +public : + + /** + * @brief Attach specialized AuxStore for reading dynamic attributes + * @param object object instance to which the store will be attached to - has to be an instance of the type the reader was created for + * @param ttree_row + + Use this method to instrument an AuxStore object AFTER it was read (every time it is read) + This will attach its dynamic attributes with read-on-demand capability + */ + virtual void addReaderToObject(void* object, size_t ttree_row) = 0; + + virtual size_t getBytesRead() = 0; + + virtual void resetBytesRead() = 0; + + + virtual ~IRootAuxDynReader() {} +}; + + +#endif + diff --git a/Database/AthenaRoot/RootAuxDynIO/cmt/requirements b/Database/AthenaRoot/RootAuxDynIO/cmt/requirements new file mode 100644 index 0000000000000000000000000000000000000000..8edc7e42c2b1a43853b19410e8b58d60c3a300bb --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/cmt/requirements @@ -0,0 +1,18 @@ +package RootAuxDynIO + +author Marcin Nowak + +use AtlasPolicy AtlasPolicy-* +use AtlasROOT AtlasROOT-* External + +private +use AthContainersInterfaces AthContainersInterfaces-* Control +use AthContainers AthContainers-* Control +use AthContainersRoot AthContainersRoot-* Control +use RootUtils RootUtils-* Control + +public +apply_pattern installed_library +library RootAuxDynIO *.cxx + + diff --git a/Database/AthenaRoot/RootAuxDynIO/share/RootAuxVectorFactory_test.ref b/Database/AthenaRoot/RootAuxDynIO/share/RootAuxVectorFactory_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..fadbf1d8531cefc931988be7e19da5fb524c3e74 --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/share/RootAuxVectorFactory_test.ref @@ -0,0 +1,4 @@ +test1 +test2 +test3 +test4 diff --git a/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynReader.cxx b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynReader.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6dfeceb6cd7f2bf6a5dbaad4809de45355e66a30 --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynReader.cxx @@ -0,0 +1,335 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthContainersInterfaces/IAuxStoreHolder.h" +#include "AthContainersInterfaces/AuxDataOption.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/tools/error.h" +#include "AthContainers/exceptions.h" +#include "RootUtils/Type.h" + +#include "RootAuxDynReader.h" +#include "RootAuxDynStore.h" +#include "AthContainersRoot/getDynamicAuxID.h" + +#include "TBranch.h" +#include "TClass.h" +#include "TClassTable.h" +#include "TClassEdit.h" +#include "TVirtualCollectionProxy.h" +#include "TROOT.h" +#include "TDictAttributeMap.h" + +#include <iostream> +using namespace std; + + +namespace { + + +const std::type_info* dataTypeToTypeInfo (EDataType type, std::string& typeName) +{ + RootUtils::Type typ (type); + typeName = typ.getTypeName(); + return typ.getTypeInfo(); +} + + +/** + * @brief Given TClass+EDataType (as returned by a branch), return the aux data type + * @param expectedClass TClass for the storage type if a class + * @param expectedType EDT type for the storage type if a primitive type + * @param standalone Is this for a standalone object? + * @param[out] elementTypeName Name of the type for one aux data element. + * Same as storageTypeName if @c standalone is true. + * @param[out] storageTypeName Name of the type used for I/O + * + * If standalone is true, then we return the extracted type + * directly. Otherwise, the type should be an STL vector; + * we return the type of the vector's payload. + * + * Returns 0 on failure. + */ +const std::type_info* +getAuxElementType( TClass *expectedClass, EDataType expectedType, bool standalone, + std::string& elementTypeName, std::string& storageTypeName) +{ + if (standalone) { + if(expectedClass) { + elementTypeName = expectedClass->GetName(); + storageTypeName = elementTypeName; + return expectedClass->GetTypeInfo(); + } + const std::type_info* ret = dataTypeToTypeInfo(expectedType, elementTypeName); + storageTypeName = elementTypeName; + return ret; + } + + // Not standalone; branch should be a vector. + if (!expectedClass) return 0; + + storageTypeName = expectedClass->GetName(); + if (strncmp (expectedClass->GetName(), "vector<", 7) == 0) { + TVirtualCollectionProxy* prox = expectedClass->GetCollectionProxy(); + if (!prox) return 0; + if (prox->GetValueClass()) { + elementTypeName = prox->GetValueClass()->GetName(); + return prox->GetValueClass()->GetTypeInfo(); + } + return dataTypeToTypeInfo (prox->GetType(), elementTypeName); + } + else if (strncmp (expectedClass->GetName(), "SG::PackedContainer<", 20) == 0){ + TClassEdit::TSplitType split (expectedClass->GetName()); + if (split.fElements.size() > 1) { + elementTypeName = split.fElements[1]; + RootUtils::Type typ (elementTypeName); + return typ.getTypeInfo(); + } + } + return 0; +} + + + +SG::auxid_t +getAuxIdForAttribute(const std::string& attr, TClass *tclass, EDataType edt, bool standalone) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + + SG::auxid_t auxid = r.findAuxID(attr); + if(auxid != SG::null_auxid) + return auxid; + + string elemen_type_name; + string branch_type_name; + const type_info* ti = getAuxElementType(tclass, edt, standalone, elemen_type_name, branch_type_name); + if( !ti ) + return auxid; + + return SG::getDynamicAuxID (*ti, attr, elemen_type_name, branch_type_name, standalone); +} + + + +} // anonymous namespace + + + +namespace RootAuxDynIO +{ + + std::string + auxBranchName(const std::string& attr_name, const std::string& baseBranchName) + { + string branch_name = baseBranchName; + if( branch_name.back() == '.' ) branch_name.pop_back(); + branch_name += RootAuxDynIO::AUXDYN_POSTFIX + attr_name; + return branch_name; + } + + + bool + isAuxDynBranch(TBranch *branch) + { + const string bname = branch->GetName(); + if( bname.size() >= 5 && bname.substr(bname.size()-4, 4) == RootAuxDynIO::AUX_POSTFIX ) + return true; + + TClass *tc = 0; + EDataType type; + if( branch->GetExpectedType(tc, type) ) { + // error - not expecting this to happen ever, but better report + errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RootAuxDynIO::isAuxDynBranch"); + msg << "GetExpectedType() failed for branch: " << branch->GetName(); + return false; + } + if( tc && tc->GetAttributeMap() && tc->GetAttributeMap()->HasKey("IAuxStore") ) + return true; + + return false; + } + + + IRootAuxDynReader* + getReaderForBranch(TBranch *branch) + { + if( isAuxDynBranch(branch) ) { + TClass *tc = 0; + EDataType type; + if( branch->GetExpectedType(tc, type) ) { + return nullptr; + } + // cout << "--- getReaderForClass: " << tc->GetName() << " branch " << branch->GetName() << endl; + + TClass *storeTC = tc->GetBaseClass("SG::IAuxStoreHolder"); + if( storeTC ) { + int store_holder_offset = tc->GetBaseClassOffset( storeTC ); + return new RootAuxDynReader(branch, store_holder_offset); + } + } + return nullptr; + } + +} + + + + +void RootAuxDynReader::BranchInfo::setAddress(void* data) const +{ + if( needsSE ) { + // reading through the TTree - allows for schema evolution + if( branch->GetTree()->SetBranchAddress( branch->GetName(), data, + SE_tclass, SE_edt, true) < 0 ) { + throw string("SetBranchAddress() failed for ") + branch->GetName(); + } + } else { + branch->SetAddress(data); + } +} + + +// Fix Reader for a specific tree and branch base name. +// Find all dynamic attribute branches that share the base name +RootAuxDynReader::RootAuxDynReader(TBranch *branch, int store_holder_offset) + : m_tree( branch->GetTree() ), + m_baseBranchName( branch->GetName() ), + m_storeHolderOffset( store_holder_offset ) +{ + string branch_prefix = RootAuxDynIO::auxBranchName("", m_baseBranchName); + // cout << "RootAuxDynReader: scanning for branches with prefix: " << branch_prefix << endl; + TObjArray *all_branches = m_tree->GetListOfBranches(); + for( int i=0; i<all_branches->GetEntriesFast(); i++ ) { + const char *bname = (*all_branches)[i]->GetName(); + if( strncmp(bname, branch_prefix.c_str(), branch_prefix.size()) == 0 ) { + const string attr = bname+branch_prefix.size(); + m_branchMap[attr] = (TBranch*)(*all_branches)[i]; + // m_attrNames.insert(attr); // may be useful + // cout << " >>> Branch " << bname << ", attr=" << attr << endl; + } + } +} + + +// Has to be a separate method because 'standalone' status is not know at construction time +// Prepare all branch infos for dynamic attributes (auxids and types) +void RootAuxDynReader::init(bool standalone) +{ + if( m_initialized ) + return; + for( const auto& attr2branch: m_branchMap ) { + const string& attr = attr2branch.first; + TBranch* branch = attr2branch.second; + TClass* expectedClass = 0; + EDataType expectedType = kOther_t; + if( branch->GetExpectedType(expectedClass, expectedType) != 0) { + // raise hell + } + SG::auxid_t auxid = getAuxIdForAttribute(attr, expectedClass, expectedType, standalone); + // add AuxID to the list + // May still be null if we don't have a dictionary for the branch. + if (auxid != SG::null_auxid) { + m_auxids.insert(auxid); + } else { + errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RootAuxDynReader::init"); + msg << "Could not find auxid for " << branch->GetName() + << " type: " << expectedClass->GetName(); + + } + m_initialized = true; + } +} + + +// Called by the AuxStore when it is reading new attribute data from the file +// All information is cached in a BranchInfo object for better performance +const RootAuxDynReader::BranchInfo& +RootAuxDynReader::getBranchInfo(const SG::auxid_t& auxid, const SG::AuxStoreInternal& store) +{ + BranchInfo& brInfo = m_branchInfos[auxid]; + if( brInfo.status == BranchInfo::NotInitialized ) + { + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + brInfo.auxid = auxid; + brInfo.attribName = r.getName(auxid); + const string aux_branch_name = RootAuxDynIO::auxBranchName(brInfo.attribName, m_baseBranchName); + brInfo.branch = m_tree->GetBranch( aux_branch_name.c_str() ); + // mark initialized here so it remembers this branch was not found + if( !brInfo.branch ) { + brInfo.status = BranchInfo::NotFound; + return brInfo; + } + EDataType typ; + if( brInfo.branch->GetExpectedType( brInfo.tclass, typ) ) { + brInfo.status = BranchInfo::TypeError; + throw string("Error getting branch type for ") + aux_branch_name; + } + + if( !store.standalone() ) + if( brInfo.tclass && strncmp( brInfo.tclass->GetName(), "SG::PackedContainer<", 20) == 0) + brInfo.isPackedContainer = true; + + string elem_tname, branch_tname; + const type_info* ti = getAuxElementType( brInfo.tclass, typ, store.standalone(), + elem_tname, branch_tname ); + const type_info* reg_ti = r.getType(auxid); + if( ti && ti != reg_ti && strcmp(ti->name(), reg_ti->name()) != 0 ) + { + // type in registry is different than type in the file. + // will need to use ROOT auto schema evolution + brInfo.needsSE = true; + errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "RootAuxDynReader"); + msg << "attribute " << brInfo.attribName << " (id=" << auxid << + " typename=" << SG::AuxTypeRegistry::instance().getType(auxid)->name() + << ") has different type than the branch " << branch_tname; + + const std::type_info *tinf = store.getIOType(auxid); + brInfo.SE_tclass = TClass::GetClass(*tinf); + brInfo.SE_edt = kOther_t; + if( !brInfo.SE_tclass ) { + brInfo.SE_edt = TDataType::GetType(*tinf); + if( brInfo.SE_edt <=0 ) { + brInfo.status = BranchInfo::TypeError; + throw string("Error getting ROOT type for AUX branch ") + aux_branch_name + + " typeinfo=" + tinf->name(); + } + } + } + brInfo.status = BranchInfo::Initialized; + } + return brInfo; +} + + +void RootAuxDynReader::addReaderToObject(void* object, size_t ttree_row) +{ + auto store_holder = reinterpret_cast<SG::IAuxStoreHolder*>((char*)object + m_storeHolderOffset); + bool standalone { store_holder->getStoreType()==SG::IAuxStoreHolder::AST_ObjectStore }; + if( !m_initialized ) + init(standalone); + store_holder->setStore( new RootAuxDynStore(*this, ttree_row, standalone) ); +} + + +void RootAuxDynReader::addBytes(size_t bytes) +{ + m_bytesRead += bytes; +} + +size_t RootAuxDynReader::getBytesRead() { + return m_bytesRead; +} + +void RootAuxDynReader::resetBytesRead() { + m_bytesRead = 0; +} + +const SG::auxid_set_t& RootAuxDynReader::auxIDs() const +{ + return m_auxids; +} + + + + diff --git a/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynReader.h b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynReader.h new file mode 100644 index 0000000000000000000000000000000000000000..16a8d88f71185f71d008664ea9a6e5f9e9f1e811 --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynReader.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ROOTAUXDYNREADER_H +#define ROOTAUXDYNREADER_H + +#include "AthContainers/AuxStoreInternal.h" +#include "RootAuxDynIO/RootAuxDynIO.h" + +#include "TClass.h" +#include "TTree.h" + +#include <map> +#include <string> + + +class RootAuxDynReader : public IRootAuxDynReader +{ +public : + + struct BranchInfo + { + enum Status { NotInitialized, Initialized, TypeError, NotFound }; + + TBranch* branch = 0; + TClass* tclass = 0; + + TClass* SE_tclass = 0; + EDataType SE_edt = kOther_t; + + bool isPackedContainer = false; + bool needsSE = false; + enum Status status = NotInitialized; + + SG::auxid_t auxid; + std::string attribName; + + void setAddress(void* data) const; + }; + + RootAuxDynReader(TBranch *, int store_holder_offset); + + + virtual void addReaderToObject(void* object, size_t ttree_row); + + void init(bool standalone); + const BranchInfo& getBranchInfo(const SG::auxid_t& auxid, const SG::AuxStoreInternal& store); + + + void addBytes(size_t bytes); + + size_t getBytesRead(); + + void resetBytesRead(); + + const SG::auxid_set_t& auxIDs() const; + +protected: + // map of attribute name to TBranch* as read from the file + std::map<std::string, TBranch*> m_branchMap; + // map auxid -> branch info. not sure if it can be different from m_branchMap + std::map<SG::auxid_t, BranchInfo> m_branchInfos; + // auxids that could be found in registry for attribute names from the m_branchMap + SG::auxid_set_t m_auxids; + + TTree* m_tree = 0; + std::string m_baseBranchName; + // counter for bytes read + size_t m_bytesRead = 0; + // offset of the AxuStoreHolder base class in the objects read by the Reader + int m_storeHolderOffset = -1; + bool m_initialized = false; +}; + + +#endif diff --git a/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynStore.cxx b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynStore.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cddb725ea5a894f57bdc7c8706bd9273d0c4ccbb --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynStore.cxx @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/tools/error.h" +#include "AthContainers/exceptions.h" +#include "AthContainersInterfaces/AuxDataOption.h" + +#include "RootAuxDynStore.h" +#include "RootAuxDynReader.h" + +#include <iostream> +using namespace std; + + + + +RootAuxDynStore::RootAuxDynStore(RootAuxDynReader& reader, long long entry, bool standalone) + : SG::AuxStoreInternal( standalone ), + m_reader(reader), + m_entry(entry) +{ + for( auto id : reader.auxIDs() ) { + addAuxID(id); + } + lock(); +} + + + +const void* RootAuxDynStore::getData(SG::auxid_t auxid) const +{ + guard_t guard (m_mutex); + // lock + const void* ret = SG::AuxStoreInternal::getData (auxid); + if (!ret) { + const_cast<RootAuxDynStore*>(this)->readData(auxid); + ret = SG::AuxStoreInternal::getData (auxid); + } + return ret; +} + + +const void* RootAuxDynStore::getIOData(SG::auxid_t auxid) const +{ + guard_t guard (m_mutex); + const void* ret = SG::AuxStoreInternal::getIODataInternal (auxid, true); + if (!ret) { + const_cast<RootAuxDynStore*>(this)->readData(auxid); + ret = SG::AuxStoreInternal::getIOData (auxid); + } + return ret; +} + + +bool RootAuxDynStore::readData(SG::auxid_t auxid) +{ + //cout << "RootAuxDynStore::getData() id=" << auxid << ", name=" + // << reg.getName(auxid) << endl; + try { + // cout << "--- RootAuxDynStore reading id=" << auxid << endl; + auto& brInfo = m_reader.getBranchInfo(auxid, *this); + if( !brInfo.branch ) return false; + + // Make a 1-element vector. + SG::AuxStoreInternal::getDataInternal(auxid, 1, 1, true); + if( brInfo.isPackedContainer ) { + setOption (auxid, SG::AuxDataOption ("nbits", 32)); + } + + // get memory location where to write data from the branch entry + void * vector = const_cast<void*>(SG::AuxStoreInternal::getIOData (auxid)); // xxx + void * data = &vector; + if( standalone() && !brInfo.tclass ) { + // reading fundamental type - ROOT expects a direct pointer + data = vector; + } + + // read branch + brInfo.setAddress(data); + int nbytes = brInfo.branch->GetEntry(m_entry); + if( nbytes <= 0 ) + throw string("Error reading branch ") + brInfo.branch->GetName(); + // read OK + m_reader.addBytes(nbytes); + } + catch(const string& e_str) { + ATHCONTAINERS_ERROR("RootAuxDynStore::getData", e_str); + return false; + } + return true; +} + + +/** + * @brief Return the data vector for one aux data decoration item. + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * The base class implementation works except for the case where we have + * not yet created a vector for an item in the root file. We need to + * detect that case and raise an exception. + */ +void* +RootAuxDynStore::getDecoration (SG::auxid_t auxid, size_t size, size_t capacity) +{ + guard_t guard (m_mutex); + if (SG::AuxStoreInternal::getIODataInternal (auxid, true) == 0 && + SG::AuxStoreInternal::getAuxIDs().count (auxid) > 0) + { + throw SG::ExcStoreLocked (auxid); + } + return SG::AuxStoreInternal::getDecoration (auxid, size, capacity); +} + + + diff --git a/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynStore.h b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynStore.h new file mode 100644 index 0000000000000000000000000000000000000000..7c149cdfc49fcff5438a40c7fbc7ce836e099892 --- /dev/null +++ b/Database/AthenaRoot/RootAuxDynIO/src/RootAuxDynStore.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ROOTAUXDYNSTORE_H +#define ROOTAUXDYNSTORE_H + +#include "AthContainers/AuxStoreInternal.h" + +#include <string> + +class RootAuxDynReader; + +class RootAuxDynStore : public SG::AuxStoreInternal +{ +public: + RootAuxDynStore(RootAuxDynReader& reader, long long entry, bool standalone); + virtual ~RootAuxDynStore() {} + + /// implementation of the IAuxStore interface + virtual const void* getData(SG::auxid_t auxid) const; + virtual void* getData(SG::auxid_t auxid, size_t size, size_t capacity); + + /// implementation of the IAuxStoreIO interface + virtual const void* getIOData(SG::auxid_t auxid) const; + + + /** + * @brief Return the data vector for one aux data decoration item. + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + */ + void* getDecoration (SG::auxid_t auxid, size_t size, size_t capacity); + + +protected: + /// read data from ROOT and store it in m_vecs. Returns False on error + bool readData(SG::auxid_t auxid); + +protected: + RootAuxDynReader& m_reader; + long long m_entry; + +private: + /// Mutex used to synchronize modifications to the cache vector. + typedef AthContainers_detail::mutex mutex_t; + typedef AthContainers_detail::lock_guard<mutex_t> guard_t; + mutable mutex_t m_mutex; +}; + + + +inline +void* RootAuxDynStore::getData(SG::auxid_t auxid, size_t /*size*/, size_t /*capacity*/) +{ + // MN: how do we add new attributes to this store? A:for now we don't + return const_cast<void*>(getData(auxid)); +} + + + +#endif