diff --git a/Control/StoreGate/StoreGate/ReadHandleKeyArray.h b/Control/StoreGate/StoreGate/ReadHandleKeyArray.h new file mode 100644 index 0000000000000000000000000000000000000000..d9464c503a9454c3fbdecaa81f04974a2b8628e9 --- /dev/null +++ b/Control/StoreGate/StoreGate/ReadHandleKeyArray.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_READHANDLEKEYARRAY_H +#define STOREGATE_READHANDLEKEYARRAY_H 1 + +#include "StoreGate/VarHandleKeyArray.h" + +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/ReadHandle.h" + +#include <vector> +#include <string> + +namespace SG { + + /** + * @class SG::ReadHandleKeyArray<T> + * @brief class to hold an array of ReadHandleKeys + * + * since it inherits from std::vector, all vector operations are + * permitted. + * + * initialization can be done in three ways. + * 1: with an std::vector<ReadHandleKey> as a parameter + * SG::ReadHandleKeyArray<foo> m_foo ( std::vector<ReadHandleKey> ); + * 2: with an initializer list of ReadHandleKeys + * SG::ReadHandleKeyArray<foo> m_foo { ReadHandleKey<foo> k1, ReadHandleKey<foo> k2 }; + * 3: with an initializer list of std::strings, that will be used to + * internally create ReadHandleKeys with those initializers + * SG::ReadHandleKeyArray<foo> m_foo { "key1", "key2", "key3" }; + */ + + template <class T> + class ReadHandleKeyArray : public VarHandleKeyArrayCommon< ReadHandleKey<T> > { + public: + /** + * @brief default Constructor from a ReadHandleKeyArray + */ + ReadHandleKeyArray(){}; + + /** + * @brief Constructor from a ReadHandleKeyArray that takes a vector + * of ReaDHandleKeys + * @param v vector of ReadHandleKey + */ + ReadHandleKeyArray( const std::vector<ReadHandleKey<T>>& v ): + VarHandleKeyArrayCommon<ReadHandleKey<T>> ( v ) {}; + + /** + * @brief Constructor from a ReadHandleKeyArray that takes an + * initializer list of ReadHandleKeys + * @param l initializer list of ReadHandleKey + */ + ReadHandleKeyArray( std::initializer_list<ReadHandleKey<T>> l ): + VarHandleKeyArrayCommon<ReadHandleKey<T>> {l} {}; + + /** + * @brief Constructor from a ReadHandleKeyArray that takes an + * initializer list of std::strings. + * @param l initializer list of std::strings used to create the + * ReadHandleKeys + */ + ReadHandleKeyArray( std::initializer_list<std::string> l ): + VarHandleKeyArrayCommon<ReadHandleKey<T>> {l} {}; + + /** + * @brief return the type (Read/Write/Update) of handle + */ + Gaudi::DataHandle::Mode mode() const { return Gaudi::DataHandle::Reader; } + + /** + * @brief create a vector of ReadHandles from the ReadHandleKeys + * in the array + */ + std::vector< ReadHandle<T> > makeHandles() const { + std::vector< ReadHandle<T> > hndl; + typename std::vector<ReadHandleKey<T>>::const_iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + hndl.push_back ( ReadHandle<T>( *itr) ); + } + return ( std::move( hndl ) ); + } + + }; + + +} // namespace SG + +#endif diff --git a/Control/StoreGate/StoreGate/SGtests.h b/Control/StoreGate/StoreGate/SGtests.h index df7c9855e94b8e821a84d9a3b630e1220c03c9b6..d2098117579392ced5e23c93f4a50dffe0ca313f 100644 --- a/Control/StoreGate/StoreGate/SGtests.h +++ b/Control/StoreGate/StoreGate/SGtests.h @@ -53,5 +53,9 @@ namespace Athena_test void testBoundReset(StoreGateSvc& rSG); + void testRecordObject(StoreGateSvc& rSG); + + void testWriteAux(StoreGateSvc& rSG); + } //end namespace #endif // TEST_SGTESTS_H diff --git a/Control/StoreGate/StoreGate/StoreGateSvc.h b/Control/StoreGate/StoreGate/StoreGateSvc.h index 3dce2ddff9cd8e44aceca2908ffbfe10c732b6b4..64dbb169ac0825fcba0e725b0cfcbb1da1cc0ccc 100644 --- a/Control/StoreGate/StoreGate/StoreGateSvc.h +++ b/Control/StoreGate/StoreGate/StoreGateSvc.h @@ -511,6 +511,8 @@ public: /// set store ID. request forwarded to DataStore: void setStoreID(StoreID::type id); + /// get store ID. request forwarded to DataStore: + StoreID::type storeID() const; /** provide list of all storegate keys associated with an object. @@ -645,6 +647,8 @@ public: * @param key The key as which it should be stored. * @param allowMods If false, the object will be recorded as const. * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. * * Full-blown record. @c obj should usually be something * deriving from @c SG::DataBucket. @@ -954,7 +958,9 @@ private: /// remove proxy from store, unless it is reset only. /// provide pTrans!=0 (must match proxy...) to save time - /// @param forceRemove remove the proxy no matter what + /// @param forceRemove remove the proxy no matter what + /// DO NOT USE THIS FUNCTION! + /// IT IS UNSAFE AND IS LIKELY TO BE REMOVED! StatusCode removeProxy(SG::DataProxy* proxy, const void* pTrans, bool forceRemove=false); ///forwarded to DataStore diff --git a/Control/StoreGate/StoreGate/VarHandleKeyArray.h b/Control/StoreGate/StoreGate/VarHandleKeyArray.h new file mode 100644 index 0000000000000000000000000000000000000000..3616da01c05da37858d315877283d3872e727ba7 --- /dev/null +++ b/Control/StoreGate/StoreGate/VarHandleKeyArray.h @@ -0,0 +1,116 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_VARHANDLEKEYARRAY_H +#define STOREGATE_VARHANDLEKEYARRAY_H 1 + +/** + * @file StoreGate/VarHandleKeyArray.h + * @author C. Leggett + * @date Updated: Jun 17, 2016 + * @brief Base class for VarHandleKeyArray for reading from StoreGate. + */ + +#include "GaudiKernel/DataHandle.h" +#include "StoreGate/VarHandleKey.h" + +#include <vector> +#include <string> + +namespace SG { + + /** + * @class SG::VarHandleKeyArray<T> + * @brief untemplated base class for VarHandleKeyArrays + */ + class VarHandleKeyArray { + public: + VarHandleKeyArray(){}; + virtual ~VarHandleKeyArray(){}; + virtual StatusCode assign(const std::vector<std::string>& vs)=0; + virtual std::string toString() const = 0; + virtual Gaudi::DataHandle::Mode mode() const = 0; + + virtual std::vector<SG::VarHandleKey*> keys() const = 0; + + }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +// mixin class for common functionality +// + + /** + * @class SG::VarHandleKeyArrayCommon<T> + * @brief mixin base class for VarHandleKeyArrays, inheriting from + * std::vector as well as VarHandleKeyArray to provide vector-like + * access + * + */ + + template <class Base> + class VarHandleKeyArrayCommon : public VarHandleKeyArray, + public std::vector<Base> { + public: + /** + * @brief default base Constructor of mixin + * + */ + VarHandleKeyArrayCommon() : std::vector<Base>() {}; + + /** + * @brief base Constructor from a VarHandleKeyArray that takes a vector + * @param v vector of Read/Write/UpdateHandleKey + */ + VarHandleKeyArrayCommon( const std::vector<Base>& v ): + std::vector<Base>(v) {}; + + /** + * @brief base Constructor from a VarHandleKeyArray that takes an + * initializer list of VarHandleKeys + * @param l initializer list of Read/Write/UpdateHandleKey + */ + VarHandleKeyArrayCommon( std::initializer_list<Base> l ): + std::vector<Base>{l} {}; + + /** + * @brief base Constructor from a VarHandleKeyArray that takes an + * initializer list of std::strings. + * @param l initializer list of std::strings used to create the + * VarHandleKeys + */ + VarHandleKeyArrayCommon( std::initializer_list<std::string> l ) { + for (auto &e : l) { + this->push_back( Base{e} ); + } + } + + /** + * @brief forward the initialization to the member VarHandleKeys + */ + StatusCode initialize(); + + /** + * @brief Set the contents of the VarHandleKeyArray from a + * vector of std::strings + * @param vs vector of initializer strings + */ + StatusCode assign(const std::vector<std::string>& vs); + + /** + * @brief string representation of the VarHandleKeyArray + */ + std::string toString() const; + + /** + * @brief create array of all base VarHandleKeys in the Array + */ + std::vector<SG::VarHandleKey*> keys() const; + + }; + +} // namespace SG + +#include "StoreGate/VarHandleKeyArray.icc" + +#endif diff --git a/Control/StoreGate/StoreGate/VarHandleKeyArray.icc b/Control/StoreGate/StoreGate/VarHandleKeyArray.icc new file mode 100644 index 0000000000000000000000000000000000000000..9dd049ce85789d2bb973f8836e4f83f3716632c4 --- /dev/null +++ b/Control/StoreGate/StoreGate/VarHandleKeyArray.icc @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +namespace SG { + // + // Forward the initialization to the member VarHandleKeys + // + template <class Base> + inline + StatusCode VarHandleKeyArrayCommon<Base>::initialize() { + StatusCode sc(StatusCode::SUCCESS); + typename std::vector<Base>::iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + if (! itr->initialize() ) { + sc = StatusCode::FAILURE; + } + } + return sc; + } + + // + // Set the VarHandleKey from a string + // + template <class Base> + inline + StatusCode VarHandleKeyArrayCommon<Base>::assign(const std::vector<std::string>& vs) { + StatusCode sc(StatusCode::SUCCESS); + this->clear(); + for (auto & s : vs) { + Base b; + if (!b.assign(s)) { + sc = StatusCode::FAILURE; + } else { + // Skip blank keys + if (b.key() != "") { + this->push_back(b); + } + } + } + return sc; + } + + // + // string representation of VarHandleKeyArray + // + template <class Base> + inline + std::string VarHandleKeyArrayCommon<Base>::toString() const { + std::ostringstream ost; + typename std::vector<Base>::const_iterator itr; + itr = this->begin(); + size_t sz = this->size(); + for ( size_t i=0; i < sz; ++i, ++itr) { + ost << "'" << itr->storeHandle().name() << "/" + << itr->objKey() << "'"; + if (i != sz-1) { + ost << ","; + } + } + return ost.str(); + } + + // + // create array of all base VarHandleKeys in the Array + // + template <class Base> + inline + std::vector<SG::VarHandleKey*> VarHandleKeyArrayCommon<Base>::keys() const { + std::vector<SG::VarHandleKey*> keys; + typename std::vector<Base>::const_iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + SG::VarHandleKey* vk = + const_cast<SG::VarHandleKey*>( (const SG::VarHandleKey*) &(*itr) ); + keys.push_back( vk ); + } + return keys; + } + +} diff --git a/Control/StoreGate/StoreGate/VarHandleKeyArrayProperty.h b/Control/StoreGate/StoreGate/VarHandleKeyArrayProperty.h new file mode 100644 index 0000000000000000000000000000000000000000..eaa86d68f6caafe92918dbf36014900dd398b481 --- /dev/null +++ b/Control/StoreGate/StoreGate/VarHandleKeyArrayProperty.h @@ -0,0 +1,104 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_VARHANDLEKEYARRAYPROPERTY +#define STOREGATE_VARHANDLEKEYARRAYPROPERTY 1 + +/** + * @file StoreGate/VarHandleKeyArrayProperty.h + * @author C. Leggett + * @date Updated: Jun 17, 2016 + * @brief class to handle Properties for VarHandleKeyArray + */ + +#include "StoreGate/VarHandleKeyArray.h" +#include "StoreGate/ReadHandleKeyArray.h" +#include "StoreGate/WriteHandleKeyArray.h" +#include "GaudiKernel/Property.h" +#include <iostream> + +namespace Gaudi { + namespace Parsers { + GAUDI_API + StatusCode parse(SG::VarHandleKeyArray& v, const std::string& s); + } + + namespace Utils { + GAUDI_API + std::ostream& toStream(const SG::VarHandleKeyArray& v, std::ostream& o); + } +} + +namespace SG { + + class GAUDI_API VarHandleKeyArrayProperty + : public ::Property + { + public: + + VarHandleKeyArrayProperty( const std::string& name, + SG::VarHandleKeyArray& ref ); + + VarHandleKeyArrayProperty& operator=( const SG::VarHandleKeyArray& value ); + + virtual VarHandleKeyArrayProperty* clone() const override; + + virtual bool load( Property& destination ) const override; + + virtual bool assign( const Property& source ) override; + + virtual std::string toString() const override; + + virtual void toStream(std::ostream& out) const override; + + virtual StatusCode fromString(const std::string& s) override; + + const SG::VarHandleKeyArray& value() const; + + bool setValue( const SG::VarHandleKeyArray& value ); + + + private: + /** Pointer to the real property. Reference would be better, + * but Reflex does not support references yet + */ + SG::VarHandleKeyArray* m_pValue; + }; + + +} // namespace SG + +template<> +class SimplePropertyRef< SG::VarHandleKeyArray > : + public SG::VarHandleKeyArrayProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::VarHandleKeyArray& value) : + SG::VarHandleKeyArrayProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::ReadHandleKeyArray<T> > : + public SG::VarHandleKeyArrayProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::ReadHandleKeyArray<T>& value) : + SG::VarHandleKeyArrayProperty(name, value) {} +}; + +template<typename T> +class SimplePropertyRef< SG::WriteHandleKeyArray<T> > : + public SG::VarHandleKeyArrayProperty +{ +public: + SimplePropertyRef( const std::string& name, + SG::WriteHandleKeyArray<T>& value ) : + SG::VarHandleKeyArrayProperty(name, value) {} +}; + + + + +#endif diff --git a/Control/StoreGate/StoreGate/WriteHandle.h b/Control/StoreGate/StoreGate/WriteHandle.h index bf7b11da2d23f89cbb0662e6936a37a21415f7a2..84d99dcff0029135f79bbc4a039540db39eaba0d 100644 --- a/Control/StoreGate/StoreGate/WriteHandle.h +++ b/Control/StoreGate/StoreGate/WriteHandle.h @@ -4,7 +4,7 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -// $Id: WriteHandle.h 726621 2016-02-27 20:03:45Z ssnyder $ +// $Id: WriteHandle.h 756419 2016-06-21 02:02:43Z ssnyder $ /** * @file StoreGate/WriteHandle.h * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> @@ -145,7 +145,15 @@ public: /** * @brief Move operator. */ - WriteHandle& operator=( WriteHandle&& rhs ); + WriteHandle& operator=( WriteHandle&& rhs ); + + + /** + * @brief Destructor. + * + * Lock an aux object if m_lockAuxPending is set. + */ + ~WriteHandle(); //************************************************************************ @@ -312,6 +320,24 @@ private: record (std::unique_ptr<T> data, std::unique_ptr<AUXSTORE> auxstore, bool isConst); + + +private: + /// If non-null, then we need to lock the associated aux store object + /// when we're deleted. + /// + /// This is set when we record an object along with the associated aux const + /// with the const flag set (the default). Recall that for a const record, + /// we want to support the semantics that you can get a non-const pointer + /// back from the handle as long as it exists, to finish initialization + /// of the object. For an aux store, though, just getting back a non-const + /// pointer is not sufficient, since the store will have been locked + /// at the time of the record, preventing changes to the store. + /// + /// So if we're meant to record a const aux store object, we don't actually + /// set it const on the record, but instead set this and do the + /// setConst in the destructor. + SG::DataProxy* m_lockAuxPending = nullptr; }; diff --git a/Control/StoreGate/StoreGate/WriteHandle.icc b/Control/StoreGate/StoreGate/WriteHandle.icc index 4fa307d6dda9b0a1d0ce7972870e6adf37ce98e6..4b5e3f016dd546982a5b5201173f11973c3b5429 100644 --- a/Control/StoreGate/StoreGate/WriteHandle.icc +++ b/Control/StoreGate/StoreGate/WriteHandle.icc @@ -2,7 +2,7 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -// $Id: WriteHandle.icc 726840 2016-02-29 16:43:53Z ssnyder $ +// $Id: WriteHandle.icc 756419 2016-06-21 02:02:43Z ssnyder $ /** * @file StoreGate/WriteHandle.icc * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> @@ -23,6 +23,36 @@ namespace SG { +/** + * @brief Helper to temporarily clear aux store association. + * + * This is used in the object+store version of record, in order to prevent + * the store from being locked prematurely. + */ +template <class T> +class SaveStore +{ +public: + SaveStore (T& o) + : m_store (o.getStore()), + m_o (o) + { + if (m_store) + o.setStore (static_cast<SG::IAuxStore*>(nullptr)); + } + + ~SaveStore() + { + if (m_store) + m_o.setStore (m_store); + } + +private: + IAuxStore* m_store; + T& m_o; +}; + + //************************************************************************ // Constructors, etc. // @@ -140,6 +170,20 @@ WriteHandle<T>::operator= (WriteHandle&& h) } +/** + * @brief Destructor. + * + * Lock an aux object if m_lockAuxPending is true. + */ +template <class T> +WriteHandle<T>::~WriteHandle() +{ + if (m_lockAuxPending) { + m_lockAuxPending->setConst(); + } +} + + //************************************************************************ // Deference. These all return only the cached pointer. // @@ -414,8 +458,12 @@ WriteHandle<T>::record (std::unique_ptr<T> data, { T& dref = *data; - if (isConst) + if (isConst) { + // Temporarily clear the store association, in order to prevent + // the aux store from being locked at this point. + SaveStore<T> ss (*data); CHECK (this->record(std::move(data))); + } else CHECK (this->recordNonConst(std::move(data))); @@ -425,7 +473,7 @@ WriteHandle<T>::record (std::unique_ptr<T> data, (SG::asStorable (std::move (auxstore))); SG::DataProxy* proxy = m_store->recordObject (std::move(dobj), this->name() + "Aux.", - !m_proxy->isConst(), + true, false); if (!proxy) { REPORT_ERROR (StatusCode::FAILURE) @@ -438,6 +486,8 @@ WriteHandle<T>::record (std::unique_ptr<T> data, return StatusCode::FAILURE; } + if (m_proxy->isConst()) + m_lockAuxPending = proxy; return StatusCode::SUCCESS; } diff --git a/Control/StoreGate/StoreGate/WriteHandleKeyArray.h b/Control/StoreGate/StoreGate/WriteHandleKeyArray.h new file mode 100644 index 0000000000000000000000000000000000000000..8c051ff88f2f7d552336fadb481b1aa0b4f93ec9 --- /dev/null +++ b/Control/StoreGate/StoreGate/WriteHandleKeyArray.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_WRITEHANDLEKEYARRAY_H +#define STOREGATE_WRITEHANDLEKEYARRAY_H 1 + +#include "StoreGate/VarHandleKeyArray.h" + +#include "StoreGate/WriteHandleKey.h" +#include "StoreGate/WriteHandle.h" + +#include <vector> +#include <string> + +namespace SG { + + /** + * @class SG::WriteHandleKeyArray<T> + * @brief class to hold an array of WriteHandleKeys + * + * since it inherits from std::vector, all vector operations are + * permitted. + * + * initialization can be done in three ways. + * 1: with an std::vector<WriteHandleKey> as a parameter + * SG::WriteHandleKeyArray<foo> m_foo ( std::vector<WriteHandleKey> ); + * 2: with an initializer list of WriteHandleKeys + * SG::WriteHandleKeyArray<foo> m_foo { WriteHandleKey<foo> k1, WriteHandleKey<foo> k2 }; + * 3: with an initializer list of std::strings, that will be used to + * internally create WriteHandleKeys with those initializers + * SG::WriteHandleKeyArray<foo> m_foo { "key1", "key2", "key3" }; + */ + + template <class T> + class WriteHandleKeyArray : public VarHandleKeyArrayCommon< WriteHandleKey<T> > { + public: + /** + * @brief default Constructor from a WriteHandleKeyArray + */ + WriteHandleKeyArray(){}; + + /** + * @brief Constructor from a WriteHandleKeyArray that takes a vector + * of ReaDHandleKeys + * @param v vector of WriteHandleKey + */ + WriteHandleKeyArray( const std::vector<WriteHandleKey<T>>& v ) : + VarHandleKeyArrayCommon<WriteHandleKey<T>> ( v ) {}; + + /** + * @brief Constructor from a WriteHandleKeyArray that takes an + * initializer list of WriteHandleKeys + * @param l initializer list of WriteHandleKey + */ + WriteHandleKeyArray( std::initializer_list<WriteHandleKey<T>> l ): + VarHandleKeyArrayCommon<WriteHandleKey<T>> {l} {}; + + /** + * @brief Constructor from a WriteHandleKeyArray that takes an + * initializer list of std::strings. + * @param l initializer list of std::strings used to create the + * WriteHandleKeys + */ + WriteHandleKeyArray( std::initializer_list<std::string> l ): + VarHandleKeyArrayCommon<WriteHandleKey<T>> {l} {}; + + /** + * @brief return the type (Read/Write/Update) of handle + */ + Gaudi::DataHandle::Mode mode() const { return Gaudi::DataHandle::Writer; } + + /** + * @brief create a vector of WriteHandles from the WriteHandleKeys + * in the array + */ + std::vector< WriteHandle<T> > makeHandles() const { + std::vector< WriteHandle<T> > hndl; + typename std::vector<WriteHandleKey<T>>::const_iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + hndl.push_back ( WriteHandle<T>( *itr) ); + } + return ( std::move( hndl ) ); + } + + }; + + +} // namespace SG + +#endif diff --git a/Control/StoreGate/StoreGate/tools/SGImplSvc.h b/Control/StoreGate/StoreGate/tools/SGImplSvc.h index 069b569f5e9df89154538f0b42db43ffadbd4b1f..2d94299d728195d31c3d1ea7345246565a49e461 100644 --- a/Control/StoreGate/StoreGate/tools/SGImplSvc.h +++ b/Control/StoreGate/StoreGate/tools/SGImplSvc.h @@ -113,7 +113,7 @@ namespace PerfMon { class StorePayloadMon; } * @param "FolderNameList" property (default ""): data folders to be created * in this store * @author ATLAS Collaboration - * $Id: SGImplSvc.h 733875 2016-04-04 23:33:03Z leggett $ + * $Id: SGImplSvc.h 754375 2016-06-13 02:59:46Z ssnyder $ **/ class SGImplSvc : public Service, @@ -501,6 +501,8 @@ public: /// set store ID. request forwarded to DataStore: void setStoreID(StoreID::type id); + /// get store ID. request forwarded to DataStore: + StoreID::type storeID() const; /** provide list of all storegate keys associated with an object. @@ -594,6 +596,8 @@ public: * @param key The key as which it should be stored. * @param allowMods If false, the object will be recorded as const. * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. * * Full-blown record. @c obj should usually be something * deriving from @c SG::DataBucket. diff --git a/Control/StoreGate/src/SGImplSvc.cxx b/Control/StoreGate/src/SGImplSvc.cxx index dd1016a05a0008d4508799560a6efa9fed1aaec5..f07bad09d215f3ed4dcde21409cc0b792e3834ac 100644 --- a/Control/StoreGate/src/SGImplSvc.cxx +++ b/Control/StoreGate/src/SGImplSvc.cxx @@ -56,13 +56,52 @@ using std::hex; using std::dec; using std::endl; using std::ends; +using std::pair; using std::setw; using std::string; +using std::vector; using SG::DataProxy; using SG::DataStore; using SG::TransientAddress; +/////////////////////////////////////////////////////////////////////////// +// Find the store id + +// return StoreID corresponding to storeNamePrefix. +StoreID::type findStoreID(const string& storeNamePrefix) { + //vector must be lexically sorted + static const vector<pair<string, StoreID::type> > NAMETOID { + { "ConditionsStore", StoreID::CONDITION_STORE }, + { "DetectorStore", StoreID::DETECTOR_STORE }, + { "EventStore", StoreID::EVENT_STORE }, + { "InputMetaDataStore", StoreID::METADATA_STORE }, + { "MetaDataStore", StoreID::SIMPLE_STORE }, + { "SpareStore", StoreID::SPARE_STORE }, + { "StoreGateSvc", StoreID::EVENT_STORE }, + { "TagMetaDataStore", StoreID::METADATA_STORE } + }; + const auto BEG(NAMETOID.begin()); + const auto END(NAMETOID.end()); + + // Account for AthenaMT stores that start with {digits}_ + size_t ist (0); + if (::isdigit(storeNamePrefix.at(0))) { + ist = storeNamePrefix.find("_",0) +1; + } + + auto i(BEG); + while (i != END) { + int comp = storeNamePrefix.compare(ist, (i->first).size(), (i->first)); + // std::cout << storeNamePrefix <<' '<< storeNamePrefix.size() <<' '<< i->first <<' '<< (i->first).size() <<' '<< comp << std::endl; + //NAMETOID is sorted so if we go past storeNamePrefix we are done + if (comp < 0) break; + else if (comp == 0) return i->second; + ++i; + } + return StoreID::UNKNOWN; +} + /////////////////////////////////////////////////////////////////////////// // Remapping implementation. @@ -142,47 +181,28 @@ SGImplSvc::~SGImplSvc() { /// Service initialisation StatusCode SGImplSvc::initialize() { - msg() << MSG::INFO << "Initializing " << name() + msg() << MSG::VERBOSE << "Initializing " << name() << " - package version " << PACKAGE_VERSION << endreq ; + if(!(Service::initialize()).isSuccess()) { + msg() << MSG::ERROR << "Could not initialize base Service !!" << endreq; + return StatusCode::FAILURE; + } + if (!m_pStore) m_pStore = new DataStore (*this); if (!m_remap_impl) m_remap_impl = new SG::RemapImpl; - if(!(Service::initialize()).isSuccess()) { - msg() << MSG::ERROR << "Could not initialize base Service !!" << endreq; - return StatusCode::FAILURE; - } //properties accessible from now on - // set store ID (ugly!): - string generic_name = name() ; - if (generic_name.find("StoreGateSvc")!=std::string::npos || - generic_name.find("EventStore")!=std::string::npos) { - store()->setStoreID(StoreID::EVENT_STORE); - } else if (generic_name.find("DetectorStore")!=std::string::npos) { - store()->setStoreID(StoreID::DETECTOR_STORE); - } else if (generic_name.find("ConditionsStore")!=std::string::npos) { - store()->setStoreID(StoreID::CONDITION_STORE); - } else if (generic_name.find("InputMetaDataStore")!=std::string::npos || - generic_name.find("TagMetaDataStore")!=std::string::npos) { - store()->setStoreID(StoreID::METADATA_STORE); - } else if (generic_name.find("MetaDataStore")!=std::string::npos) { - store()->setStoreID(StoreID::SIMPLE_STORE); - } else if (generic_name.find("SpareStore")!=std::string::npos) { - store()->setStoreID(StoreID::SPARE_STORE); - } else { - store()->setStoreID(StoreID::UNKNOWN); - } + store()->setStoreID(findStoreID(name())); // If this is the default event store (StoreGateSvc), then declare // our arena as the default for memory allocations. - if (generic_name.find("StoreGateSvc")!=std::string::npos || - generic_name.find("EventStore")!=std::string::npos) - { - m_arena.makeCurrent(); - SG::CurrentEventStore::setStore (this); - } + if (this->storeID() == StoreID::EVENT_STORE) { + m_arena.makeCurrent(); + SG::CurrentEventStore::setStore (this); + } // set up the incident service: if (!(m_pIncSvc.retrieve()).isSuccess()) { msg() << MSG::ERROR @@ -238,7 +258,7 @@ StatusCode SGImplSvc::initialize() { /// Service start StatusCode SGImplSvc::start() { - msg() << MSG::INFO << "Start " << name() << endreq; + msg() << MSG::VERBOSE << "Start " << name() << endreq; /* // This will need regFcn clients to be updated first. if ( 0 == m_pPPS || (m_pPPS->preLoadProxies(*m_pStore)).isFailure() ) @@ -255,7 +275,7 @@ StatusCode SGImplSvc::start() { /// Service stop StatusCode SGImplSvc::stop() { - msg() << MSG::INFO << "Stop " << name() << endreq; + msg() << MSG::VERBOSE << "Stop " << name() << endreq; //HACK ALERT: ID event store objects refer to det store objects //by setting an ad-hoc priority for event store(s) we make sure they are finalized and hence cleared first // see e.g. https://savannah.cern.ch/bugs/index.php?99993 @@ -264,7 +284,7 @@ StatusCode SGImplSvc::stop() { if (!pISM) return StatusCode::FAILURE; pISM->setPriority(name(), pISM->getPriority(name())+1).ignore(); - msg() << MSG::INFO << "stop: setting service priority to " << pISM->getPriority(name()) + msg() << MSG::VERBOSE << "stop: setting service priority to " << pISM->getPriority(name()) << " so that event stores get finalized and cleared before other stores" <<endmsg; } return StatusCode::SUCCESS; @@ -349,7 +369,7 @@ StatusCode SGImplSvc::clearStore(bool forceRemove) ////////////////////////////////////////////////////////////// /// Service finalisation StatusCode SGImplSvc::finalize() { - msg() << MSG::INFO << "Finalizing " << name() + msg() << MSG::VERBOSE << "Finalizing " << name() << " - package version " << PACKAGE_VERSION << endreq ; // Incident service may not work in finalizea. @@ -377,7 +397,7 @@ StatusCode SGImplSvc::finalize() { ////////////////////////////////////////////////////////////// /// Service reinitialization StatusCode SGImplSvc::reinitialize() { - msg() << MSG::INFO << "Reinitializing " << name() + msg() << MSG::VERBOSE << "Reinitializing " << name() << " - package version " << PACKAGE_VERSION << endreq ; const bool FORCEREMOVE(true); clearStore(FORCEREMOVE).ignore(); @@ -558,6 +578,11 @@ void SGImplSvc::setStoreID(StoreID::type id) { store()->setStoreID(id); } +/// get store id from DataStore: +StoreID::type SGImplSvc::storeID() const +{ + return store()->storeID(); +} void SGImplSvc::keys(const CLID& id, std::vector<std::string>& vkeys, @@ -732,11 +757,18 @@ StatusCode SGImplSvc::addToStore (CLID id, SG::DataProxy* proxy) * @param obj The data object to store. * @param key The key as which it should be stored. * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. * * Full-blown record. @c obj should usually be something * deriving from @c SG::DataBucket. * * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. */ SG::DataProxy* SGImplSvc::recordObject (SG::DataObjectSharedPtr<DataObject> obj, const std::string& key, @@ -754,6 +786,25 @@ SG::DataProxy* SGImplSvc::recordObject (SG::DataObjectSharedPtr<DataObject> obj, if (returnExisting) { SG::DataProxy* proxy = this->proxy (obj->clID(), key); if (proxy) return proxy; + + // Look for the same object recorded under a different key. + proxy = this->proxy (raw_ptr); + if (proxy) { + // Make an alias. + if (addAlias (key, proxy).isFailure()) { + CLID clid = proxy->clID(); + std::string clidTypeName; + m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore(); + msg() << MSG::WARNING + << "SGImplSvc::recordObject: addAlias fails for object " + << clid << "[" << clidTypeName << "] " << proxy->name() + << " and new key " << key + << endreq; + + proxy = nullptr; + } + return proxy; + } } const bool resetOnly = true; @@ -1019,8 +1070,10 @@ SGImplSvc::record_impl( DataObject* pDObj, const std::string& key, << " already in store with key="<< dp->name() << ". Will not record a duplicate! " << endreq; - DataBucketBase* pDBB(dynamic_cast<DataBucketBase*>(pDObj)); - if (pDBB) pDBB->relinquish(); //don't own the data obj already recorded! + if (pDObj != dp->object()) { + DataBucketBase* pDBB(dynamic_cast<DataBucketBase*>(pDObj)); + pDBB->relinquish(); //don't own the data obj already recorded! + } this->recycle(pDObj); return nullptr; } diff --git a/Control/StoreGate/src/StoreGateSvc.cxx b/Control/StoreGate/src/StoreGateSvc.cxx index bc9d63bf6ba43dd4fedb3de72247e782ef2ee176..70473965c9a801b8bd5fd16ea0fc850e0fd07f0f 100644 --- a/Control/StoreGate/src/StoreGateSvc.cxx +++ b/Control/StoreGate/src/StoreGateSvc.cxx @@ -147,7 +147,7 @@ StatusCode StoreGateSvc::initialize() { if(!(Service::initialize()).isSuccess()) return StatusCode::FAILURE; MsgStream log( messageService(), name() ); - log << MSG::INFO << "Initializing " << name() + log << MSG::VERBOSE << "Initializing " << name() << " - package version " << PACKAGE_VERSION << endreq ; // lifted from AlwaysPrivateToolSvc (see Wim comment about lack of global jo svc accessor @@ -204,7 +204,7 @@ StatusCode StoreGateSvc::initialize() { /// Service start StatusCode StoreGateSvc::stop() { - msg() << MSG::INFO << "Stop " << name() << endreq; + msg() << MSG::VERBOSE << "Stop " << name() << endreq; //HACK ALERT: ID event store objects refer to det store objects //by setting an ad-hoc priority for event store(s) we make sure they are finalized and hence cleared first // see e.g. https://savannah.cern.ch/bugs/index.php?99993 @@ -213,7 +213,7 @@ StatusCode StoreGateSvc::stop() { if (!pISM) return StatusCode::FAILURE; pISM->setPriority(name(), pISM->getPriority(name())+1).ignore(); - msg() << MSG::INFO << "stop: setting service priority to " << pISM->getPriority(name()) + msg() << MSG::VERBOSE << "stop: setting service priority to " << pISM->getPriority(name()) << " so that event stores get finalized and cleared before other stores" <<endmsg; } return StatusCode::SUCCESS; @@ -234,7 +234,7 @@ StatusCode StoreGateSvc::finalize() { if(!(Service::finalize()).isSuccess()) return StatusCode::FAILURE; MsgStream log( messageService(), name() ); - log << MSG::INFO << "Finalizing " << name() + log << MSG::VERBOSE << "Finalizing " << name() << " - package version " << PACKAGE_VERSION << endreq ; if (m_defaultStore) { // m_defaultStore is not active, so ServiceManager won't finalize it! @@ -296,6 +296,8 @@ StatusCode StoreGateSvc::addToStore (CLID id, SG::DataProxy* proxy) * @param key The key as which it should be stored. * @param allowMods If false, the object will be recorded as const. * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. * * Full-blown record. @c obj should usually be something * deriving from @c SG::DataBucket. @@ -390,6 +392,11 @@ StoreGateSvc::setStoreID(StoreID::type id) { _SGVOIDCALL(setStoreID,(id)); } +StoreID::type +StoreGateSvc::storeID() const +{ + _SGXCALL(storeID,(),StoreID::UNKNOWN); +} void StoreGateSvc::keys(const CLID& id, std::vector<std::string>& vkeys, @@ -536,5 +543,10 @@ void StoreGateSvc::makeCurrent() _SGVOIDCALL (makeCurrent, ()); } +StatusCode StoreGateSvc::removeProxy(SG::DataProxy* proxy, const void* pTrans, + bool forceRemove) { + _SGXCALL(removeProxy, (proxy, pTrans, forceRemove), StatusCode::FAILURE); +} + #endif //ATLASHIVE diff --git a/Control/StoreGate/src/VarHandleKeyArrayProperty.cxx b/Control/StoreGate/src/VarHandleKeyArrayProperty.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c1996368821503aafd1b4e157e5f49b3446b6773 --- /dev/null +++ b/Control/StoreGate/src/VarHandleKeyArrayProperty.cxx @@ -0,0 +1,206 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// stl includes +#include <sstream> +#include <map> +#include <boost/tokenizer.hpp> + +// StoreGate includes +#include "StoreGate/VarHandleKeyArrayProperty.h" + +namespace Gaudi { + namespace Parsers { + + +/** + * @brief Gaudi function used to initialize a property from a string. + * @param v The object to initialize. + * @param s The string from which to initialize. + * + * Used during Gaudi property handling to set object @c v from the string @c s. + * Note that @c s is a representation of the property setting; thus, in the + * case of setting a property from a string, @c s will contain quote marks. + */ + StatusCode + GAUDI_API + parse(SG::VarHandleKeyArray& v, const std::string& s) + { + std::vector<std::string> vp; + StatusCode sc = Gaudi::Parsers::parse(vp, s); + + if (sc.isSuccess()) + sc = v.assign( vp ); + + return sc; + } + + } //> ns Parsers + + namespace Utils { + + +/** + * @brief Gaudi function used to convert a property to a string. + * @param v The object to convert. + * @param o Stream to which to do the conversion. + * + * Used during Gaudi property handling to get a string representation of @c v. + * Note that if the representation is a string, it should be surrounded + * by quote marks. + */ + std::ostream& + GAUDI_API + toStream(const SG::VarHandleKeyArray& v, std::ostream& o) + { + o << "[" << v.toString() << "]"; + return o; + } + + } //> ns Utils +} //> ns Gaudi + + +namespace SG { + + +/** + * @brief Constructor with parameters. + * @param name Name of the property. + * @param ref Object which this property is setting. + */ + VarHandleKeyArrayProperty::VarHandleKeyArrayProperty( const std::string& name, + SG::VarHandleKeyArray& ref ) + : Property( name, typeid( SG::VarHandleKeyArray ) ), + m_pValue( &ref ) + { +} + + +/** + * @brief Assignment operator. + * @param value Value from which to assign. + * + * Copy the value object which we control from another value object. + */ +VarHandleKeyArrayProperty& +VarHandleKeyArrayProperty::operator=( const SG::VarHandleKeyArray& value ) +{ + setValue( value ); + return *this; +} + + +/** + * @brief Return a new copy of this Property object. + * + * The new object will be associated with the _same_ value object + * as the original. + */ +VarHandleKeyArrayProperty* +VarHandleKeyArrayProperty::clone() const +{ + return new VarHandleKeyArrayProperty( *this ); +} + + +/** + * @brief Set the value of another Property. + * @param destination The Property whose value is changed. + * + * The value object of this Property is copied to that of @c destination + * by converting to a string and back again. Returns true on success, + * false on failure. + */ +bool +VarHandleKeyArrayProperty::load( Property& destination ) const +{ + return destination.assign( *this ); +} + + +/** + * @brief Set the value of this Property from another. + * @param destination The Property from which the value should be copied. + * + * The value object of this @c source is copied to that of this Property + * by converting to a string and back again. Returns true on success, + * false on failure. + */ +bool +VarHandleKeyArrayProperty::assign( const Property& source ) +{ + return fromString( source.toString() ).isSuccess(); +} + + +/** + * @brief Return a string representation of the value object. + */ +std::string +VarHandleKeyArrayProperty::toString( ) const +{ + useReadHandler(); + std::ostringstream o; + Gaudi::Utils::toStream(*m_pValue, o); + return o.str(); +} + + +/** + * @brief Write a string representation of the value object to a stream. + * @param out Stream to which to write. + */ +void +VarHandleKeyArrayProperty::toStream(std::ostream& out) const +{ + useReadHandler(); + out << this->toString(); +} + + +/** + * @brief Set this value object from a string. + * @param s String from which to initialize the value. + * + * Returns failure if the conversion does not succeed. + */ +StatusCode +VarHandleKeyArrayProperty::fromString(const std::string& s) +{ + if (!Gaudi::Parsers::parse(*m_pValue, s).isSuccess()) { + return StatusCode::FAILURE; + } + return useUpdateHandler() + ? StatusCode::SUCCESS + : StatusCode::FAILURE; +} + + +/** + * @brief Return the value object for this Property. + */ +const SG::VarHandleKeyArray& +VarHandleKeyArrayProperty::value() const +{ + useReadHandler(); + return *m_pValue; +} + + +/** + * @brief Set the value object for this Property. + * @param value Value from which to copy. + * + * Return true on success; false if the update handler failed. + */ +bool +VarHandleKeyArrayProperty::setValue( const SG::VarHandleKeyArray& value ) +{ + m_pValue->operator=(value); + return useUpdateHandler(); +} + + +} // namespace SG diff --git a/Control/StoreGate/test/SGtests.cxx b/Control/StoreGate/test/SGtests.cxx index e7fcfd043facde1fa0c822da1ce9e4c69dd79cd6..4013bbc93801afcaab183e702401f799a37f918e 100644 --- a/Control/StoreGate/test/SGtests.cxx +++ b/Control/StoreGate/test/SGtests.cxx @@ -50,10 +50,12 @@ using CxxUtils::make_unique; class Base {}; class Foo : public Base { public: + static std::vector<int> dtor_log; Foo() : m_i(0), m_d(0.0) {} Foo(int i) : m_i(i), m_d(0.0) {} int i() const { return m_i; } ~Foo() { + dtor_log.push_back (m_i); #ifdef MAKEITBOMB //int* ifg(0); //std::cout << *ifg << std::endl; @@ -64,6 +66,7 @@ private: int m_i; double m_d; }; +std::vector<int> Foo::dtor_log; class Bar : public Base {}; class NotThere {}; @@ -98,14 +101,16 @@ struct BX : public IAuxElement { int x; - BX(int the_x=0) : x(the_x), m_store(0) {} + BX(int the_x=0) : x(the_x), m_store(0), m_constStore(nullptr) {} bool hasStore() const { return m_store != 0; } void setStore (SG::IAuxStore* store) { m_store = store; } + void setStore (SG::IConstAuxStore* store) { m_constStore = store; } bool usingStandaloneStore() const { return hasStore(); } SG::IAuxStore* getStore() { return m_store; } SG::IAuxStore* m_store; + SG::IConstAuxStore* m_constStore; }; struct BBX : public IAuxElement @@ -131,9 +136,10 @@ CLASS_DEF( TestVector<BX> , 82735621, 1 ) CLASS_DEF( TestVector<BBX> , 125040193 , 1 ) class TestAuxStore - : public SG::IAuxStore + : public SG::IAuxStore, public ILockable { public: + TestAuxStore() : m_locked(false) {} virtual const void* getData (SG::auxid_t /*auxid*/) const { return 0; } virtual const SG::auxid_set_t& getAuxIDs() const { return m_set; } virtual void* getData (auxid_t /*auxid*/, size_t /*size*/, size_t /*capacity*/) { return 0; } @@ -142,9 +148,12 @@ public: virtual void reserve (size_t /*sz*/) {} virtual void shift (size_t /*pos*/, ptrdiff_t /*offs*/) {} virtual void* getDecoration (auxid_t /*auxid*/, size_t /*size*/, size_t /*capacity*/) { std::abort(); } - virtual void lock() { std::abort(); } + virtual void lock() { m_locked = true; } virtual void clearDecorations() { std::abort(); } virtual size_t size() const { std::abort(); } + + bool m_locked; + private: SG::auxid_set_t m_set; }; @@ -1005,6 +1014,82 @@ namespace Athena_test { } + void testRecordObject(StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test testRecordObject BEGINS ***" << endl; + Foo::dtor_log.clear(); + + SG::DataObjectSharedPtr<DataObject> obj101 = + SG::asStorable (CxxUtils::make_unique<Foo> (101)); + SG::DataProxy* proxy101 = rSG.recordObject (obj101, "obj101", false, false); + assert (proxy101->name() == "obj101"); + assert (proxy101->object() == obj101.get()); + assert (obj101->refCount() == 2); + assert (proxy101->refCount() == 1); + assert (proxy101->isConst()); + + SG::DataObjectSharedPtr<DataObject> obj102 = + SG::asStorable (CxxUtils::make_unique<Foo> (102)); + SG::DataProxy* proxy102 = rSG.recordObject (obj102, "obj102", true, false); + assert (proxy102->name() == "obj102"); + assert (proxy102->object() == obj102.get()); + assert (obj102->refCount() == 2); + assert (!proxy102->isConst()); + + assert (Foo::dtor_log.empty()); + + std::cout << ">>> test duplicate record1\n"; + SG::DataObjectSharedPtr<DataObject> obj103 = + SG::asStorable (CxxUtils::make_unique<Foo> (103)); + SG::DataProxy* proxy103 = rSG.recordObject (obj103, "obj101", false, false); + assert (proxy103 == nullptr); + assert (obj103->refCount() == 2); // Held by m_trash + std::cout << "<<< test duplicate record1\n"; + + SG::DataObjectSharedPtr<DataObject> obj104= + SG::asStorable (CxxUtils::make_unique<Foo> (104)); + SG::DataProxy* proxy104 = rSG.recordObject (obj104, "obj101", false, true); + assert (proxy104 == proxy101); + assert (obj104->refCount() == 1); + + std::cout << ">>> test duplicate record2\n"; + SG::DataProxy* proxy999 = rSG.recordObject (obj101, "obj999", false, false); + assert (proxy999 == nullptr); + assert (obj101->refCount() == 3); // Held by m_trash + std::cout << "<<< test duplicate record2\n"; + + assert (proxy101->refCount() == 1); + proxy999 = rSG.recordObject (obj101, "obj999", false, true); + assert (proxy999 == proxy101); + assert (proxy101->refCount() == 2); + assert (obj101->refCount() == 3); + + rSG.clearStore(); + assert (obj101->refCount() == 1); + assert (obj102->refCount() == 1); + assert (obj103->refCount() == 1); + assert (obj104->refCount() == 1); + + cout << "\n*** StoreGateSvcClient_test testRecordObject OK ***" << endl; + } + + + void testWriteAux(StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test testWriteAux BEGINS ***" << endl; + + TestAuxStore* paux = nullptr; + { + SG::WriteHandle<BX> h ("testWriteAux", rSG.name()); + auto obj = CxxUtils::make_unique<BX> (10); + auto objAux = CxxUtils::make_unique<TestAuxStore>(); + paux = objAux.get(); + assert (h.record (std::move(obj), std::move(objAux)).isSuccess()); + assert (!paux->m_locked); + } + cout << "\n*** StoreGateSvcClient_test testWriteAux OK ***" << endl; + } + } //end namespace #endif /*NOGAUDI*/ diff --git a/Control/StoreGate/test/WriteHandle_test.cxx b/Control/StoreGate/test/WriteHandle_test.cxx index 45deff97ca9bf5ccfbd8e0d873f7ebe6e130fe87..c49555a82074d8f3e7b9a71fae016d13a5c5fe02 100644 --- a/Control/StoreGate/test/WriteHandle_test.cxx +++ b/Control/StoreGate/test/WriteHandle_test.cxx @@ -30,17 +30,18 @@ class MyObjAux - : public SG::IConstAuxStore + : public SG::IConstAuxStore, public ILockable { public: MyObjAux(int x=0) : x(x) {} ~MyObjAux() { deleted.push_back (x); } int x; + bool m_locked = false; virtual const void* getData (SG::auxid_t /*auxid*/) const override { return 0; } virtual void* getDecoration (SG::auxid_t /*auxid*/, size_t /*size*/, size_t /*capacity*/) override { return 0; } virtual const SG::auxid_set_t& getAuxIDs() const override { std::abort(); } - virtual void lock() override { } + virtual void lock() override { m_locked = true; } virtual void clearDecorations() override { } virtual size_t size() const override { return 0; } @@ -54,6 +55,7 @@ class MyObj public: MyObj(int x=0) : x(x) {} ~MyObj() { deleted.push_back (x); } + SG::IAuxStore* getStore() const { return nullptr; } void setStore (SG::IConstAuxStore* store) {aux = dynamic_cast<MyObjAux*>(store); } int x; MyObjAux* aux {nullptr}; @@ -340,7 +342,7 @@ void test5() assert (h4a.isValid()); assert (h4a.isInitialized()); assert (h4a->x == 133); - assert (h4a.isConst()); + assert (!h4a.isConst()); MyObj::deleted.clear(); MyObjAux::deleted.clear(); @@ -365,6 +367,17 @@ void test5() assert (h6->aux == nullptr); assert (MyObj::deleted == std::vector<int>{}); assert (MyObjAux::deleted == std::vector<int>{135}); + + MyObjAux* paux = nullptr; + { + SG::WriteHandle<MyObj> h7 ("foo7", "FooSvc"); + assert (h7.setStore (&testStore).isSuccess()); + auto ptrs7 = makeWithAux(30); + paux = ptrs7.second.get(); + assert (h7.record (std::move(ptrs7.first), std::move(ptrs7.second)).isSuccess()); + assert (!paux->m_locked); + } + assert (paux->m_locked); }