ATLAS Offline Software
Loading...
Searching...
No Matches
Control/SGTools/src/DataStore.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "SGTools/DataStore.h"
6#include "SGTools/DataProxy.h"
10#include "GaudiKernel/ClassID.h"
11#include "GaudiKernel/MsgStream.h"
12#include "GaudiKernel/Bootstrap.h"
13#include "GaudiKernel/ISvcLocator.h"
16
17using namespace std;
18using SG::DataStore;
19using SG::DataProxy;
20using SG::ProxyMap;
23
24
30 : m_pool (pool),
31 m_storeMap(),
32 m_keyMap(KeyMap_t::Updater_t()),
33 m_storeID(StoreID::UNKNOWN), m_t2p(),
35{
36 setSvcLoc().ignore();
37}
38
39//Destructor
41{
42 clearStore(false, true, nullptr);
43}
44
46 StatusCode sc(StatusCode::FAILURE);
47 m_pSvcLoc = Gaudi::svcLocator( );
48 if (!m_pSvcLoc) std::cout<<"DataStore::setSvcLoc: WARNING svcLocator not found! "<<std::endl;
49 return sc;
50}
51
53 if (!m_pSGAudSvc) {
54 //try once to get the service
55 if (!m_noAudSvc) {
56 const bool DONOTCREATE(false);
57 m_pSGAudSvc = m_pSvcLoc->service("SGAudSvc", DONOTCREATE);
58 m_noAudSvc = not m_pSGAudSvc.isValid();
59 }
60 }
61 return;
62}
63
64
66void DataStore::clearStore(bool force, bool hard, MsgStream* /*pmlog*/)
67{
70
78 std::unordered_set<DataProxy*> removed;
79
85 for (size_t i = 0; i < m_proxies.size(); ) {
86 SG::DataProxy* dp = m_proxies[i];
87 if (dp->requestRelease (force, hard)) [[unlikely]] {
88 removed.insert (dp);
89 if (removeProxyImpl (dp, i).isFailure()) {
90 ++i;
91 }
92 }
93 else {
94 ++i;
95 }
96 }
97
98 if (!removed.empty()) {
99 KeyMap_t newMap (KeyMap_t::Updater_t(), m_keyMap.capacity());
100 {
101 auto lock = newMap.lock();
102 auto ctx = KeyMap_t::Updater_t::defaultContext();
103 for (auto p : m_keyMap) {
104 if (removed.count (p.second) == 0) {
105 newMap.emplace (lock, p.first, p.second, ctx);
106 }
107 }
108 }
109 m_keyMap.swap (newMap);
110 }
111
112 // clear T2PMap
113 m_t2p.clear();
114}
115
117// access all the keys associated with an object:
118//
119void DataStore::keys(const CLID& id, std::vector<std::string>& vkeys,
120 bool includeAlias, bool onlyValid)
121{
122 vkeys.clear();
123 for (const ProxyMap::value_type& p : m_storeMap[id]) {
124 bool includeProxy(true);
125 if (onlyValid) includeProxy=p.second->isValid();
126 if (includeAlias) {
127 if (includeProxy) vkeys.push_back(p.first);
128 }
129 else {
130 if (p.first == p.second->name() && includeProxy)
131 vkeys.push_back(p.first);
132 }
133 }
134}
135
137//---------------------------------------------------------------//
138// record the proxy in StoreGate
139StatusCode
141{
142 if (!dp) {
143 return StatusCode::FAILURE;
144 }
145
148 bool primary = false;
149 if (dp->store() == nullptr) {
150 m_proxies.push_back (dp);
151 primary = true;
152 }
153
154 if (id == 0 && dp->clID() == 0 && dp->sgkey() != 0) {
155 // Handle a dummied proxy.
156 m_keyMap.emplace (dp->sgkey(), dp);
157 }
158 else {
159 ProxyMap& pmap = m_storeMap[id];
160
161 // Set the primary key.
162 sgkey_t primary_sgkey = m_pool.stringToKey (dp->name(), dp->clID());
163 sgkey_t sgkey = primary_sgkey;
164 if (id != dp->clID()) {
165 sgkey = m_pool.stringToKey (dp->name(), id);
166 }
167 if (dp->sgkey() == 0) {
168 dp->setSGKey (sgkey);
169 }
170
171 if (!m_keyMap.emplace (sgkey, dp).second) {
172 if (primary) {
173 m_proxies.pop_back();
174 }
175 return StatusCode::FAILURE;
176 }
177
178 pmap.insert(ProxyMap::value_type(dp->name(), dp));
179 }
180
181 // Note : No checking if proxy already exists in store because it
182 // is already checked in StoreGateSvc.
183 // if (pmap.find(dp->name()) == pmap.end()) {
184 dp->addRef(); // The store now owns this
185 dp->setT2p(&m_t2p);
186 dp->setStore(&m_pool);
187
188 return StatusCode::SUCCESS;
189}
190
191
193//---------------------------------------------------------------//
194// if Proxy is a resettable proxy only then reset it, otherwise
195// delete it and remove from proxy map.
196StatusCode
197DataStore::removeProxy(DataProxy* proxy, bool forceRemove, bool hard)
198{
199 if (!proxy) {
200 return StatusCode::FAILURE;
201 }
202
203 if (!forceRemove && proxy->isResetOnly()) {
204 // A reset-only proxy. Don't remove it.
205 proxy->reset (hard);
206 return StatusCode::SUCCESS;
207 }
208
209 // First remove from m_keyMap.
210 // We may fail to find the entry if this is a key that has been versioned.
211 // E.g., we add aVersObj. Call this DP1.
212 // Then we add a new version of it. Call this DP2.
213 // The version logic will add the alias ';00;aVersObj' to DP1.
214 // It will also then add the alias `aVersObj' to DP2.
215 // This will overwrite the entries for DP1 in pmap and m_keyMap.
216 // If we then clear and DP2 is removed first, then the m_keyMap entry
217 // for DP1's primary key will be gone.
218 // FIXME: Should just remove the versioned key code ... it's anyway
219 // not compatible with MT.
220 removeFromKeyMap (proxy).ignore();
221
222 // Then remove from the m_storeMap and release the proxy.
223 auto it = std::find (m_proxies.begin(), m_proxies.end(), proxy);
224 if (it == m_proxies.end()) {
225 return StatusCode::FAILURE;
226 }
227 return removeProxyImpl (proxy, it - m_proxies.begin());
228}
229
230
236{
237 SG::DataProxy::AliasCont_t alias_set = proxy->alias();
238 std::string name = proxy->name();
239
240 for (CLID symclid : proxy->transientID())
241 {
242 sgkey_t sgkey = m_pool.stringToKey (name, symclid);
243 m_keyMap.erase (sgkey);
244
245 for (const std::string& alias : alias_set) {
246 m_keyMap.erase (m_pool.stringToKey (alias, symclid));
247 }
248 }
249
250 return StatusCode::SUCCESS;
251}
252
253
262StatusCode
264{
265 proxy->setStore (nullptr);
266
267 std::string name = proxy->name();
268 CLID clid = proxy->clID();
269 SG::DataProxy::AliasCont_t alias_set = proxy->alias();
270
271 // nb. This has to be here, not just before the loop below,
272 // as the proxy may be deleted in the meantime.
273 SG::DataProxy::CLIDCont_t clids = proxy->transientID();
274
275 StoreIterator storeIter = m_storeMap.find(clid);
276 if (storeIter != m_storeMap.end()) {
277 ProxyMap& pmap = storeIter->second;
278
279 // first remove the alias key:
280 for (const std::string& alias : alias_set) {
281 if (1 == pmap.erase(alias)) proxy->release();
282 }
283
284 // Remove primary entry.
285 if (1 == pmap.erase(name)) {
286 proxy->release();
287 }
288 }
289 else {
290 // A dummy proxy.
291 proxy->release();
292 }
293
294 // Remove all symlinks too.
295 for (CLID symclid : clids)
296 {
297 if (clid == symclid) continue;
298 storeIter = m_storeMap.find(symclid);
299 if (storeIter != m_storeMap.end()) {
300 ProxyMap& pmap = storeIter->second;
301 SG::ProxyIterator it = pmap.find (name);
302 if (it != pmap.end() && it->second == proxy) {
303 storeIter->second.erase (it);
304 proxy->release();
305 }
306
307 for (const std::string& alias : alias_set) {
308 if (1 == pmap.erase (alias)) proxy->release();
309 }
310 }
311 } //symlinks loop
312
313 if (index != -1 && !m_proxies.empty()) {
314 // Remove the proxy from m_proxies. If it's not at the end, then
315 // move the proxy at the end to this proxy's index (and update the
316 // index for the other proxy stored in m_keyMap).
317 if (index != (int)m_proxies.size() - 1) {
318 m_proxies[index] = m_proxies.back();
319 }
320 m_proxies.pop_back();
321 }
322
323 return StatusCode::SUCCESS;
324}
325
327//---------------------------------------------------------------//
328// record the symlink in StoreGate
329StatusCode
331{
332 // Make sure the symlink doesn't already exist.
333 DataProxy* exist = proxy_exact (linkid, dp->name());
334 if (exist == dp) {
335 // Entry already exists pointing at the desired proxy.
336 return StatusCode::SUCCESS;
337 }
338 else if (!exist) {
339 dp->setTransientID(linkid);
340 return addToStore(linkid, dp);
341 }
342
343 // Already an existing proxy.
344 if (exist->isValidObject()) {
345 // And it's set to something. Ok if it's the same DataObject.
346 // Otherwise fail.
347 if (exist->object() == dp->object()) {
348 dp->setTransientID(linkid);
349 return StatusCode::SUCCESS;
350 }
351 return StatusCode::FAILURE;
352 }
353 if (!dp->object()) {
354 return StatusCode::FAILURE;
355 }
356 if (exist->loader()) {
357 return StatusCode::FAILURE;
358 }
359
360 // The existing proxy is not set to anything, and it doesn't have a loader.
361 // It may have been created by a forward-declared link to a base class.
362 // In that case, set the existing proxy to also point at the same DataObject.
363 const SG::BaseInfoBase* bib = SG::BaseInfoBase::find (dp->clID());
364 if (bib && bib->is_base (exist->clID())) {
365 dp->setTransientID(linkid);
366 exist->setObject (dp->object(), false);
367 return StatusCode::SUCCESS;
368 }
369
370 // Entry already exists pointing at another proxy.
371 // Don't change the existing entry.
372 return StatusCode::FAILURE;
373}
374//---------------------------------------------------------------//
375// record the alias in StoreGate
376StatusCode
377DataStore::addAlias(const std::string& aliasKey, DataProxy* dp)
378{
379 for (CLID clid : dp->transientID()) {
380 // locate proxy map and add alias to proxymap
381 ProxyMap& pmap = m_storeMap[clid];
382
383 // check if another proxy for the same type caries the same alias.
384 // if yes, then remove that alias from that proxy and establish the
385 // alias in the new proxy.
386 // pmap.insert will overwrite, associate alias with new proxy.
387 ConstProxyIterator p_iter = pmap.find(aliasKey);
388 if (p_iter != pmap.end() && dp->clID() == p_iter->second->clID()) {
389 if (dp->name() == p_iter->second->name()) return StatusCode::SUCCESS;
390 p_iter->second->removeAlias(aliasKey);
391 p_iter->second->release();
392 }
393 dp->addRef();
394 pmap[aliasKey] = dp;
395 m_keyMap.emplace (m_pool.stringToKey (aliasKey, clid), dp);
396 }
397
398 // set alias in proxy
399 dp->setAlias(aliasKey);
400
401 return StatusCode::SUCCESS;
402}
403//---------------------------------------------------------------//
404// Count instances of TYPE in store
405int DataStore::typeCount(const CLID& id) const
406{
407 ConstStoreIterator storeIter = m_storeMap.find(id);
408 if (storeIter == m_storeMap.end()) return 0;
409 return (storeIter->second).size();
410}
411
412//---------------------------------------------------------------//
413// Return proxy for a given Transient Address
415{
416 return proxy(tAddr->clID(), tAddr->name());
417}
418
419// Return proxy for a given Transient ID (TYPE and KEY)
420DataProxy* DataStore::proxy(const CLID& id, const std::string& key) const
421{
422
423 // The logic here: if a key is specified, we locate it.
424 // If we don't find it and the default key (DEFAULTKEY) is specified,
425 // then we return any existing proxy for this type as long as there
426 // is exactly one, not counting aliases. More than one would be ambiguous
427
428 ConstStoreIterator siter = m_storeMap.find(id);
429 DataProxy *p(0);
430 if (siter != m_storeMap.end())
431 {
432 const ProxyMap& pmap = siter->second;
433 ConstProxyIterator p_iter = pmap.find(key);
434 if (p_iter != pmap.end()) {
435 p=p_iter->second;
436
437 } else if (key == SG::DEFAULTKEY && !pmap.empty()) {
438 // we did not find the object using key.
439 // Now check for default object.
440 // If there are multiple entries, they must all be
441 // referring to the same proxy (aliases).
442 for (const auto& ent : pmap) {
443 if (!p) {
444 p = ent.second;
445 }
446 else if (p != ent.second) {
447 p = nullptr;
448 break;
449 }
450 }
451
452 // If that didn't work, try it again, considering only objects that
453 // are exactly the type being requested.
454 if (!p) {
455 for (const auto& ent : pmap) {
456 if (ent.second->clID() == id) {
457 if (!p) {
458 p = ent.second;
459 }
460 else if (p != ent.second) {
461 p = nullptr;
462 break;
463 }
464 }
465 }
466 }
467 }
468 else {
469 // Ok since access to DataStore is serialized by StoreGate.
470 DataStore* nc_store ATLAS_THREAD_SAFE = const_cast<DataStore*> (this);
471 p = nc_store->findDummy (id, key);
472 }
473 }
474 else {
475 // Ok since access to DataStore is serialized by StoreGate.
476 DataStore* nc_store ATLAS_THREAD_SAFE = const_cast<DataStore*> (this);
477 p = nc_store->findDummy (id, key);
478 }
479
480 if (p && m_pSGAudSvc)
481 m_pSGAudSvc->SGAudit(p->name(), id, 0, m_storeID);
482
483 return p;
484}
485
486
505DataProxy* DataStore::findDummy (CLID id, const std::string& key)
506{
507 sgkey_t sgkey = m_pool.stringToKey (key, id);
508 DataProxy* p = proxy_exact (sgkey);
509 if (p) {
510 p->setID (id, key);
511 ProxyMap& pmap = m_storeMap[id];
512 if (!pmap.insert(ProxyMap::value_type(key, p)).second) {
513 // This shouldn't happen.
514 DataProxy* p2 = pmap[key];
515 throw SG::ExcProxyCollision (id, key, p2->clID(), p2->name());
516 }
517 }
518 return p;
519}
520
521
525{
526 if (m_pSGAudSvc) {
527 CLID clid;
528 const std::string* strkey = m_pool.keyToString (sgkey, clid);
529 if (strkey)
530 m_pSGAudSvc->SGAudit(*strkey, clid, 0, m_storeID);
531 }
532 KeyMap_t::const_iterator i = m_keyMap.find (sgkey);
533 if (i != m_keyMap.end())
534 return i->second;
535 return 0;
536}
537
538
544 std::recursive_mutex& mutex) const
545{
546 if (m_pSGAudSvc) {
547 std::unique_lock lock (mutex);
548 CLID clid;
549 const std::string* strkey = m_pool.keyToString (sgkey, clid);
550 if (strkey)
551 m_pSGAudSvc->SGAudit(*strkey, clid, 0, m_storeID);
552 }
553 KeyMap_t::const_iterator i = m_keyMap.find (sgkey);
554 if (i != m_keyMap.end())
555 return i->second;
556 return 0;
557}
558
559
563 const std::string& key) const
564{
565 // Suppress warning here about calling to a nonconst method
566 // of m_pool. Ok since all callers here must own the store lock.
567 IProxyDict& pool_nc ATLAS_THREAD_SAFE = m_pool;
568 return proxy_exact (pool_nc.stringToKey (key, id));
569}
570
571
572//---------------------------------------------------------------//
573// Return an iterator over proxies for a given CLID:
575 ConstProxyIterator& pe) const
576{
577 static const ProxyMap emptyMap;
578 StatusCode sc(StatusCode::FAILURE);
579
580 ConstStoreIterator storeIter = m_storeMap.find(id);
581 if (storeIter != m_storeMap.end())
582 {
583 const ProxyMap& pmap = storeIter->second;
584 pf = pmap.begin();
585 pe = pmap.end();
586 if (pmap.size() > 0) sc = StatusCode::SUCCESS;
587 } else {
588 //keep valgrind happy
589 pf = emptyMap.end();
590 pe = emptyMap.end();
591 }
592 return sc;
593}
594//---------------------------------------------------------------//
595// Return an iterator over the Store Map
596StatusCode DataStore::tRange(ConstStoreIterator& tf,
597 ConstStoreIterator& te) const
598{
599 tf = m_storeMap.begin();
600 te = m_storeMap.end();
601 return StatusCode::SUCCESS;
602}
603//---------------------------------------------------------------//
604// locate Persistent Representation of a Transient Object
605//
606DataProxy* DataStore::locatePersistent(const void* const pTransient) const
607{
608 return m_t2p.locatePersistent(pTransient);
609}
610
613DataStore::t2pRegister(const void* const pTrans, DataProxy* const pPers)
614{
615 std::string name=pPers->name();
616 int i=name.find('/', 0);
617 name=name.erase(0,i+1);
618
619 if (doAudit()) m_pSGAudSvc->SGAudit(name, pPers->clID(), 1, m_storeID);
620
621 return (m_t2p.t2pRegister(pTrans, pPers)) ?
622 StatusCode::SUCCESS :
623 StatusCode::FAILURE;
624}
625
626
627const std::vector<DataProxy*>& DataStore::proxies() const
628{
629 return m_proxies;
630}
631
A set of pointers, alowing concurrent, lockless reads.
Exceptions that can be thrown by SGTools.
uint32_t CLID
The Class ID type.
Abstract interface for looking up strings/CLIDs in a pool.
static Double_t sc
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
DataStore(IProxyDict &pool)
Constructor.
virtual sgkey_t stringToKey(const std::string &str, CLID clid)=0
Find the key for a string/CLID pair.
The non-template portion of the BaseInfo implementation.
static const BaseInfoBase * find(CLID clid)
Find the BaseInfoBase instance for clid.
Definition BaseInfo.cxx:570
bool is_base(CLID clid) const
Return true if clid is the ID of a class that is known to be a base of T.
Definition BaseInfo.cxx:344
CLID clID() const
Retrieve clid.
virtual const name_type & name() const override final
Retrieve data object key == string.
std::vector< std::string > AliasCont_t
Definition DataProxy.h:55
TransientAddress::TransientClidSet CLIDCont_t
Definition DataProxy.h:54
Hold DataProxy instances associated with a store.
ConcurrentSGKeyMap< DataProxy * > KeyMap_t
Map of hashed sgkey -> DataProxy.
virtual StatusCode addToStore(const CLID &id, DataProxy *proxy) override
add proxy to store.
StatusCode pRange(const CLID &id, SG::ConstProxyIterator &f, SG::ConstProxyIterator &e) const
Return an iterator over proxy for a given CLID:
StatusCode removeFromKeyMap(DataProxy *proxy)
Look for (and convert) a matching dummy proxy.
DataStore(IProxyDict &pool)
Constructor.
int typeCount(const CLID &id) const
Count number of object of a given type in store.
DataProxy * locatePersistent(const void *const pTransient) const
locate the persistent (proxy) for a given T* (void*):
virtual StatusCode addAlias(const std::string &aliasKey, DataProxy *proxy) override
add alias to store
std::vector< DataProxy * > m_proxies
All proxies managed by this store.
IProxyDict & m_pool
The string pool associated with this store.
StatusCode addSymLink(const CLID &linkid, DataProxy *proxy)
add symlink to store:
void keys(const CLID &id, std::vector< std::string > &vkeys, bool includeAlias, bool onlyValid)
StoreMap::const_iterator ConstStoreIterator
StoreMap m_storeMap
Maps locating proxies by clid/key.
virtual SG::DataProxy * proxy_exact(sgkey_t sgkey) const override
get proxy with given key.
virtual DataProxy * proxy(const TransientAddress *tAddr) const override
return proxy for a given type/key pair if key is empty returns the default proxy (currently last regi...
StatusCode removeProxy(DataProxy *proxy, bool forceRemove, bool hard)
remove proxy from store, unless proxy is reset only.
StatusCode t2pRegister(const void *const pTrans, DataProxy *const pPers)
methods to query the T2PMap:
StatusCode removeProxyImpl(DataProxy *proxy, int index)
Helper for removing a proxy.
SG::DataProxy * proxy_exact_unlocked(sgkey_t sgkey, std::recursive_mutex &mutex) const
Like proxy_exact, but intended to be called without holding the store lock.
const std::vector< DataProxy * > & proxies() const
All proxies managed by this store.
StatusCode tRange(ConstStoreIterator &f, ConstStoreIterator &e) const
Return an iterator over the StoreMap:
void clearStore(bool force, bool hard, MsgStream *pmlog)
If HARD is true, then the bound objects should also clear any data that depends on the identity of th...
Exception — Proxy collision for clid/key.
CLID clID() const
Retrieve string key:
const std::string & name() const
Get the primary (hashed) SG key.
defines an enum used by address providers to decide what kind of StoreGateSvc they are providing addr...
Definition StoreID.h:18
::StatusCode StatusCode
StatusCode definition for legacy code.
std::map< std::string, DataProxy * > ProxyMap
Definition ProxyMap.h:22
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition sgkey_t.h:32
const std::string DEFAULTKEY
Definition DefaultKey.h:12
ProxyMap::const_iterator ConstProxyIterator
Definition ProxyMap.h:24
ProxyMap::iterator ProxyIterator
Definition ProxyMap.h:23
virtual void lock() override
Lock the container.
Definition index.py:1
Framework include files.
Definition libname.h:15
STL namespace.
#define unlikely(x)