diff --git a/Control/AthenaKernel/AthenaKernel/CondCont.h b/Control/AthenaKernel/AthenaKernel/CondCont.h index 358f45c8fa81f984c4e31409fbea5bd05a4e3497..81515ec7275b272120ed7e54eae181dadc108f44 100644 --- a/Control/AthenaKernel/AthenaKernel/CondCont.h +++ b/Control/AthenaKernel/AthenaKernel/CondCont.h @@ -114,27 +114,28 @@ public: /** * @brief Return CLID/key corresponding to this container. */ - virtual const DataObjID& id() const = 0; + const DataObjID& id() const; /** * @brief Return the associated @c DataProxy, if any. */ - virtual SG::DataProxy* proxy() = 0; + SG::DataProxy* proxy(); /** * @brief Set the associated @c DataProxy. * @param proxy The proxy to set. */ - virtual void setProxy(SG::DataProxy*) = 0; + void setProxy(SG::DataProxy*); /** * @brief Dump the container contents for debugging. * @param ost Stream to which to write the dump. */ - virtual void list (std::ostream& ost) const = 0; + virtual + void list (std::ostream& ost) const; /** @@ -146,27 +147,30 @@ public: /** * @brief Return the number of conditions objects in the container. */ - virtual size_t entries() const = 0; + size_t entries() const; /** * @brief Return the number of run+LBN conditions objects * in the container. */ - virtual size_t entriesRunLBN() const = 0; + virtual + size_t entriesRunLBN() const; /** * @brief Return the number of timestamp-based conditions objects * in the container. */ - virtual size_t entriesTimestamp() const = 0; + virtual + size_t entriesTimestamp() const; /** * @brief Return all IOV validity ranges defined in this container. */ - virtual std::vector<EventIDRange> ranges() const = 0; + virtual + std::vector<EventIDRange> ranges() const; /** @@ -185,16 +189,18 @@ public: * duplicates an existing one, and FAILURE otherwise * (ownership of the object will be taken in any case). */ - virtual StatusCode typelessInsert (const EventIDRange& r, - void* obj, - const EventContext& ctx = Gaudi::Hive::currentContext()) = 0; + virtual + StatusCode typelessInsert (const EventIDRange& r, + void* obj, + const EventContext& ctx = Gaudi::Hive::currentContext()); /** * @brief Test to see if a given IOV time is mapped in the container. * @param t IOV time to check. */ - virtual bool valid( const EventIDBase& t) const = 0; + virtual + bool valid( const EventIDBase& t) const; /** @@ -204,7 +210,8 @@ public: * * Returns true if @c t is mapped; false otherwise. */ - virtual bool range (const EventIDBase& t, EventIDRange& r) const = 0; + virtual + bool range (const EventIDBase& t, EventIDRange& r) const; /** @@ -212,8 +219,9 @@ public: * @param IOV time of element to erase. * @param ctx Event context for the current thread. */ - virtual void erase (const EventIDBase& t, - const EventContext& ctx = Gaudi::Hive::currentContext()) = 0; + virtual + void erase (const EventIDBase& t, + const EventContext& ctx = Gaudi::Hive::currentContext()); /** @@ -235,7 +243,8 @@ public: * * Returns the number of objects that were removed. */ - virtual size_t trimRunLBN (const std::vector<key_type>& keys) = 0; + virtual + size_t trimRunLBN (const std::vector<key_type>& keys); /** @@ -257,7 +266,8 @@ public: * * Returns the number of objects that were removed. */ - virtual size_t trimTimestamp (const std::vector<key_type>& keys) = 0; + virtual + size_t trimTimestamp (const std::vector<key_type>& keys); /** @@ -267,19 +277,19 @@ public: * This would normally be done through RCU service. * Defined here for purposes of testing. */ - virtual void quiescent (const EventContext& ctx = Gaudi::Hive::currentContext()) = 0; + void quiescent (const EventContext& ctx = Gaudi::Hive::currentContext()); /** * @brief Return the number times an item was inserted into the map. */ - virtual size_t nInserts() const = 0; + size_t nInserts() const; /** * @brief Return the maximum size of the map. */ - virtual size_t maxSize() const = 0; + size_t maxSize() const; /** @@ -292,8 +302,9 @@ public: * IOV is changed to the end time for @c newRange. (If the end time for @c newRange * is before the end of the last IOV, then nothing is changed.) */ - virtual StatusCode extendLastRange (const EventIDRange& newRange, - const EventContext& ctx = Gaudi::Hive::currentContext()) = 0; + virtual + StatusCode extendLastRange (const EventIDRange& newRange, + const EventContext& ctx = Gaudi::Hive::currentContext()); /** @@ -377,17 +388,56 @@ public: protected: + typedef CxxUtils::ConcurrentRangeMap<RangeKey, key_type, void, Compare, + Athena::RCUUpdater> + CondContSet; + + typedef CondContSet::Updater_t Updater_t; + /** * @brief Internal constructor. * @param rcusvc RCU service instance. * @param CLID of the most-derived @c CondCont. * @param id CLID+key for this object. * @param proxy @c DataProxy for this object. + * @param delfcn Deletion function for the actual payload type. + * @param capacity Initial capacity of the container. */ CondContBase (Athena::IRCUSvc& rcusvc, CLID clid, const DataObjID& id, - SG::DataProxy* proxy); + SG::DataProxy* proxy, + CondContSet::delete_function* delfcn, + size_t capacity); + + + /** + * @brief Insert a new conditions object. + * @param r Range of validity of this object. + * @param t Pointer to the object being inserted. + * @param ctx Event context for the current thread. + * + * Returns SUCCESS if the object was successfully inserted; + * DUPLICATE if the object wasn't inserted because the range + * duplicates an existing one, and FAILURE otherwise + * (ownership of the object will be taken in any case). + */ + StatusCode insertBase (const EventIDRange& r, + CondContSet::payload_unique_ptr t, + const EventContext& ctx = Gaudi::Hive::currentContext()); + + + /** + * @brief Internal lookup function. + * @param t IOV time to find. + * @param r If non-null, copy validity range of the object here. + * + * Looks up the conditions object corresponding to the IOV time @c t. + * If found, return the pointer (as a pointer to the payload type + * of the most-derived CondCont). Otherwise, return nullptr. + */ + const void* findBase (const EventIDBase& t, + EventIDRange const** r) const; /** @@ -402,19 +452,19 @@ protected: const void* cast (CLID clid, const void* ptr) const; - /** - * @brief Internal lookup function. + /** + * @brief Do pointer conversion for the payload type. * @param clid CLID for the desired pointer type. - * @param t IOV time to find. - * @param r If non-null, copy validity range of the object here. + * @param ptr Pointer of type @c T*. * - * Looks up the conditions object corresponding to the IOV time @c t. - * If found, convert the pointer to a pointer to the type identified - * by CLID and return it. Otherwise, return nullptr. + * Converts @c ptr from @c T* to a pointer to the type + * given by @c clid. Returns nullptr if the conversion + * is not possible. + * + * This is a virtual function that calls @c cast from the most-derived class + * of the hierarchy. */ - virtual const void* findByCLID (CLID clid, - const EventIDBase& t, - EventIDRange const** r) const = 0; + virtual const void* doCast (CLID clid, const void* ptr) const = 0; /** @@ -427,6 +477,15 @@ private: /// CLID of the most-derived @c CondCont CLID m_clid; + /// CLID+key for this container. + DataObjID m_id; + + /// Associated @c DataProxy. + SG::DataProxy* m_proxy; + + /// Sets of mapped objects, by timestamp and run+LBN. + CondContSet m_condSet_clock, m_condSet_RE; + /// Handle to the cleaner service. ServiceHandle<Athena::IConditionsCleanerSvc> m_cleanerSvc; @@ -523,6 +582,8 @@ public: /// Base class. typedef typename CondContBaseInfo<T>::Base Base; + typedef typename Base::CondContSet CondContSet; + /// Payload type held by this class. typedef T Payload; @@ -550,79 +611,6 @@ public: CondCont& operator= (const CondCont&) = delete; - /** - * @brief Return CLID/key corresponding to this container. - */ - virtual const DataObjID& id() const override; - - - /** - * @brief Return the associated @c DataProxy, if any. - */ - virtual SG::DataProxy* proxy() override; - - - /** - * @brief Set the associated @c DataProxy. - * @param proxy The proxy to set. - */ - virtual void setProxy (SG::DataProxy* proxy) override; - - - /** - * @brief Dump the container contents for debugging. - * @param ost Stream to which to write the dump. - */ - virtual void list (std::ostream& ost) const override; - - - /** - * @brief Return the number of conditions objects in the container. - */ - virtual size_t entries() const override; - - - /** - * @brief Return the number of run+LBN conditions objects - * in the container. - */ - virtual size_t entriesRunLBN() const override; - - - /** - * @brief Return the number of timestamp-based conditions objects - * in the container. - */ - virtual size_t entriesTimestamp() const override; - - - /** - * @brief Return all IOV validity ranges defined in this container. - */ - virtual std::vector<EventIDRange> ranges() const override; - - - /** - * @brief Insert a new conditions object. - * @param r Range of validity of this object. - * @param obj Pointer to the object being inserted. - * @param ctx Event context for the current thread. - * - * @c obj must point to an object of type @c T, - * except in the case of inheritance, where the type of @c obj must - * correspond to the most-derived @c CondCont type. - * The container will take ownership of this object. - * - * Returns SUCCESS if the object was successfully inserted; - * DUPLICATE if the object wasn't inserted because the range - * duplicates an existing one, and FAILURE otherwise - * (ownership of the object will be taken in any case). - */ - virtual StatusCode typelessInsert (const EventIDRange& r, - void* obj, - const EventContext& ctx = Gaudi::Hive::currentContext()) override; - - /** * @brief Insert a new conditions object. * @param r Range of validity of this object. @@ -656,103 +644,6 @@ public: EventIDRange const** r = nullptr) const; - /** - * @brief Test to see if a given IOV time is mapped in the container. - * @param t IOV time to check. - */ - virtual bool valid (const EventIDBase& t) const override; - - - /** - * @brief Return the mapped validity range for an IOV time. - * @param t IOV time to check. - * @param r[out] The range containing @c t. - * - * Returns true if @c t is mapped; false otherwise. - */ - virtual bool range (const EventIDBase& t, EventIDRange& r) const override; - - - /** - * @brief Erase the first element not less than @c t. - * @param IOV time of element to erase. - * @param ctx Event context for the current thread. - */ - virtual void erase (const EventIDBase& t, - const EventContext& ctx = Gaudi::Hive::currentContext()) override; - - - /** - * @brief Remove unused run+LBN entries from the front of the list. - * @param keys List of keys that may still be in use. - * (Must be sorted.) - * - * We examine the objects in the container, starting with the earliest one. - * If none of the keys in @c keys match the range for this object, then - * it is removed from the container. We stop when we either find - * an object with a range matching a key in @c keys or when there - * is only one object left. - * - * The list @c keys should contain keys as computed by keyFromRunLBN. - * The list must be sorted. - * - * Removed objects are queued for deletion once all slots have been - * marked as quiescent. - * - * Returns the number of objects that were removed. - */ - virtual size_t trimRunLBN (const std::vector<key_type>& keys) override; - - - /** - * @brief Remove unused timestamp entries from the front of the list. - * @param keys List of keys that may still be in use. - * (Must be sorted.) - * - * We examine the objects in the container, starting with the earliest one. - * If none of the keys in @c keys match the range for this object, then - * it is removed from the container. We stop when we either find - * an object with a range matching a key in @c keys or when there - * is only one object left. - * - * The list @c keys should contain keys as computed by keyFromRunLBN. - * The list must be sorted. - * - * Removed objects are queued for deletion once all slots have been - * marked as quiescent. - * - * Returns the number of objects that were removed. - */ - virtual size_t trimTimestamp (const std::vector<key_type>& keys) override; - - - /** - * @brief Mark that this thread is no longer accessing data from this container. - * @param ctx Event context for the current thread. - * - * This would normally be done through RCU service. - * Defined here for purposes of testing. - */ - virtual void - quiescent (const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) override; - - - /** - * @brief Return the number times an item was inserted into the map. - */ - virtual size_t nInserts() const override; - - - /** - * @brief Return the maximum size of the map. - */ - virtual size_t maxSize() const override; - - - virtual StatusCode extendLastRange (const EventIDRange& newRange, - const EventContext& ctx = Gaudi::Hive::currentContext()) override; - - protected: /** * @brief Internal constructor. @@ -760,11 +651,15 @@ protected: * @param CLID of the most-derived @c CondCont. * @param id CLID+key for this object. * @param proxy @c DataProxy for this object. + * @param delfcn Deletion function for the actual payload type. + * @param capacity Initial capacity of the container. */ CondCont (Athena::IRCUSvc& rcusvc, CLID clid, const DataObjID& id, - SG::DataProxy* proxy); + SG::DataProxy* proxy, + const typename CondContSet::delete_function* delfcn, + size_t capacity); /** @@ -779,19 +674,19 @@ protected: const void* cast (CLID clid, const void* ptr) const; - /** - * @brief Internal lookup function. + /** + * @brief Do pointer conversion for the payload type. * @param clid CLID for the desired pointer type. - * @param t IOV time to find. - * @param r If non-null, copy validity range of the object here. + * @param ptr Pointer of type @c T*. * - * Looks up the conditions object corresponding to the IOV time @c t. - * If found, convert the pointer to a pointer to the type identified - * by CLID and return it. Otherwise, return nullptr. + * Converts @c ptr from @c T* to a pointer to the type + * given by @c clid. Returns nullptr if the conversion + * is not possible. + * + * This is a virtual function that calls @c cast from the most-derived class + * of the hierarchy. */ - virtual const void* findByCLID (CLID clid, - const EventIDBase& t, - EventIDRange const** r) const override; + virtual const void* doCast (CLID clid, const void* ptr) const override; public: @@ -804,17 +699,10 @@ private: typedef CondContBase::RangeKey RangeKey; - /// Sets of mapped objects, by timestamp and run+LBN. - typedef CxxUtils::ConcurrentRangeMap<RangeKey, key_type, T, CondContBase::Compare, - Athena::RCUUpdater> - CondContSet; - CondContSet m_condSet_clock, m_condSet_RE; - - /// CLID+key for this container. - DataObjID m_id; - - /// Associated @c DataProxy. - SG::DataProxy* m_proxy; + /// Deletion function to pass to @c ConcurrentRangeMap. + static void delfcn (const void* p) { + delete reinterpret_cast<const T*>(p); + } }; diff --git a/Control/AthenaKernel/AthenaKernel/CondCont.icc b/Control/AthenaKernel/AthenaKernel/CondCont.icc index 7432e3c35d3ea185fd332571383345267bf9a38c..aac30e77d638ef52450c13565b0977d9ff458aa6 100644 --- a/Control/AthenaKernel/AthenaKernel/CondCont.icc +++ b/Control/AthenaKernel/AthenaKernel/CondCont.icc @@ -20,6 +20,49 @@ CLID CondContBase::clid() const } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/** + * @brief Return CLID/key corresponding to this container. + */ +inline +const DataObjID& CondContBase::id() const +{ + return m_id; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/** + * @brief Return the associated @c DataProxy, if any. + */ +inline +SG::DataProxy* CondContBase::proxy() +{ + return m_proxy; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/** + * @brief Test to see if a given IOV time is mapped in the container. + * @param t IOV time to check. + */ +inline +bool CondContBase::valid (const EventIDBase& t) const +{ + return findBase (t, nullptr) != nullptr; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** * @brief Do pointer conversion for the payload type. * @param clid CLID for the desired pointer type. @@ -45,6 +88,9 @@ CondContBase::key_type CondContBase::keyFromRunLBN (const EventIDBase& b) } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** * @brief Make a timestamp key from an EventIDBase. * @param Event ID to convert. @@ -56,6 +102,9 @@ CondContBase::key_type CondContBase::keyFromTimestamp (const EventIDBase& b) } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** * @brief Default constructor. */ @@ -67,6 +116,9 @@ CondContBase::RangeKey::RangeKey() } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** * @brief Constructor from range+start/stop. * @param r The range to store. @@ -100,11 +152,7 @@ CondCont<T>::CondCont (Athena::IRCUSvc& rcusvc, const DataObjID& id, SG::DataProxy* proxy /*=nullptr*/, size_t capacity /*= 16*/) - : Base (rcusvc, ClassID_traits<CondCont<T> >::ID(), id, proxy), - m_condSet_clock (typename CondContSet::Updater_t (rcusvc), capacity), - m_condSet_RE (typename CondContSet::Updater_t (rcusvc), capacity), - m_id (id), - m_proxy (proxy) + : Base (rcusvc, ClassID_traits<CondCont<T> >::ID(), id, proxy, delfcn, capacity) { CondCont<T>::registerBaseInit(); } @@ -124,171 +172,13 @@ CondCont<T>::~CondCont<T>() { /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/** - * @brief Return CLID/key corresponding to this container. - */ -template <class T> -inline -const DataObjID& CondCont<T>::id() const -{ - return m_id; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return the associated @c DataProxy, if any. - */ -template <class T> -inline -SG::DataProxy* CondCont<T>::proxy() -{ - return m_proxy; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Set the associated @c DataProxy. - * @param proxy The proxy to set. - */ -template <class T> -inline -void CondCont<T>::setProxy (SG::DataProxy* proxy) -{ - m_proxy = proxy; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Dump the container contents for debugging. - * @param ost Stream to which to write the dump. - */ -template <typename T> -void CondCont<T>::list (std::ostream& ost) const -{ - ost << "id: " << m_id << " proxy: " << m_proxy << std::endl; - - ost << "clock: [" << m_condSet_clock.size() << "]" << std::endl; - for (const typename CondContSet::value_type& ent : m_condSet_clock.range()) { - ost << ent.first.m_range << " " << ent.second << std::endl; - } - ost << "RE: [" << m_condSet_RE.size() << "]" << std::endl; - for (const typename CondContSet::value_type& ent : m_condSet_RE.range()) { - ost << ent.first.m_range << " " << ent.second << std::endl; - } -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return the number of conditions objects in the container. - */ -template <typename T> -size_t CondCont<T>::entries() const -{ - return m_condSet_RE.size() + m_condSet_clock.size(); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return the number of run+LBN conditions objects - * in the container. - */ -template <typename T> -size_t CondCont<T>::entriesRunLBN() const -{ - return m_condSet_RE.size(); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return the number of timestamp-based conditions objects - * in the container. - */ -template <typename T> -size_t CondCont<T>::entriesTimestamp() const -{ - return m_condSet_clock.size(); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return all IOV validity ranges defined in this container. - */ -template <typename T> -std::vector<EventIDRange> -CondCont<T>::ranges() const -{ - std::vector<EventIDRange> r; - r.reserve (m_condSet_RE.size() + m_condSet_clock.size()); - for (const typename CondContSet::value_type& ent : m_condSet_RE.range()) { - r.push_back( ent.first.m_range ); - } - for (const typename CondContSet::value_type& ent : m_condSet_clock.range()) { - r.push_back( ent.first.m_range ); - } - - return r; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** * @brief Insert a new conditions object. * @param r Range of validity of this object. - * @param obj Pointer to the object being inserted. + * @param t Pointer to the object being inserted. * @param ctx Event context for the current thread. * - * @c obj must point to an object of type @c T, - * except in the case of inheritance, where the type of @c obj must - * correspond to the most-derived @c CondCont type. - * The container will take ownership of this object. - * - * Returns SUCCESS if the object was successfully inserted; - * DUPLICATE if the object wasn't inserted because the range - * duplicates an existing one, and FAILURE otherwise - * (ownership of the object will be taken in any case). - */ -template <typename T> -StatusCode CondCont<T>::typelessInsert (const EventIDRange& r, - void* obj, - const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) -{ - return insert (r, std::unique_ptr<T> (static_cast<T*>(obj)), ctx); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Insert a new conditions object. - * @param r Range of validity of this object. - * @param obj Pointer to the object being inserted. - * @param ctx Event context for the current thread. - * - * @c obj must point to an object of type @c T. + * @c t must point to an object of type @c T. * This will give an error if this is not called * on the most-derived @c CondCont. * @@ -308,39 +198,7 @@ StatusCode CondCont<T>::insert (const EventIDRange& r, return StatusCode::FAILURE; } - EventIDBase start = r.start(); - EventIDBase stop = r.stop(); - - // LBN part of ranges may be undefined for an open-ended range. - if (start.run_number() != EventIDBase::UNDEFNUM && - stop.run_number() != EventIDBase::UNDEFNUM) - { - if (!m_condSet_RE.emplace( RangeKey(r, - CondContBase::keyFromRunLBN (start), - CondContBase::keyFromRunLBN (stop)), - std::move(t), ctx )) - { - return CondContStatusCode::DUPLICATE; - } - - } - else if (start.isTimeStamp() && stop.isTimeStamp()) { - if (!m_condSet_clock.emplace( RangeKey(r, - CondContBase::keyFromTimestamp (start), - CondContBase::keyFromTimestamp (stop)), - std::move(t), ctx )) - { - return CondContStatusCode::DUPLICATE; - } - } - else { - std::cerr << "CondCont<T>::insert error: EventIDRange " << r - << " is neither fully RunEvent nor TimeStamp" - << std::endl; - return StatusCode::FAILURE; - } - - return this->inserted (ctx); + return Base::insertBase (r, std::move(t), ctx); } @@ -360,75 +218,14 @@ bool CondCont<T>::find (const EventIDBase& t, T const *& obj, EventIDRange const** r) const { - const void* ptr = findByCLID (ClassID_traits<CondCont<T> >::ID(), t, r); - obj = reinterpret_cast<const T*> (ptr); - return obj != nullptr; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Test to see if a given IOV time is mapped in the container. - * @param t IOV time to check. - */ -template <typename T> -bool CondCont<T>::valid (const EventIDBase& t) const -{ - return findByCLID (this->clid(), t, nullptr) != nullptr; -} + const void* ptr = Base::findBase (t, r); - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return the mapped validity range for an IOV time. - * @param t IOV time to check. - * @param r[out] The range containing @c t. - * - * Returns true if @c t is mapped; false otherwise. - */ -template <typename T> -bool -CondCont<T>::range(const EventIDBase& t, EventIDRange& r) const -{ - const EventIDRange* rp = nullptr; - if (findByCLID (this->clid(), t, &rp) != nullptr) { - r = *rp; - return true; + if (ClassID_traits<CondCont<T> >::ID() != this->clid()) { + ptr = doCast (ClassID_traits<CondCont<T> >::ID(), ptr); } - return false; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Remove unused run+LBN entries from the front of the list. - * @param keys List of keys that may still be in use. - * (Must be sorted.) - * - * We examine the objects in the container, starting with the earliest one. - * If none of the keys in @c keys match the range for this object, then - * it is removed from the container. We stop when we either find - * an object with a range matching a key in @c keys or when there - * is only one object left. - * - * The list @c keys should contain keys as computed by keyFromRunLBN. - * The list must be sorted. - * - * Removed objects are queued for deletion once all slots have been - * marked as quiescent. - * - * Returns the number of objects that were removed. - */ -template <typename T> -size_t CondCont<T>::trimRunLBN (const std::vector<key_type>& keys) -{ - return m_condSet_RE.trim (keys); + obj = reinterpret_cast<const T*> (ptr); + return obj != nullptr; } @@ -436,131 +233,22 @@ size_t CondCont<T>::trimRunLBN (const std::vector<key_type>& keys) /** - * @brief Remove unused timestamp entries from the front of the list. - * @param keys List of keys that may still be in use. - * (Must be sorted.) - * - * We examine the objects in the container, starting with the earliest one. - * If none of the keys in @c keys match the range for this object, then - * it is removed from the container. We stop when we either find - * an object with a range matching a key in @c keys or when there - * is only one object left. - * - * The list @c keys should contain keys as computed by keyFromRunLBN. - * The list must be sorted. - * - * Removed objects are queued for deletion once all slots have been - * marked as quiescent. + * @brief Do pointer conversion for the payload type. + * @param clid CLID for the desired pointer type. + * @param ptr Pointer of type @c T*. * - * Returns the number of objects that were removed. - */ -template <typename T> -size_t CondCont<T>::trimTimestamp (const std::vector<key_type>& keys) -{ - return m_condSet_clock.trim (keys); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Erase the first element not less than @c t. - * @param IOV time of element to erase. - * @param ctx Event context for the current thread. - */ -template <typename T> -void CondCont<T>::erase (const EventIDBase& t, - const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) -{ - if (t.isRunLumi()) { - m_condSet_RE.erase (CondContBase::keyFromRunLBN (t), ctx); - } - else if (t.isTimeStamp()) { - m_condSet_clock.erase (CondContBase::keyFromTimestamp (t), ctx); - } -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Mark that this thread is no longer accessing data from this container. - * @param ctx Event context for the current thread. + * Converts @c ptr from @c T* to a pointer to the type + * given by @c clid. Returns nullptr if the conversion + * is not possible. * - * This would normally be done through RCU service. - * Defined here for purposes of testing. - */ -template <typename T> -void -CondCont<T>::quiescent (const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) -{ - m_condSet_RE.quiescent (ctx); - m_condSet_clock.quiescent (ctx); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return the number times an item was inserted into the map. - */ -template <typename T> -inline -size_t CondCont<T>::nInserts() const -{ - return m_condSet_clock.nInserts() + m_condSet_RE.nInserts(); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * @brief Return the maximum size of the map. + * This is a virtual function that calls @c cast from the most-derived class + * of the hierarchy. */ template <typename T> inline -size_t CondCont<T>::maxSize() const -{ - return m_condSet_clock.maxSize() + m_condSet_RE.maxSize(); -} - - -/** - * @brief Extend the range of the last IOV. - * @param newRange New validity range. - * @param ctx Event context. - * - * Returns failure if the start time of @c newRange does not match the start time - * of the last IOV in the container. Otherwise, the end time for the last - * IOV is changed to the end time for @c newRange. (If the end time for @c newRange - * is before the end of the last IOV, then nothing is changed.) - */ -template <typename T> -StatusCode -CondCont<T>::extendLastRange (const EventIDRange& newRange, - const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) +const void* CondCont<T>::doCast (CLID clid, const void* ptr) const { - typename CondContSet::const_iterator it = nullptr; - if (newRange.start().isRunLumi()) { - it = m_condSet_RE.extendLastRange - (RangeKey (newRange, - CondContBase::keyFromRunLBN (newRange.start()), - CondContBase::keyFromRunLBN (newRange.stop())), ctx); - } - else if (newRange.start().isTimeStamp()) { - it = m_condSet_clock.extendLastRange - (RangeKey (newRange, - CondContBase::keyFromTimestamp (newRange.start()), - CondContBase::keyFromTimestamp (newRange.stop())), ctx); - } - if (it != nullptr) { - return StatusCode::SUCCESS; - } - return StatusCode::FAILURE; + return cast (clid, ptr); } @@ -573,18 +261,18 @@ CondCont<T>::extendLastRange (const EventIDRange& newRange, * @param CLID of the most-derived @c CondCont. * @param id CLID+key for this object. * @param proxy @c DataProxy for this object. + * @param delfcn Deletion function for the actual payload type. + * @param capacity Initial capacity of the container. */ template <typename T> inline CondCont<T>::CondCont (Athena::IRCUSvc& rcusvc, CLID clid, const DataObjID& id, - SG::DataProxy* proxy) - : Base (rcusvc, clid, id, proxy), - m_condSet_clock (typename CondContSet::Updater_t (rcusvc)), - m_condSet_RE (typename CondContSet::Updater_t (rcusvc)), - m_id(id), - m_proxy(proxy) + SG::DataProxy* proxy, + const typename CondContSet::delete_function* delfcn, + size_t capacity) + : Base (rcusvc, clid, id, proxy, delfcn, capacity) { CondCont<T>::registerBaseInit(); } @@ -603,6 +291,7 @@ CondCont<T>::CondCont (Athena::IRCUSvc& rcusvc, * is not possible. */ template <typename T> +inline const void* CondCont<T>::cast (CLID clid, const void* ptr) const { if (clid == ClassID_traits<CondCont<T> >::ID()) @@ -615,57 +304,6 @@ const void* CondCont<T>::cast (CLID clid, const void* ptr) const /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/** - * @brief Internal lookup function. - * @param clid CLID for the desired pointer type. - * @param t IOV time to find. - * @param r If non-null, copy validity range of the object here. - * - * Looks up the conditions object corresponding to the IOV time @c t. - * If found, convert the pointer to a pointer to the type identified - * by CLID and return it. Otherwise, return nullptr. - */ -template <typename T> -const void* CondCont<T>::findByCLID (CLID clid, - const EventIDBase& t, - EventIDRange const** r) const -{ - const void* ptr = nullptr; - if (t.isRunLumi()) { - key_type key = CondContBase::keyFromRunLBN (t); - typename CondContSet::const_iterator it = m_condSet_RE.find (key); - if (it && key < it->first.m_stop) { - if (r) { - *r = &it->first.m_range; - } - ptr = it->second; - } - } - - if (!ptr && t.isTimeStamp()) { - key_type key = CondContBase::keyFromTimestamp (t); - typename CondContSet::const_iterator it = m_condSet_clock.find (key); - if (it && key < it->first.m_stop) { - if (r) { - *r = &it->first.m_range; - } - ptr = it->second; - } - } - - // Do pointer conversion if needed. - if (ptr && clid != ClassID_traits<CondCont<T> >::ID()) { - ptr = Base::cast (clid, static_cast<const typename Base::Payload*> - (reinterpret_cast<const T*> (ptr))); - } - - return ptr; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** * @brief Helper to ensure that the inheritance information for this class * gets initialized. diff --git a/Control/AthenaKernel/src/CondCont.cxx b/Control/AthenaKernel/src/CondCont.cxx index 553ae76fb2f115b28e169aa52517c7c59347bbd0..b68ef6806edbde65b49c67d4d875a5e7bf4f905e 100644 --- a/Control/AthenaKernel/src/CondCont.cxx +++ b/Control/AthenaKernel/src/CondCont.cxx @@ -63,12 +63,269 @@ bool CondContBase::Category::isDuplicate (StatusCode code) STATUSCODE_ENUM_IMPL (CondContStatusCode, CondContBase::Category) +/** + * @brief Set the associated @c DataProxy. + * @param proxy The proxy to set. + */ +void CondContBase::setProxy (SG::DataProxy* proxy) +{ + m_proxy = proxy; +} + + +/** + * @brief Dump the container contents for debugging. + * @param ost Stream to which to write the dump. + */ +void CondContBase::list (std::ostream& ost) const +{ + ost << "id: " << m_id << " proxy: " << m_proxy << std::endl; + + ost << "clock: [" << m_condSet_clock.size() << "]" << std::endl; + for (const typename CondContSet::value_type& ent : m_condSet_clock.range()) { + ost << ent.first.m_range << " " << ent.second << std::endl; + } + ost << "RE: [" << m_condSet_RE.size() << "]" << std::endl; + for (const typename CondContSet::value_type& ent : m_condSet_RE.range()) { + ost << ent.first.m_range << " " << ent.second << std::endl; + } +} + + /** * @brief Dump the container to cout. For calling from the debugger. */ void CondContBase::print() const { - this->list (std::cout); + list (std::cout); +} + + +/** + * @brief Return the number of conditions objects in the container. + */ +size_t CondContBase::entries() const +{ + return m_condSet_RE.size() + m_condSet_clock.size(); +} + + +/** + * @brief Return the number of run+LBN conditions objects + * in the container. + */ +size_t CondContBase::entriesRunLBN() const +{ + return m_condSet_RE.size(); +} + + +/** + * @brief Return the number of timestamp-based conditions objects + * in the container. + */ +size_t CondContBase::entriesTimestamp() const +{ + return m_condSet_clock.size(); +} + + +/** + * @brief Return all IOV validity ranges defined in this container. + */ +std::vector<EventIDRange> +CondContBase::ranges() const +{ + std::vector<EventIDRange> r; + r.reserve (m_condSet_RE.size() + m_condSet_clock.size()); + for (const typename CondContSet::value_type& ent : m_condSet_RE.range()) { + r.push_back( ent.first.m_range ); + } + for (const typename CondContSet::value_type& ent : m_condSet_clock.range()) { + r.push_back( ent.first.m_range ); + } + + return r; +} + + +/** + * @brief Insert a new conditions object. + * @param r Range of validity of this object. + * @param obj Pointer to the object being inserted. + * @param ctx Event context for the current thread. + * + * @c obj must point to an object of type @c T, + * except in the case of inheritance, where the type of @c obj must + * correspond to the most-derived @c CondCont type. + * The container will take ownership of this object. + * + * Returns SUCCESS if the object was successfully inserted; + * DUPLICATE if the object wasn't inserted because the range + * duplicates an existing one, and FAILURE otherwise + * (ownership of the object will be taken in any case). + */ +StatusCode +CondContBase::typelessInsert (const EventIDRange& r, + void* obj, + const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) +{ + return insertBase (r, + CondContSet::payload_unique_ptr (obj, m_condSet_RE.delfcn()), + ctx); +} + + +/** + * @brief Return the mapped validity range for an IOV time. + * @param t IOV time to check. + * @param r[out] The range containing @c t. + * + * Returns true if @c t is mapped; false otherwise. + */ +bool +CondContBase::range(const EventIDBase& t, EventIDRange& r) const +{ + const EventIDRange* rp = nullptr; + if (findBase (t, &rp) != nullptr) { + r = *rp; + return true; + } + return false; +} + + +/** + * @brief Erase the first element not less than @c t. + * @param IOV time of element to erase. + * @param ctx Event context for the current thread. + */ +void CondContBase::erase (const EventIDBase& t, + const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) +{ + if (t.isRunLumi()) { + m_condSet_RE.erase (CondContBase::keyFromRunLBN (t), ctx); + } + else if (t.isTimeStamp()) { + m_condSet_clock.erase (CondContBase::keyFromTimestamp (t), ctx); + } +} + + +/** + * @brief Remove unused run+LBN entries from the front of the list. + * @param keys List of keys that may still be in use. + * (Must be sorted.) + * + * We examine the objects in the container, starting with the earliest one. + * If none of the keys in @c keys match the range for this object, then + * it is removed from the container. We stop when we either find + * an object with a range matching a key in @c keys or when there + * is only one object left. + * + * The list @c keys should contain keys as computed by keyFromRunLBN. + * The list must be sorted. + * + * Removed objects are queued for deletion once all slots have been + * marked as quiescent. + * + * Returns the number of objects that were removed. + */ +size_t CondContBase::trimRunLBN (const std::vector<key_type>& keys) +{ + return m_condSet_RE.trim (keys); +} + + +/** + * @brief Remove unused timestamp entries from the front of the list. + * @param keys List of keys that may still be in use. + * (Must be sorted.) + * + * We examine the objects in the container, starting with the earliest one. + * If none of the keys in @c keys match the range for this object, then + * it is removed from the container. We stop when we either find + * an object with a range matching a key in @c keys or when there + * is only one object left. + * + * The list @c keys should contain keys as computed by keyFromRunLBN. + * The list must be sorted. + * + * Removed objects are queued for deletion once all slots have been + * marked as quiescent. + * + * Returns the number of objects that were removed. + */ +size_t CondContBase::trimTimestamp (const std::vector<key_type>& keys) +{ + return m_condSet_clock.trim (keys); +} + + +/** + * @brief Mark that this thread is no longer accessing data from this container. + * @param ctx Event context for the current thread. + * + * This would normally be done through RCU service. + * Defined here for purposes of testing. + */ +void +CondContBase::quiescent (const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) +{ + m_condSet_RE.quiescent (ctx); + m_condSet_clock.quiescent (ctx); +} + + +/** + * @brief Return the number times an item was inserted into the map. + */ +size_t CondContBase::nInserts() const +{ + return m_condSet_clock.nInserts() + m_condSet_RE.nInserts(); +} + + +/** + * @brief Return the maximum size of the map. + */ +size_t CondContBase::maxSize() const +{ + return m_condSet_clock.maxSize() + m_condSet_RE.maxSize(); +} + + +/** + * @brief Extend the range of the last IOV. + * @param newRange New validity range. + * @param ctx Event context. + * + * Returns failure if the start time of @c newRange does not match the start time + * of the last IOV in the container. Otherwise, the end time for the last + * IOV is changed to the end time for @c newRange. (If the end time for @c newRange + * is before the end of the last IOV, then nothing is changed.) + */ +StatusCode +CondContBase::extendLastRange (const EventIDRange& newRange, + const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) +{ + typename CondContSet::const_iterator it = nullptr; + if (newRange.start().isRunLumi()) { + it = m_condSet_RE.extendLastRange + (RangeKey (newRange, + CondContBase::keyFromRunLBN (newRange.start()), + CondContBase::keyFromRunLBN (newRange.stop())), ctx); + } + else if (newRange.start().isTimeStamp()) { + it = m_condSet_clock.extendLastRange + (RangeKey (newRange, + CondContBase::keyFromTimestamp (newRange.start()), + CondContBase::keyFromTimestamp (newRange.stop())), ctx); + } + if (it != nullptr) { + return StatusCode::SUCCESS; + } + return StatusCode::FAILURE; } @@ -78,12 +335,20 @@ void CondContBase::print() const * @param CLID of the most-derived @c CondCont. * @param id CLID+key for this object. * @param proxy @c DataProxy for this object. + * @param delfcn Deletion function for the actual payload type. + * @param capacity Initial capacity of the container. */ -CondContBase::CondContBase (Athena::IRCUSvc& /*rcusvc*/, +CondContBase::CondContBase (Athena::IRCUSvc& rcusvc, CLID clid, - const DataObjID& /*id*/, - SG::DataProxy* /*proxy*/) + const DataObjID& id, + SG::DataProxy* proxy, + CondContSet::delete_function* delfcn, + size_t capacity) : m_clid (clid), + m_id (id), + m_proxy (proxy), + m_condSet_clock (Updater_t (rcusvc, delfcn), delfcn, capacity), + m_condSet_RE (Updater_t (rcusvc, delfcn), delfcn, capacity), m_cleanerSvc (s_cleanerSvcName, "CondContBase") { if (!m_cleanerSvc.retrieve().isSuccess()) { @@ -92,6 +357,98 @@ CondContBase::CondContBase (Athena::IRCUSvc& /*rcusvc*/, } +/** + * @brief Insert a new conditions object. + * @param r Range of validity of this object. + * @param t Pointer to the object being inserted. + * @param ctx Event context for the current thread. + * + * Returns SUCCESS if the object was successfully inserted; + * DUPLICATE if the object wasn't inserted because the range + * duplicates an existing one, and FAILURE otherwise + * (ownership of the object will be taken in any case). + */ +StatusCode +CondContBase::insertBase (const EventIDRange& r, + CondContSet::payload_unique_ptr t, + const EventContext& ctx /*= Gaudi::Hive::currentContext()*/) +{ + EventIDBase start = r.start(); + EventIDBase stop = r.stop(); + + // LBN part of ranges may be undefined for an open-ended range. + if (start.run_number() != EventIDBase::UNDEFNUM && + stop.run_number() != EventIDBase::UNDEFNUM) + { + if (!m_condSet_RE.emplace( RangeKey(r, + keyFromRunLBN (start), + keyFromRunLBN (stop)), + std::move(t), ctx )) + { + return CondContStatusCode::DUPLICATE; + } + + } + else if (start.isTimeStamp() && stop.isTimeStamp()) { + if (!m_condSet_clock.emplace( RangeKey(r, + keyFromTimestamp (start), + keyFromTimestamp (stop)), + std::move(t), ctx )) + { + return CondContStatusCode::DUPLICATE; + } + } + else { + std::cerr << "CondCont<T>::insert error: EventIDRange " << r + << " is neither fully RunEvent nor TimeStamp" + << std::endl; + return StatusCode::FAILURE; + } + + return this->inserted (ctx); +} + + +/** + * @brief Internal lookup function. + * @param clid CLID for the desired pointer type. + * @param t IOV time to find. + * @param r If non-null, copy validity range of the object here. + * + * Looks up the conditions object corresponding to the IOV time @c t. + * If found, convert the pointer to a pointer to the type identified + * by CLID and return it. Otherwise, return nullptr. + */ +const void* CondContBase::findBase (const EventIDBase& t, + EventIDRange const** r) const +{ + const void* ptr = nullptr; + if (t.isRunLumi()) { + key_type key = keyFromRunLBN (t); + CondContSet::const_iterator it = m_condSet_RE.find (key); + if (it && key < it->first.m_stop) { + if (r) { + *r = &it->first.m_range; + } + ptr = it->second; + } + } + + if (!ptr && t.isTimeStamp()) { + key_type key = keyFromTimestamp (t); + CondContSet::const_iterator it = m_condSet_clock.find (key); + if (it && key < it->first.m_stop) { + if (r) { + *r = &it->first.m_range; + } + ptr = it->second; + } + } + + return ptr; +} + + /** * @brief Tell the cleaner that a new object was added to the container. */ diff --git a/Control/AthenaServices/test/ConditionsCleanerSvc_test.cxx b/Control/AthenaServices/test/ConditionsCleanerSvc_test.cxx index 48266d65f87e3fd7efc25d9df9029b28f37e92fd..701975f22e2ef12ab3b89f24c19f2e6a0e90b041 100644 --- a/Control/AthenaServices/test/ConditionsCleanerSvc_test.cxx +++ b/Control/AthenaServices/test/ConditionsCleanerSvc_test.cxx @@ -27,9 +27,9 @@ class RCUTest : public Athena::IRCUSvc { public: - virtual void add (Athena::IRCUObject*) override { std::abort(); } - virtual StatusCode remove (Athena::IRCUObject*) override { std::abort(); } - virtual size_t getNumSlots() const override { std::abort(); } + virtual void add (Athena::IRCUObject*) override { } + virtual StatusCode remove (Athena::IRCUObject*) override { return StatusCode::SUCCESS; } + virtual size_t getNumSlots() const override { return 1; } virtual unsigned long addRef()override { std::abort(); } virtual unsigned long release() override { std::abort(); } virtual StatusCode queryInterface( const InterfaceID&, void** ) override { std::abort(); } @@ -41,39 +41,12 @@ class CondContTest : public CondContBase { public: - CondContTest() - : CondContBase (m_rcu, 123, m_id, nullptr) + CondContTest (Athena::IRCUSvc& rcusvc, const DataObjID& id) + : CondContBase (rcusvc, 123, id, nullptr, nullptr, 0) {} - virtual const DataObjID& id() const override { std::abort(); } - virtual SG::DataProxy* proxy() override { std::abort(); } - virtual void setProxy(SG::DataProxy*) override { std::abort(); } - virtual void list (std::ostream&) const override { std::abort(); } - virtual size_t entries() const override { std::abort(); } - virtual size_t entriesRunLBN() const override { std::abort(); } - virtual size_t entriesTimestamp() const override { std::abort(); } - virtual std::vector<EventIDRange> ranges() const override { std::abort(); } - virtual StatusCode typelessInsert (const EventIDRange&, - void*, - const EventContext&) override { std::abort(); } - virtual bool valid( const EventIDBase&) const override { std::abort(); } - virtual bool range (const EventIDBase&, EventIDRange&) const override { std::abort(); } - virtual void erase (const EventIDBase&, - const EventContext&) override { std::abort(); } - virtual size_t trimRunLBN (const std::vector<key_type>&) override { std::abort(); } - virtual size_t trimTimestamp (const std::vector<key_type>&) override { std::abort(); } - virtual void quiescent (const EventContext&) override { std::abort(); } - - virtual const void* findByCLID (CLID, - const EventIDBase&, - EventIDRange const**) const override { std::abort(); } - virtual size_t nInserts() const override { std::abort(); } - virtual size_t maxSize() const override { std::abort(); } - virtual StatusCode extendLastRange (const EventIDRange& /*newRange*/, - const EventContext& /*ctx*/) override { std::abort(); } - -private: - RCUTest m_rcu; - DataObjID m_id; + + virtual const void* doCast (CLID /*clid*/, const void* /*ptr*/) const override + { std::abort(); } }; @@ -131,7 +104,10 @@ void testit (IService* mgr) assert( ccs->event (EventContext(0,0), false).isSuccess() ); - CondContTest cc; + RCUTest rcu; + DataObjID id; + + CondContTest cc (rcu, id); assert( ccs->condObjAdded (EventContext(0,0), cc).isSuccess() ); assert( ccs->printStats().isSuccess() ); diff --git a/Control/AthenaServices/test/DelayedConditionsCleanerSvc_test.cxx b/Control/AthenaServices/test/DelayedConditionsCleanerSvc_test.cxx index fc52680c26e283914449b7fbfdb7d1c84339156b..a3b29ee45f6130d6cbd35984aeba326ba3a80934 100644 --- a/Control/AthenaServices/test/DelayedConditionsCleanerSvc_test.cxx +++ b/Control/AthenaServices/test/DelayedConditionsCleanerSvc_test.cxx @@ -37,9 +37,9 @@ class RCUTest : public Athena::IRCUSvc { public: - virtual void add (Athena::IRCUObject*) override { std::abort(); } - virtual StatusCode remove (Athena::IRCUObject*) override { std::abort(); } - virtual size_t getNumSlots() const override { std::abort(); } + virtual void add (Athena::IRCUObject*) override { } + virtual StatusCode remove (Athena::IRCUObject*) override { return StatusCode::SUCCESS; } + virtual size_t getNumSlots() const override { return 1; } virtual unsigned long addRef()override { std::abort(); } virtual unsigned long release() override { std::abort(); } virtual StatusCode queryInterface( const InterfaceID&, void** ) override { std::abort(); } @@ -51,34 +51,13 @@ class CondContTest : public CondContBase { public: - CondContTest (int nlbn, int nts) - : CondContBase (m_rcu, 123, m_id, nullptr), + CondContTest (Athena::IRCUSvc& rcusvc, const DataObjID& id, int nlbn, int nts) + : CondContBase (rcusvc, 123, id, nullptr, nullptr, 0), m_nlbn(nlbn), m_nts (nts) {} - virtual const DataObjID& id() const override { std::abort(); } - virtual SG::DataProxy* proxy() override { std::abort(); } - virtual void setProxy(SG::DataProxy*) override { std::abort(); } - virtual void list (std::ostream&) const override { std::abort(); } - virtual size_t entries() const override { std::abort(); } - virtual std::vector<EventIDRange> ranges() const override { std::abort(); } - virtual StatusCode typelessInsert (const EventIDRange&, - void*, - const EventContext& = Gaudi::Hive::currentContext()) override { std::abort(); } - virtual bool valid( const EventIDBase&) const override { std::abort(); } - virtual bool range (const EventIDBase&, EventIDRange&) const override { std::abort(); } - virtual void erase (const EventIDBase&, - const EventContext& = Gaudi::Hive::currentContext()) override { std::abort(); } - virtual void quiescent (const EventContext& = Gaudi::Hive::currentContext()) override { std::abort(); } - virtual const void* findByCLID (CLID, - const EventIDBase&, - EventIDRange const**) const override { std::abort(); } - - virtual size_t nInserts() const override { return 0; } - virtual size_t maxSize() const override { return 0; } - virtual StatusCode extendLastRange (const EventIDRange& /*newRange*/, - const EventContext& /*ctx*/) override { std::abort(); } - + virtual const void* doCast (CLID /*clid*/, const void* /*ptr*/) const override + { std::abort(); } virtual size_t entriesRunLBN() const override { @@ -120,8 +99,6 @@ public: private: - RCUTest m_rcu; - DataObjID m_id; int m_nlbn; int m_nts; std::list<std::vector<key_type> > m_keysRunLBN; @@ -151,9 +128,12 @@ void test1 (Athena::IConditionsCleanerSvc& svc) { typedef CondContBase::key_type key_type; + RCUTest rcu; + DataObjID id; + std::cout << "test1\n"; - CondContTest cc1 (10, 0); - CondContTest cc2 (0, 10); + CondContTest cc1 (rcu, id, 10, 0); + CondContTest cc2 (rcu, id, 0, 10); assert( svc.event (makeCtx(0), false).isSuccess() ); assert( svc.event (makeCtx(1), false).isSuccess() ); @@ -188,8 +168,8 @@ void test1 (Athena::IConditionsCleanerSvc& svc) assert (cc2.nkeysTimestamp() == 0); assert (cc1.keysRunLBN() == (std::vector<key_type> { 0, 1001, 1003, 1004, 1201, 1301 })); - CondContTest cc3 (10, 0); - CondContTest cc4 (0, 10); + CondContTest cc3 (rcu, id, 10, 0); + CondContTest cc4 (rcu, id, 0, 10); assert( svc.condObjAdded (makeCtx(300), cc1).isSuccess() ); assert( svc.condObjAdded (makeCtx(303), cc2).isSuccess() ); diff --git a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h index 268b81c12f6129f9f857bf9494e192ce2729478d..7e98bfbcd58b592d7f802ca11caaa0de40f0eb11 100644 --- a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h +++ b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h @@ -37,6 +37,17 @@ namespace CxxUtils { * first for which the range is not less than the key. We also * support insertions, erasures, and iteration. * + * The only thing we need to do with the contained pointers is to delete them. + * Rather than doing that directly, we take a deletion function as an argument + * to the constructor; this should be a void function that takes a pointer argument + * and deletes it. This allows one to instantiate this template with @c void as @c T, + * to reduce the amount of generated code. The @c emplace method takes + * a @c unique_ptr as an argument. We define @c payload_unique_ptr which + * is a @c unique_ptr to @c T that does deletion by calling an arbitrary function. + * @c payload_unique_ptr may be initialized from a @c unique_ptr; to construct + * one directly, the deletion function should be passed as a second argument + * to the @c payload_unique_ptr constructor. + * * There can be only one writer at a time; this is enforced with internal locks. * However, there can be any number of concurrent readers at any time. * The reads are lockless (but not necessarily waitless, though this should @@ -116,6 +127,69 @@ public: typedef COMPARE key_compare; typedef KEY key_query_type; + + /// Function to delete a @c T* + typedef void delete_function (const T*); + + + /** + * @brief @c unique_ptr deletion class for a payload object. + * + * We can't use the unique_ptr default because we want to allow + * instantiating with a @c void. + */ + struct DeletePayload + { + /// Initialize with an explicit deletion function. + DeletePayload (delete_function* delfcn) + : m_delete (delfcn) + { + } + + /// Allow initializing a @c payload_unique_ptr from a @c std::unique_ptr<U>. + template <class U> + static void delfcn (const T* p) + { + delete reinterpret_cast<const U*>(p); + } + template <class U> + DeletePayload (const std::default_delete<U>&) + { + m_delete = delfcn<U>; + } + + /// Delete a pointer. + void operator() (const T* p) const + { + m_delete (p); + } + + /// The deletion function. + delete_function* m_delete; + }; + + + /** + * @brief @c unique_ptr holding a payload object. + * + * One may initialize an instance of this in one of two ways. + * First, from another @c std::unique_ptr: + * + *@code + * payload_unique_ptr p = std::unique_ptr<U> (...); + @endcode + * + * where U* must be convertable to T*. In this case, the pointer + * will be deleted as a U*. + * Second, one can supply an explicit deletion function: + * + *@code + * T* tp = ...; + * payload_unique_ptr p (tp, delfcn); + @endcode + */ + typedef std::unique_ptr<T, DeletePayload> payload_unique_ptr; + typedef const value_type* const_iterator; typedef boost::iterator_range<const_iterator> const_iterator_range; @@ -138,9 +212,11 @@ public: public: /** * @brief Constructor. + * @param delfcn Deletion function. * @param capacity Size of the data vector to allocate. */ - Impl (size_t capacity = 10); + Impl (delete_function* delfcn, + size_t capacity = 10); /** @@ -170,6 +246,9 @@ public: private: + /// Deletion function. + delete_function* m_delete; + /// Vector holding the map data. std::vector<value_type> m_data; @@ -185,10 +264,12 @@ public: * @brief Constructor. * @param updater Object used to manage memory * (see comments at the start of the class). + * @param delfcn Deletion function. * @param capacity Initial capacity of the map. * @param compare Comparison object. */ ConcurrentRangeMap (Updater_t&& updater, + delete_function* delfcn, size_t capacity = 16, const COMPARE& compare = COMPARE()); @@ -220,7 +301,7 @@ public: * no new element is inserted (and @c ptr gets deleted). */ bool emplace (const RANGE& range, - std::unique_ptr<T> ptr, + payload_unique_ptr ptr, const typename Updater_t::Context_t& ctx = Updater_t::defaultContext()); @@ -335,6 +416,12 @@ public: Updater_t::defaultContext()); + /** + * @brief Return the deletion function for this container. + */ + delete_function* delfcn() const; + + private: /** * @brief Return the begin/last pointers. @@ -393,6 +480,9 @@ private: /// Comparison object. COMPARE m_compare; + /// Deletion function. + delete_function* m_delete; + /// Current version of the implementation class. Impl* m_impl; diff --git a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc index 094c98684f8cb37da50a328fe61625d5419fccab..95dd7251494b5a54e149a193fbe918ee6d869d16 100644 --- a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc +++ b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc @@ -19,11 +19,14 @@ namespace CxxUtils { /** * @brief Constructor. + * @param delfcn Deletion function. * @param capacity Size of the data vector to allocate. */ T_CONCURRENTRANGEMAP -CONCURRENTRANGEMAP::Impl::Impl (size_t capacity /*= 10*/) - : m_data (capacity) +CONCURRENTRANGEMAP::Impl::Impl (delete_function* delfcn, + size_t capacity /*= 10*/) + : m_delete (delfcn), + m_data (capacity) { } @@ -37,7 +40,7 @@ T_CONCURRENTRANGEMAP CONCURRENTRANGEMAP::Impl::~Impl() { for (const T* p : m_garbage) { - delete p; + m_delete (p); } } @@ -79,19 +82,23 @@ CONCURRENTRANGEMAP::Impl::discard (const T* p) * @brief Constructor. * @param updater Object used to manage memory * (see comments at the start of the class). + * @param delfcn Deletion function. * @param capacity Initial capacity of the map. * @param compare Comparison object. */ T_CONCURRENTRANGEMAP CONCURRENTRANGEMAP::ConcurrentRangeMap (Updater_t&& updater, + delete_function* delfcn, size_t capacity /*= 16*/, const COMPARE& compare /*= COMPARE()*/) + : m_updater (std::move (updater)), m_compare (compare), + m_delete (delfcn), m_nInserts (0), m_maxSize (0) { - auto impl = std::make_unique<Impl> (capacity); + auto impl = std::make_unique<Impl> (m_delete, capacity); value_type* data = impl->data(); installImpl (std::move (impl), data, data, @@ -110,7 +117,7 @@ CONCURRENTRANGEMAP::~ConcurrentRangeMap() value_type* last = m_last; if (last) { for (value_type* p = m_begin; p <= m_last; ++p) { - delete p->second; + m_delete (p->second); } } @@ -165,7 +172,7 @@ CONCURRENTRANGEMAP::find (const key_query_type& key) const T_CONCURRENTRANGEMAP bool CONCURRENTRANGEMAP::emplace (const RANGE& range, - std::unique_ptr<T> ptr, + payload_unique_ptr ptr, const typename Updater_t::Context_t& ctx /*= Updater_t::defaultContext()*/) { @@ -209,7 +216,7 @@ CONCURRENTRANGEMAP::emplace (const RANGE& range, } // Allocate the new object. - auto new_impl = std::make_unique<Impl> (new_capacity); + auto new_impl = std::make_unique<Impl> (m_delete, new_capacity); value_type* new_begin = new_impl->data(); value_type* new_end = new_begin; @@ -293,7 +300,7 @@ CONCURRENTRANGEMAP::erase (const key_query_type& key, // Need to make a new implementation object and copy data. size_t capacity = m_impl->capacity(); - auto new_impl = std::make_unique<Impl> (capacity); + auto new_impl = std::make_unique<Impl> (m_delete, capacity); value_type* new_begin = new_impl->data(); value_type* new_end = new_begin; @@ -355,7 +362,7 @@ CONCURRENTRANGEMAP::extendLastRange (const RANGE& newRange, // Make a new implementation object and copy data. size_t capacity = m_impl->capacity(); - auto new_impl = std::make_unique<Impl> (capacity); + auto new_impl = std::make_unique<Impl> (m_delete, capacity); value_type* new_begin = new_impl->data(); value_type* new_end = new_begin; value_type* begin = m_begin; @@ -426,7 +433,7 @@ CONCURRENTRANGEMAP::trim (const std::vector<key_query_type>& keys) if (!garbage) { // Allocate a dummy impl object if we haven't done so yet. - garbage = std::make_unique<Impl> (0); + garbage = std::make_unique<Impl> (m_delete, 0); } // Add it to the garbage list. @@ -534,6 +541,18 @@ CONCURRENTRANGEMAP::quiescent (const typename Updater_t::Context_t& ctx /*= Upda } +/** + * @brief Return the deletion function for this container. + */ +T_CONCURRENTRANGEMAP +inline +typename CONCURRENTRANGEMAP::delete_function* +CONCURRENTRANGEMAP::delfcn() const +{ + return m_delete; +} + + /** * @brief Return the begin/last pointers. * @param [inout] last Current value of last. diff --git a/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx b/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx index 3fbaabec2322f365cd91ba614592953a1577c820..abfdfc1d9a0be13c272adf4c6d351917379aadac 100644 --- a/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx +++ b/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx @@ -76,6 +76,12 @@ struct Payload }; +void delfcn (const Payload* p) +{ + delete p; +} + + template <class T> class TestUpdater { @@ -152,7 +158,7 @@ void test1a() std::cout << "test1a\n"; Payload::Hist phist; { - TestMap map (TestMap::Updater_t(), 3); + TestMap map (TestMap::Updater_t(), delfcn, 3); assert (map.size() == 0); assert (map.empty()); @@ -555,7 +561,7 @@ void test1b() std::cout << "test1b\n"; Payload::Hist phist; - TestMap map (TestMap::Updater_t(), 100); + TestMap map (TestMap::Updater_t(), delfcn, 100); assert (map.emplace (Range (10, 20), std::make_unique<Payload> (100, &phist))); assert (map.emplace (Range (25, 30), std::make_unique<Payload> (200, &phist))); assert (map.emplace (Range (30, 40), std::make_unique<Payload> (300, &phist))); @@ -785,7 +791,7 @@ void test2_Reader::operator()() void test2_iter() { - TestMap map (TestMap::Updater_t(), 20); + TestMap map (TestMap::Updater_t(), delfcn, 20); const int nthread = 4; std::thread threads[nthread];