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