ATLAS Offline Software
Loading...
Searching...
No Matches
SGImplSvc.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#undef DEBUG_SGIMPL
6
7#include <algorithm>
8#include <cassert>
9#include <cstdio>
10#include <iostream>
11#include <functional>
12#include <format>
13#include <string>
14#include <unordered_map>
15
16#include <sstream>
17#include <fstream>
18#include <iomanip>
19
28#include "GaudiKernel/IClassIDSvc.h"
29#include "GaudiKernel/IHistorySvc.h"
30#include "GaudiKernel/ISvcLocator.h"
31#include "GaudiKernel/IConversionSvc.h"
32#include "GaudiKernel/Incident.h"
33#include "GaudiKernel/IOpaqueAddress.h"
34#include "GaudiKernel/MsgStream.h"
35#include "GaudiKernel/StatusCode.h"
36#include "GaudiKernel/DataHistory.h"
39#include "SGTools/DataProxy.h"
40#include "SGTools/DataStore.h"
41#include "SGTools/StringPool.h"
48
49// StoreGateSvc. must come before SGImplSvc.h
52#include "SGTools/DataStore.h"
53
54using std::setw;
55using std::hex;
56using std::dec;
57using std::endl;
58using std::ends;
59using std::pair;
60using std::string;
61using std::vector;
62
63using SG::DataProxy;
64using SG::DataStore;
66
67// Helpers for debug formatting
68// std::print implementation to be replaced when C++ 23 is available
69namespace dbg {
70template <class... Args> void print(std::FILE* stream, std::format_string<Args...> fmt, Args&&... args) {
71 std::fputs(std::format(fmt, std::forward<Args>(args)...), stream);
72}
73
74template <class T> void* ptr(T* p) { return static_cast<void*>(p); }
75}
76
78// Remapping implementation.
79
80
81namespace SG {
82
83
95
96
97} // namespace SG
98
99
102SGImplSvc::SGImplSvc(const string& name,ISvcLocator* svc)
103 : base_class(name, svc),
104 m_pCLIDSvc("ClassIDSvc", name),
105 m_pDataLoader("EventPersistencySvc", name),
106 m_pPPSHandle("ProxyProviderSvc", name),
107 m_pPPS(nullptr),
108 m_pHistorySvc("HistorySvc", name),
109 m_pStore(new DataStore(*this)),
110 m_pIncSvc("IncidentSvc", name),
111 m_DumpStore(false),
112 m_ActivateHistory(false),
113 m_DumpArena(false),
114 m_pIOVSvc("IOVSvc", name),
115 m_storeLoaded(false),
116 m_remap_impl (new SG::RemapImpl),
117 m_arena (name),
118 m_slotNumber(-1),
119 m_numSlots(1)
120{
121 //our properties
122 declareProperty("ProxyProviderSvc", m_pPPSHandle);
123 declareProperty("Dump", m_DumpStore);
124 declareProperty("ActivateHistory", m_ActivateHistory);
125 declareProperty("DumpArena", m_DumpArena);
126 //StoreGateSvc properties
127 declareProperty("IncidentSvc", m_pIncSvc);
128 //add handler for Service base class property
129 m_outputLevel.declareUpdateHandler(&SGImplSvc::msg_update_handler, this);
130
132 header->addArena (&m_arena);
133}
134
135
139 header->delArena (&m_arena);
140
141 delete m_pStore;
142 delete m_remap_impl;
143}
144
148
149 verbose() << "Initializing " << name() << endmsg;
150
151 CHECK( Service::initialize() );
152
153 if (!m_pStore)
154 m_pStore = new DataStore (*this);
155 if (!m_remap_impl)
157
158 //properties accessible from now on
159
161 // If this is the default event store (StoreGateSvc), then declare
162 // our arena as the default for memory allocations.
163 if (this->storeID() == StoreID::EVENT_STORE) {
164 m_arena.makeCurrent();
166 }
167 // set up the incident service:
168 if (!(m_pIncSvc.retrieve()).isSuccess()) {
169 error() << "Could not locate IncidentSvc "
170 << endmsg;
171 return StatusCode::FAILURE;
172 }
173
174 // We explicitly do not retrieve m_pIOVSvc and rely on retrieval
175 // on first use to avoid an initialization loop here.
176
177 CHECK( m_pDataLoader.retrieve() );
178 CHECK( m_pCLIDSvc.retrieve() );
179
180 if (!m_pPPSHandle.empty()) {
181 CHECK( m_pPPSHandle.retrieve() );
183 }
184
185 if ( m_pPPS && (m_pPPS->preLoadProxies(*m_pStore)).isFailure() )
186 {
187 SG_MSG_DEBUG(" Failed to preLoad proxies");
188 return StatusCode::FAILURE;
189 }
190
191 // Get hold of History Service
192 if (m_ActivateHistory) {
193 CHECK( m_pHistorySvc.retrieve() );
194 }
195
196 return StatusCode::SUCCESS;
197}
198
199StatusCode SGImplSvc::start() {
200
201 verbose() << "Start " << name() << endmsg;
202 /*
203 // This will need regFcn clients to be updated first.
204 if ( 0 == m_pPPS || (m_pPPS->preLoadProxies(*m_pStore)).isFailure() ) {
205 debug() << " Failed to preLoad proxies"
206 << endmsg;
207 return StatusCode::FAILURE;
208 }
209 */
210
211 return StatusCode::SUCCESS;
212}
213
214StatusCode SGImplSvc::stop() {
215
216 verbose() << "Stop " << name() << endmsg;
217 //HACK ALERT: ID event store objects refer to det store objects
218 //by setting an ad-hoc priority for event store(s) we make sure they are finalized and hence cleared first
219 // see e.g. https://savannah.cern.ch/bugs/index.php?99993
220 if (store()->storeID() == StoreID::EVENT_STORE) {
221 ISvcManager* pISM(dynamic_cast<ISvcManager*>(serviceLocator().get()));
222 if (!pISM)
223 return StatusCode::FAILURE;
224 pISM->setPriority(name(), pISM->getPriority(name())+1).ignore();
225 verbose() << "stop: setting service priority to " << pISM->getPriority(name())
226 << " so that event stores get finalized and cleared before other stores" <<endmsg;
227 }
228 return StatusCode::SUCCESS;
229}
230
232void SGImplSvc::handle(const Incident &inc) {
233
234 if (inc.type() == "EndEvent") {
235 if (m_DumpStore) {
236 SG_MSG_DEBUG("Dumping StoreGate Contents");
237 info() << '\n' << dump() << endl
238 << endmsg;
239 }
240 }
241}
242
244 lock_t lock (m_mutex);
245 StatusCode sc(StatusCode::SUCCESS);
246 //FIXME this should probably be dealt with by the providers
247 if (0 != m_pPPS && !m_storeLoaded) {
248 m_storeLoaded = true;
249 sc=m_pPPS->loadProxies(*m_pStore);
250#ifdef DEBUG_SGIMPL
251 dbg::print(stderr, "SGImplSvc::loadEventProxies() LOADED PROXIES on {}\n", name());
252 }
253 else {
254 dbg::print(stderr, "SGImplSvc::loadEventProxies() PROXIES ALREADY LOADED on {}\n", name());
255#endif
256 }
257 return sc;
258}
259
261// Create a key for a type (used if the client has not specified a key)
262string SGImplSvc::createKey(const CLID& id)
263{
264 return std::to_string(m_pStore->typeCount(id) + 1);
265}
266
267// clear store
268StatusCode SGImplSvc::clearStore(bool forceRemove)
269{
270#ifdef DEBUG_SGIMPL
271 dbg::print(stderr, "SGImplSvc::clearStore(forceRemove={}) on {}\n", forceRemove, name());
272#endif
273 {
274 if (m_DumpArena) {
275 std::ostringstream s;
276 m_arena.report(s);
277 info() << "Report for Arena: " << m_arena.name() << '\n'
278 << s.str() << endmsg;
279 }
280 }
281 {
282 lock_t lock (m_mutex);
283 emptyTrash();
284 for (auto& p : m_newBoundHandles)
285 p.second.clear();
286 assert(m_pStore);
287 debug() << "Clearing store with forceRemove="
288 << forceRemove << endmsg;
289 bool hard_reset = (m_numSlots > 1);
290 m_pStore->clearStore(forceRemove, hard_reset, &msgStream(MSG::DEBUG));
291 m_storeLoaded=false; //FIXME hack needed by loadEventProxies
292 }
293 {
294 lock_t remap_lock (m_remapMutex);
295 m_remap_impl->m_remaps.clear();
296 m_arena.reset();
297 }
298
299 return StatusCode::SUCCESS;
300}
301
304 verbose() << "Finalizing " << name() << endmsg ;
305
306 // Incident service may not work in finalize.
307 // Clear this, so that we won't try to send an incident from clearStore.
308 (m_pIncSvc.release()).ignore();
309
310 const bool FORCEREMOVE(true);
311 clearStore(FORCEREMOVE).ignore();
312
313 m_stringpool.clear();
314 delete m_pStore;
315 m_pStore = nullptr;
316 delete m_remap_impl;
317 m_remap_impl = 0;
318 m_arena.erase();
319
320 return Service::finalize();
321}
322
325 verbose() << "Reinitializing " << name() << endmsg ;
326 const bool FORCEREMOVE(true);
327 clearStore(FORCEREMOVE).ignore();
328 //not in v20r2p2! return Service::reinitialize();
329 return StatusCode::SUCCESS;
330}
331
334// add proxy (with IOpaqueAddress that will later be retrieved from P)
336StatusCode SGImplSvc::recordAddress(const std::string& skey,
338 bool clearAddressFlag)
339{
340 lock_t lock (m_mutex);
341 assert(0 != pAddress);
342 CLID dataID = pAddress->clID();
343
344 if (dataID == 0)
345 {
346 warning() << "recordAddress: Invalid Class ID found in IOpaqueAddress @"
347 << pAddress.get() << ". IOA will not be recorded"
348 << endmsg;
349 return StatusCode::FAILURE;
350 }
351
352 //do not overwrite a persistent object
353 if (m_pPPS) {
354 DataProxy* dp = m_pStore->proxy (dataID, skey);
355 if (!dp) {
356 dp = m_pPPS->retrieveProxy(dataID, skey, *m_pStore);
357 }
358 if (dp && dp->provider()) {
359 std::string clidTypeName;
360 m_pCLIDSvc->getTypeNameOfID(dataID, clidTypeName).ignore();
361 warning() << "recordAddress: failed for key="<< skey << ", type "
362 << clidTypeName
363 << " (CLID " << dataID << ')'
364 << "\n there is already a persistent version of this object. Will not record a duplicate! "
365 << endmsg;
366 return StatusCode::FAILURE;
367 }
368 }
369
370 // Check if a key already exists
371 DataProxy* dp = m_pStore->proxy_exact(dataID, skey);
372 if (0 == dp && 0 != m_pPPS) {
373 dp = m_pPPS->retrieveProxy(dataID, skey, *m_pStore);
374 }
375
376 // Now treat the various cases:
377 if (0 == dp)
378 {
379 // create the proxy object and register it
380 dp = new DataProxy (TransientAddress (dataID, skey,
381 std::move(pAddress),
382 clearAddressFlag),
383 m_pDataLoader.get(), true, true);
384 m_pStore->addToStore(dataID, dp).ignore();
385
386 addAutoSymLinks (skey, dataID, dp, 0, false);
387 }
388 else if ((0 != dp) && (0 == dp->address()))
389 // Note: intentionally not checking dp->isValidAddress()
390 {
391 // Update proxy with IOpaqueAddress
392 dp->setAddress(std::move(pAddress));
393 }
394 else
395 {
396 string errType;
397 m_pCLIDSvc->getTypeNameOfID(dataID, errType).ignore();
398 warning() << "recordAddress: preexisting proxy @" << dp
399 << " with non-NULL IOA found for key "
400 << skey << " type " << errType << " (" << dataID << "). \n"
401 << "Cannot record IOpaqueAddress @" << pAddress.get()
402 << endmsg;
403 return StatusCode::FAILURE;
404 }
405
406 return StatusCode::SUCCESS;
407
408}
409
412// add proxy (with IOpaqueAddress that will later be retrieved from P)
415 bool clearAddressFlag)
416{
417 lock_t lock (m_mutex);
418 assert(0 != pAddress);
419
420 CLID dataID = pAddress->clID();
421
422 string gK = (pAddress->par())[1]; // transient name by convention
423 if (gK.empty()) gK = (pAddress->par())[0]; // FIXME backward compatibility
424 if (gK.empty()) gK = createKey(dataID);
425
426 return this->recordAddress(gK, std::move(pAddress), clearAddressFlag);
427}
428
430 const string& gK,
431 DataObject* pDObj,
432 bool allowMods,
433 bool resetOnly) {
434 // locate the proxy
435 DataProxy* dp = m_pStore->proxy_exact(dataID, gK);
436
437 if (0 != dp) { //proxy found
438 if (0 != dp->object())
439 {
440 // Case 0: duplicated proxy
441 warning() << " setupProxy:: error setting up proxy for key "
442 << gK << " and clid " << dataID
443 << "\n Pre-existing valid DataProxy @"<< dp
444 << " found in Store for key " << dp->object()->name()
445 << " with clid " << dp->object()->clID()
446 << endmsg;
447 recycle(pDObj); // commit this object to trash
448 dp = 0;
449 } else {
450 // Case 1: Proxy found... if not valid, update it:
451 dp->setObject(pDObj);
452 if (!allowMods) dp->setConst();
453 }
454 } else {
455 // Case 2: No Proxy found:
456 dp = new DataProxy(pDObj,
457 TransientAddress(dataID, gK),
458 !allowMods, resetOnly);
459 if (!(m_pStore->addToStore(dataID, dp).isSuccess())) {
460 warning() << " setupProxy:: could not addToStore proxy @" << dp
461 << endmsg;
462 recycle(pDObj); // commit this object to trash
463 delete dp;
464 dp = 0;
465 }
466 }
467 return dp;
468}
469
472{
473 lock_t lock (m_mutex);
474 store()->setStoreID(id);
475}
476
478{
479 lock_t lock (m_mutex);
480 return store()->storeID();
481}
482
483
484void
485SGImplSvc::keys(const CLID& id, std::vector<std::string>& vkeys,
486 bool includeAlias, bool onlyValid)
487
488{
489 lock_t lock (m_mutex);
490 return store()->keys(id, vkeys, includeAlias, onlyValid);
491}
492
493
494bool SGImplSvc::isSymLinked(const CLID& linkID, DataProxy* dp)
495{
496 return (0 != dp) ? dp->transientID(linkID) : false;
497}
498
499
500StatusCode
502 const CallBackID& c2,
503 const IOVSvcCallBackFcn& fcn,
504 bool trigger)
505{
506 lock_t lock (m_mutex);
507 return ( m_pIOVSvc->regFcn(c1,c2,fcn,trigger) );
508}
509
510
511StatusCode
512SGImplSvc::regFcn( const std::string& toolName,
513 const CallBackID& c2,
514 const IOVSvcCallBackFcn& fcn,
515 bool trigger)
516{
517 lock_t lock (m_mutex);
518 return ( m_pIOVSvc->regFcn(toolName,c2,fcn,trigger) );
519}
520
521
523// Dump Contents in store:
524string SGImplSvc::dump() const
525{
526 lock_t lock (m_mutex);
527 auto out_buffer = std::string{};
528 auto out = std::back_inserter(out_buffer);
529 const std::string me = name();
530 std::format_to(out, "{}: <<<<<<<<<<<<<<<<< Data Store Dump >>>>>>>>>>>>>>> \n", me);
531 std::format_to(out, "{}: SGImplSvc()::dump() which is {} \n", me, m_storeLoaded ? "LOADED" : "NOT LOADED");
532
533 DataStore::ConstStoreIterator s_iter, s_end;
534 store()->tRange(s_iter, s_end).ignore();
535
536 for (; s_iter != s_end; ++s_iter)
537 {
538
539 CLID id = s_iter->first;
540 int nProxy = store()->typeCount(id);
541 std::string tname;
542 m_pCLIDSvc->getTypeNameOfID(id, tname).ignore();
543 std::format_to(out, "{}: Found {} {} for ClassID {} ({}): \n", me, nProxy, ((nProxy == 1) ? "proxy" : "proxies"), id, tname);
544
545 // loop over each type:
546 SG::ConstProxyIterator p_iter = (s_iter->second).begin();
547 SG::ConstProxyIterator p_end = (s_iter->second).end();
548
549 while (p_iter != p_end) {
550 const DataProxy& dp(*p_iter->second);
551 std::format_to(out, "{}: flags: ({:7s}, {:8s}, {:6s}) --- data: {:10p} --- key: {}\n", me,
552 (dp.isValid() ? "valid" : "INVALID"),
553 (dp.isConst() ? "locked" : "UNLOCKED"),
554 (dp.isResetOnly() ? "reset" : "DELETE"),
555 dbg::ptr(dp.object()), p_iter->first);
556 ++p_iter;
557 }
558 }
559 std::format_to(out, "{}: <<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>> \n", me);
560 return out_buffer;
561}
562
563DataStore*
565{
566 return m_pStore;
567}
568
569const DataStore*
571{
572 return m_pStore;
573}
574
575
577// Make a soft link to the object with key
579StatusCode SGImplSvc::symLink(const void* pObject, CLID linkID)
580{
581 lock_t lock (m_mutex);
582 SG::DataProxy* dp(proxy(pObject));
583
584 // if symLink already exists, just return success
585 return isSymLinked(linkID,dp) ?
586 StatusCode::SUCCESS :
587 addSymLink(linkID,dp);
588}
589
590StatusCode SGImplSvc::symLink(const CLID id, const std::string& key, const CLID linkID)
591{
592 lock_t lock (m_mutex);
593 SG::DataProxy* dp(proxy(id, key, false));
594 // if symLink already exists, just return success
595 return isSymLinked(linkID,dp) ?
596 StatusCode::SUCCESS :
597 addSymLink(linkID,dp);
598}
599
600
601StatusCode
603{
604 if (0 == dp) {
605 warning() << "addSymLink: no target DataProxy found. Sorry, can't link to a non-existing data object"
606 << endmsg;
607 return StatusCode::FAILURE;
608 }
609 StatusCode sc = m_pStore->addSymLink(linkid, dp);
610
611 // If the symlink is a derived->base conversion, then we may have
612 // a different transient pointer for the symlink.
613 if (sc.isSuccess() && dp->object()) {
614 void* baseptr = SG::DataProxy_cast (dp, linkid);
615 if (baseptr)
616 this->t2pRegister (baseptr, dp).ignore();
617 }
618 return sc;
619}
620
621
622StatusCode SGImplSvc::setAlias(const void* pObject, const std::string& aliasKey)
623{
624 lock_t lock (m_mutex);
625
626 SG::DataProxy* dp(0);
627 dp = proxy(pObject);
628 if (0 == dp) {
629 error() << "setAlias: problem setting alias "
630 << aliasKey << '\n'
631 << "DataObject does not exist, record before setting alias."
632 << endmsg;
633 return StatusCode::FAILURE;
634 }
635
636 StatusCode sc = addAlias(aliasKey, dp);
637 if (sc.isFailure()) {
638 error() << "setAlias: problem setting alias "
639 << aliasKey << '\n'
640 << "DataObject does not exist, record before setting alias."
641 << endmsg;
642 return StatusCode::FAILURE;
643 }
644
645 return StatusCode::SUCCESS;
646}
647
648
650 const std::string& key, const std::string& aKey)
651{
652 lock_t lock (m_mutex);
653
654 SG::DataProxy* dp(0);
655 dp = proxy(clid, key);
656 if (0 == dp) {
657 error() << "setAlias: problem setting alias "
658 << std::string(aKey) << '\n'
659 << "DataObject does not exist, record before setting alias."
660 << endmsg;
661 return StatusCode::FAILURE;
662 }
663
664 StatusCode sc = addAlias(aKey, dp);
665 if (sc.isFailure()) {
666 error() << "setAlias: problem setting alias "
667 << (std::string)aKey << '\n'
668 << "DataObject does not exist, record before setting alias."
669 << endmsg;
670 return StatusCode::FAILURE;
671 }
672
673 return StatusCode::SUCCESS;
674}
675
676StatusCode SGImplSvc::setAlias(SG::DataProxy* proxy, const std::string& aliasKey)
677{
678 return addAlias( aliasKey, proxy );
679}
680
681StatusCode
682SGImplSvc::addAlias(const std::string& aliasKey, DataProxy* proxy)
683{
684 if (0 == proxy) {
685 warning() << "addAlias: no target DataProxy given, Cannot alias to a non-existing object"
686 << endmsg;
687 return StatusCode::FAILURE;
688 }
689
690 // add key to proxy and to ProxyStore
691 return m_pStore->addAlias(aliasKey, proxy);
692}
693
694int SGImplSvc::typeCount(const CLID& id) const
695{
696 lock_t lock (m_mutex);
697 return m_pStore->typeCount(id);
698}
699
700
701bool
702SGImplSvc::contains(const CLID id, const std::string& key) const
703{
704 try {
705 return (0 != proxy(id, key, true));
706 } catch(...) { return false; }
707}
708
709
710bool
711SGImplSvc::transientContains(const CLID id, const std::string& key) const
712{
713 try {
714 return (0 != transientProxy(id, key));
715 } catch(...) { return false; }
716}
717
718
719DataProxy*
720SGImplSvc::proxy(const void* const pTransient) const
721{
722 // No lock needed here --- the T2pmap held by DataStore has its own locking
723 // (and we were seeing contention here).
724 //lock_t lock (m_mutex);
725 return m_pStore->locatePersistent(pTransient);
726}
727
728DataProxy*
729SGImplSvc::proxy(const CLID& id) const
730{
731 return proxy(id, false);
732}
733
734DataProxy*
735SGImplSvc::proxy(const CLID& id, bool checkValid) const
736{
737 DataProxy* dp = nullptr;
738 {
739 lock_t lock (m_mutex);
740 dp = m_pStore->proxy(id);
741 if (0 == dp && 0 != m_pPPS) {
743 dp = m_pPPS->retrieveProxy(id, string("DEFAULT"), *pStore);
744 }
745 }
747 // Be sure to release the lock before this.
748 // isValid() may call back to the store, so we could otherwise deadlock..
749 if (checkValid && 0 != dp) {
750 // FIXME: For keyless retrieve, this checks only the first instance
751 // of the CLID in store. If that happens to be invalid, but the second
752 // is valid - this does not work (when checkValid is requested).
753 return dp->isValid() ? dp : 0;
754 }
755 return dp;
756}
757
758DataProxy*
759SGImplSvc::proxy(const CLID& id, const string& key) const
760{
761 return proxy(id, key, false);
762}
763
765SGImplSvc::proxy(const CLID& id, const string& key, bool checkValid) const
766{
767 DataProxy* dp = nullptr;
768 {
769 lock_t lock (m_mutex);
770 dp = m_pStore->proxy(id, key);
771#ifdef DEBUG_SGIMPL
772 if (!dp) dbg::print(stderr, "::SGImplSvc::proxy(name={}, key={}): data proxy is null, m_pPPS is {}\n", this->name(), key, m_pPPS == 0 ? "NULL" : "NOT NULL");
773#endif
774 if (0 == dp && 0 != m_pPPS) {
776 dp = m_pPPS->retrieveProxy(id, key, *pStore);
777#ifdef DEBUG_SGIMPL
778 if (!dp) dbg::print(stderr, "::SGImplSvc::proxy(name={}, key={}): data proxy is still null\n", this->name(), key);
779#endif
780 }
781 }
782 // Be sure to release the lock before this.
783 // isValid() may call back to the store, so we could otherwise deadlock..
784 if (checkValid && 0 != dp && !(dp->isValid())) {
785 dp = 0;
786 }
787 return dp;
788}
789
790
797{
798 lock_t lock (m_mutex);
799 return m_pStore->addToStore (id, proxy);
800}
801
802
824 const std::string& key,
825 bool allowMods,
826 bool returnExisting)
827{
828 lock_t lock (m_mutex);
829 const void* raw_ptr = obj.get();
830 const std::type_info* tinfo = nullptr;
831
832 if (DataBucketBase* bucket = dynamic_cast<DataBucketBase*> (obj.get())) {
833 raw_ptr = bucket->object();
834 tinfo = &bucket->tinfo();
835 }
836
837 if (returnExisting) {
838 SG::DataProxy* proxy = this->proxy (obj->clID(), key);
839 if (proxy && proxy->isValid()) return proxy;
840
841 // Look for the same object recorded under a different key/clid.
842 proxy = this->proxy (raw_ptr);
843 if (proxy && proxy->isValid()) {
844 if (proxy->transientID (obj->clID())) {
845 // CLID matches. Make an alias.
846 if (addAlias (key, proxy).isFailure()) {
847 CLID clid = proxy->clID();
848 std::string clidTypeName;
849 m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore();
850 warning() << "SGImplSvc::recordObject: addAlias fails for object "
851 << clid << "[" << clidTypeName << "] " << proxy->name()
852 << " and new key " << key
853 << endmsg;
854
855 proxy = nullptr;
856 }
857 }
858
859 else if (key == proxy->name() || proxy->hasAlias(key) > 0)
860 {
861 // key matches. Make a symlink.
862 if (addSymLink (obj->clID(), proxy).isFailure()) {
863 CLID clid = proxy->clID();
864 std::string clidTypeName;
865 m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore();
866 CLID newclid = obj->clID();
867 std::string newclidTypeName;
868 m_pCLIDSvc->getTypeNameOfID(newclid, newclidTypeName).ignore();
869 error() << "SGImplSvc::recordObject: addSymLink fails for object "
870 << clid << "[" << clidTypeName << "] " << proxy->name()
871 << " and new clid " << newclid << "[" << newclidTypeName << "]"
872 << endmsg;
873 proxy = nullptr;
874 }
875 }
876
877 else {
878 CLID clid = proxy->clID();
879 std::string clidTypeName;
880 m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore();
881 CLID newclid = obj->clID();
882 std::string newclidTypeName;
883 m_pCLIDSvc->getTypeNameOfID(newclid, newclidTypeName).ignore();
884 error() << "SGImplSvc::recordObject: existing object found with "
885 << clid << "[" << clidTypeName << "] " << proxy->name()
886 << " but neither clid " << newclid << "[" << newclidTypeName << "]"
887 << " nor key " << key << " match."
888 << endmsg;
889 proxy = nullptr;
890 }
891
892 return proxy;
893 }
894 }
895
896 const bool resetOnly = true;
897 const bool noHist = false;
898 SG::DataProxy* proxy = nullptr;
899 if (this->typeless_record (obj.get(), key, raw_ptr,
900 allowMods, resetOnly, noHist, tinfo,
901 &proxy, true).isFailure())
902 {
903 return nullptr;
904 }
905 return proxy;
906}
907
908
913{
914 return m_pStore->proxy_exact_unlocked (sgkey, m_mutex);
915}
916
917
924void SGImplSvc::setSlotNumber (int slot, int numSlots)
925{
926 m_slotNumber = slot;
927 m_numSlots = numSlots;
928
930 header->setArenaForSlot (slot, &m_arena);
931}
932
933
934std::vector<const SG::DataProxy*>
936{
937 lock_t lock (m_mutex);
938 const std::vector<SG::DataProxy*>& proxies = store()->proxies();
939 std::vector<const SG::DataProxy*> ret (proxies.begin(), proxies.end());
940 return ret;
941}
942
943
944std::vector<CLID>
946{
947 lock_t lock (m_mutex);
948
949 using std::distance;
950 DataStore::ConstStoreIterator s_iter, s_end;
951 store()->tRange(s_iter, s_end).ignore();
952
953 std::vector<CLID> clids;
954 clids.reserve( distance( s_iter, s_end ) );
955
956 for (; s_iter != s_end; ++s_iter ) {
957 const CLID id = s_iter->first;
958 clids.push_back (id);
959 }
960
961 return clids;
962}
963
964
966SGImplSvc::transientProxy(const CLID& id, const string& key) const
967{
968 lock_t lock (m_mutex);
969 DataProxy* dp(m_pStore->proxy(id, key));
970 return ( (0 != dp && dp->isValidObject()) ? dp : 0 );
971}
972
973DataObject*
975{
976 lock_t lock (m_mutex);
977 DataProxy* theProxy(proxy(id, true));
978 return (0 == theProxy) ? 0 : theProxy->accessData();
979}
980
981DataObject*
982SGImplSvc::accessData(const CLID& id, const string& key) const
983{
984 lock_t lock (m_mutex);
985 DataProxy* theProxy(proxy(id, key, true));
986 return (0 == theProxy) ? 0 : theProxy->accessData();
987}
988
989bool
991 const std::string& keyA, const std::string& keyB )
992{
993 lock_t lock (m_mutex);
994 const bool checkValid = true;
995 DataProxy* a = proxy( id, keyA, checkValid );
996 DataProxy* b = proxy( id, keyB, checkValid );
997 if ( 0 == a || 0 == b ) { return false; }
998 DataObject* objA = a->accessData();
999 DataObject* objB = b->accessData();
1000
1001 if ( 0 == objA || 0 == objB ) { return false; }
1002 // prevent 'accidental' release of DataObjects...
1003 const unsigned int refCntA = objA->addRef();
1004 const unsigned int refCntB = objB->addRef();
1005 // in case swap is being specialized for DataObjects
1006 using std::swap;
1007 swap( objA, objB );
1008 a->setObject( objA );
1009 b->setObject( objB );
1010 // and then restore old ref-count;
1011 return ( (refCntA-1) == objA->release() &&
1012 (refCntB-1) == objB->release() );
1013}
1014
1015StatusCode
1016SGImplSvc::typeless_record( DataObject* obj, const std::string& key,
1017 const void* const raw_ptr,
1018 bool allowMods, bool resetOnly, bool noHist)
1019{
1020 return typeless_record (obj, key, raw_ptr, allowMods, resetOnly, noHist, 0,
1021 nullptr, true);
1022}
1023
1024
1025StatusCode
1026SGImplSvc::typeless_record( DataObject* obj, const std::string& key,
1027 const void* const raw_ptr,
1028 bool allowMods, bool resetOnly, bool noHist,
1029 const std::type_info* tinfo)
1030{
1031 return typeless_record (obj, key, raw_ptr, allowMods, resetOnly, noHist,tinfo,
1032 nullptr, true);
1033}
1034
1035
1036StatusCode
1037SGImplSvc::typeless_record( DataObject* obj, const std::string& key,
1038 const void* const raw_ptr,
1039 bool allowMods, bool resetOnly, bool noHist,
1040 const std::type_info* tinfo,
1041 SG::DataProxy** proxy_ret,
1042 bool noOverwrite)
1043{
1044 lock_t lock (m_mutex);
1046 record_impl( obj, key, raw_ptr, allowMods, resetOnly, !noOverwrite, tinfo);
1047 if ( proxy == nullptr )
1048 return StatusCode::FAILURE;
1049 if (proxy_ret)
1050 *proxy_ret = proxy;
1051
1052 if ( !m_ActivateHistory || noHist ) {
1053 return StatusCode::SUCCESS;
1054 }
1055
1056 if ( store()->storeID() != StoreID::EVENT_STORE ) {
1057 return StatusCode::SUCCESS;
1058 } else {
1059 return record_HistObj( obj->clID(), key, name(), allowMods, resetOnly );
1060 }
1061}
1062
1063StatusCode
1065 DataObject* obj,
1066 const std::string& key,
1067 const void* const raw_ptr,
1068 bool allowMods,
1069 bool noHist,
1070 const std::type_info* tinfo)
1071{
1072 lock_t lock (m_mutex);
1073 StatusCode sc(StatusCode::SUCCESS);
1074 SG::DataProxy* toRemove(proxy(clid, key, false));
1075 if (0 != toRemove) {
1076 toRemove->addRef();
1077 const bool FORCEREMOVE(true);
1078 sc =removeProxy(toRemove, (void*)0, FORCEREMOVE);
1079 }
1080 if (sc.isSuccess()) {
1081 const bool ALLOWOVERWRITE(true);
1082 const bool NORESET(false);
1083 if (record_impl( obj, key, raw_ptr, allowMods, NORESET, ALLOWOVERWRITE, tinfo) == nullptr)
1084 sc = StatusCode::FAILURE;
1085 else if ( m_ActivateHistory && noHist && store()->storeID() == StoreID::EVENT_STORE ) {
1086 sc = record_HistObj( obj->clID(), key, name(), allowMods, NORESET );
1087 }
1088 }
1089 //for detector store objects managed by IIOVSvc, replace the old proxy with the new one (#104311)
1090 if (toRemove && sc.isSuccess() && store()->storeID() == StoreID::DETECTOR_STORE) {
1091 sc = m_pIOVSvc->replaceProxy(toRemove, proxy(clid, key));
1092 }
1093 if (toRemove)
1094 toRemove->release();
1095 return sc;
1096}
1097
1099SGImplSvc::record_impl( DataObject* pDObj, const std::string& key,
1100 const void* const raw_ptr,
1101 bool allowMods, bool resetOnly, bool allowOverwrite,
1102 const std::type_info* tinfo)
1103{
1104 CLID clid = pDObj->clID();
1105 std::string rawKey(key);
1106 bool isVKey(SG::VersionedKey::isVersionedKey(key));
1107 if (isVKey) {
1108 //FIXME VersionedKeys will need to be handled more efficiently
1109 SG::VersionedKey vk(rawKey);
1110 DataProxy *dp(proxy(clid, vk.key()));
1111 if (dp) {
1112 //proxies primary key
1113 const std::string& pTAName(dp->name());
1114 //original key as versioned
1115 SG::VersionedKey primaryVK(pTAName);
1116
1117 //if the existing matching object has no version
1118 //create a versioned alias for the original unversioned key
1119 //so it will remain accessible
1120 if (!SG::VersionedKey::isVersionedKey(pTAName)) {
1121 if (!(this->addAlias(primaryVK.rawVersionKey(), dp)).isSuccess()) {
1122 warning() << "record_impl: Could not setup alias key "
1123 << primaryVK.rawVersionKey()
1124 << " for unversioned object " << pTAName
1125 << endmsg;
1126 return nullptr;
1127 }
1128 }
1129 if (vk.isAuto()) {
1130 //make a new versioned key incrementing the existing version
1131 SG::VersionedKey newVK(primaryVK.key(), primaryVK.version()+1);
1132 //FIXME this will fail in a confusing way if version+1 is in use
1133 //FIXME need a better error message below, probably looking at all
1134 //FIXME aliases
1135 rawKey = newVK.rawVersionKey();
1136 }
1137 }
1138 }
1139 if (!allowOverwrite && m_pPPS) {
1140 //do not overwrite a persistent object
1141 DataProxy* dp = m_pStore->proxy (clid, rawKey);
1142 if (!dp) {
1143 dp = m_pPPS->retrieveProxy(clid, rawKey, *m_pStore);
1144 }
1145 if (dp && dp->provider()) {
1146 std::string clidTypeName;
1147 m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore();
1148 warning() << "record_impl: you are recording an object with key "
1149 << rawKey << ", type " << clidTypeName
1150 << " (CLID " << clid << ')'
1151 << "\n There is already a persistent version of this object. Recording a duplicate may lead to unreproducible results and it is deprecated."
1152 << endmsg;
1153 }
1154 }
1155 //now check whether raw_ptr has already been recorded
1156 //We need to do this before we create the bucket, the proxy etc
1157 SG::DataProxy* dp(proxy(raw_ptr));
1158 if (0 != dp) {
1159 std::string clidTypeName;
1160 m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore();
1161 warning() << "record_impl: failed for key="<< rawKey << ", type "
1162 << clidTypeName
1163 << " (CLID " << clid << ')'
1164 << "\n object @" << raw_ptr
1165 << " already in store with key="<< dp->name()
1166 << ". Will not record a duplicate! "
1167 << endmsg;
1168 if (pDObj != dp->object()) {
1169 DataBucketBase* pDBB(dynamic_cast<DataBucketBase*>(pDObj));
1170 if (!pDBB) std::abort();
1171 pDBB->relinquish(); //don't own the data obj already recorded!
1172 }
1173 this->recycle(pDObj);
1174 return nullptr;
1175 }
1176
1177
1178 // setup the proxy
1179 dp = setupProxy( clid, rawKey, pDObj, allowMods, resetOnly );
1180 if ( 0 == dp ) {
1181 std::string clidTypeName;
1182 m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore();
1183 warning() << "record_impl: Problem setting up the proxy for object @"
1184 << raw_ptr
1185 << "\n recorded with key " << rawKey
1186 << " of type " << clidTypeName
1187 << " (CLID " << clid << ") in DataObject @" << pDObj
1188 << endmsg;
1189
1190 return nullptr;
1191 }
1192
1193 // record in t2p:
1194 if ( !(this->t2pRegister( raw_ptr, dp )).isSuccess() ) {
1195 std::string clidTypeName;
1196 m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore();
1197 warning() << "record_impl: can not add to t2p map object @" <<raw_ptr
1198 << "\n with key " << rawKey
1199 << " of type " << clidTypeName
1200 << " (CLID " << clid << ')'
1201 << endmsg;
1202 return nullptr;
1203 }
1204
1205 addAutoSymLinks (rawKey, clid, dp, tinfo);
1206
1207 //handle versionedKeys: we register an alias with the "true" key
1208 //unless an object as already been recorded with that key.
1209 //Notice that addAlias overwrites any existing alias, so a generic
1210 //retrieve will always return the last version added
1211 //FIXME not the one with the highest version
1212 if (isVKey) {
1213 SG::VersionedKey vk(rawKey);
1214 if (!(this->addAlias(vk.key(), dp)).isSuccess()) {
1215 warning() << "record_impl: Could not setup alias key " << vk.key()
1216 << " for VersionedKey " << rawKey
1217 << ". Generic access to this object with clid" << clid
1218 << " will not work"
1219 << endmsg;
1220 }
1221 }
1222
1223 return dp;
1224}
1225
1226DataProxy*
1228 bool checkValid) const
1229{
1230 DataProxy* dp = m_pStore->proxy(tAddr);
1231
1232 if (checkValid && 0 != dp) {
1233 return dp->isValid() ? dp : 0;
1234 } else {
1235 return dp;
1236 }
1237}
1238
1239StatusCode
1241 bool forceRemove)
1242{
1243 lock_t lock (m_mutex);
1244 // check if valid proxy
1245 if (0 == proxy) return StatusCode::FAILURE;
1246
1247 if (0 == pTrans) {
1248 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(proxy->object());
1249 if (bucket) pTrans = bucket->object();
1250 }
1251
1252 // remove all entries from t2p map
1253 // --- only if the proxy actually has an object!
1254 // otherwise, we can trigger I/O.
1255 // besides being useless here, we can get deadlocks if we
1256 // call into the I/O code while holding the SG lock.
1257 if (proxy->isValidObject()) {
1258 this->t2pRemove(pTrans);
1259 SG::DataProxy::CLIDCont_t clids = proxy->transientID();
1260 for (SG::DataProxy::CLIDCont_t::const_iterator i = clids.begin();
1261 i != clids.end();
1262 ++i)
1263 {
1264 void* ptr = SG::DataProxy_cast (proxy, *i);
1265 this->t2pRemove(ptr);
1266 }
1267 }
1268
1269 // remove from store
1270 return m_pStore->removeProxy(proxy, forceRemove, true);
1271}
1272
1273StatusCode
1274SGImplSvc::t2pRegister(const void* const pTrans, DataProxy* const pPers)
1275{
1276 return m_pStore->t2pRegister(pTrans, pPers);
1277}
1278
1279
1280void
1281SGImplSvc::t2pRemove(const void* const pTrans)
1282{
1283 m_pStore->t2pRemove(pTrans);
1284}
1285
1286void
1287SGImplSvc::msg_update_handler(Gaudi::Details::PropertyBase& /*outputLevel*/)
1288{
1289 setUpMessaging();
1290 updateMsgStreamOutputLevel( outputLevel() );
1291 msgSvc()->setOutputLevel(name(), outputLevel());
1292}
1293
1294StatusCode
1297 SG::ConstProxyIterator& end) const {
1298 lock_t lock (m_mutex);
1299 return m_pStore->pRange(id,begin,end);
1300}
1301
1302StatusCode SGImplSvc::setConst(const void* pObject)
1303{
1304 lock_t lock (m_mutex);
1305 // Check if DataProxy does not exist
1306 DataProxy * dp = proxy(pObject);
1307
1308 if (0 == dp)
1309 {
1310 warning() << "setConst: NO Proxy for the dobj you want to set const"
1311 << endmsg;
1312 return StatusCode::FAILURE;
1313 }
1314
1315 dp->setConst();
1316 return StatusCode::SUCCESS;
1317}
1318
1319
1320// remove an object from Store, will remove its proxy if not reset only
1321StatusCode
1322SGImplSvc::remove(const void* pObject)
1323{
1324 lock_t lock (m_mutex);
1325 return removeProxy(proxy(pObject), pObject);
1326}
1327
1328
1329// remove an object and its proxy from Store
1330StatusCode
1332{
1333 lock_t lock (m_mutex);
1334 const bool FORCEREMOVE(true);
1335 return removeProxy(proxy(pObject), pObject, FORCEREMOVE);
1336}
1337
1338//put a bad (unrecordable) dobj away
1339void SGImplSvc::recycle(DataObject* pBadDObj) {
1340 assert(pBadDObj);
1341 pBadDObj->addRef();
1342 m_trash.push_back(pBadDObj);
1343}
1344
1345//throw away bad objects
1347 lock_t lock (m_mutex);
1348 while (!m_trash.empty()) {
1349 m_trash.front()->release(); //delete the bad data object
1350 m_trash.pop_front(); //remove pointer from list
1351 }
1352}
1353
1354
1355/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1356
1357bool SGImplSvc::bindHandleToProxy(const CLID& id, const string& key,
1358 IResetable* ir, DataProxy *&dp)
1359{
1360 lock_t lock (m_mutex);
1361
1362 dp = m_pStore->proxy (id, key);
1363 if (dp == nullptr && m_pPPS != nullptr) {
1364 dp = m_pPPS->retrieveProxy(id, key, *m_pStore);
1365 }
1366
1367 if (0 == dp) return false;
1368
1369 if (! dp->bindHandle(ir) ) {
1370 fatal() << "DataHandle at " << hex << ir << dec
1371 << " already bound to DataProxy with key " << ir->key()
1372 << ". Cannot bind to proxy " << dp->name() << " as well\n"
1373 << " You have probably registered multiple callbacks via regFcn with the same DataHandle using different keys (DataProxies)\n"
1374 << endmsg;
1375 return false;
1376 }
1377
1378 //already done in DataHandleBase::setState dp->addRef();
1379
1380#ifndef NDEBUG
1381 SG_MSG_DEBUG(" Bound handle " << MSG::hex << ir << " to proxy "
1382 << dp << MSG::dec);
1383#endif
1384 return true;
1385}
1386
1387/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1388
1389bool SGImplSvc::bindHandleToProxyAndRegister (const CLID& id, const std::string& key,
1390 IResetable* ir, SG::DataProxy *&dp)
1391{
1392 lock_t lock (m_mutex);
1393 bool ret = bindHandleToProxy (id, key, ir, dp);
1394 if (ret) {
1395 StatusCode sc = m_pIOVSvc->regProxy(dp,key);
1396 if (sc.isFailure()) return false;
1397 }
1398 return true;
1399}
1400
1401/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1402
1403bool SGImplSvc::bindHandleToProxyAndRegister (const CLID& id, const std::string& key,
1405 const CallBackID& c,
1406 const IOVSvcCallBackFcn& fcn,
1407 bool trigger)
1408{
1409 lock_t lock (m_mutex);
1410 bool ret = bindHandleToProxy (id, key, ir, dp);
1411 if (ret) {
1412 StatusCode sc = m_pIOVSvc->regProxy(dp,key);
1413 if (sc.isFailure()) return false;
1414 sc = m_pIOVSvc->regFcn(dp,c,fcn,trigger);
1415 if (sc.isFailure()) return false;
1416 }
1417 return true;
1418}
1419
1420/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1421
1422StatusCode
1423SGImplSvc::record_HistObj(const CLID& id, const std::string& key,
1424 const std::string& store,
1425 bool allowMods, bool resetOnly) {
1426
1427 DataHistory *dho;
1428 dho = m_pHistorySvc->createDataHistoryObj( id, key, store );
1429
1430 std::string idname;
1431 StatusCode sc = m_pCLIDSvc->getTypeNameOfID(id, idname);
1432 if (sc.isFailure() || idname.empty() ) {
1433 idname = std::to_string(id);
1434 }
1435 idname += '/';
1436 idname += key;
1437
1438 DataObject* obj = SG::asStorable(dho);
1439
1440 const bool ALLOWOVERWRITE(false);
1441 if (record_impl(obj, idname, dho, allowMods, resetOnly, ALLOWOVERWRITE,
1442 &typeid(DataHistory)) == nullptr)
1443 return StatusCode::FAILURE;
1444 return StatusCode::SUCCESS;
1445}
1446
1447
1458{
1460 return m_stringpool.stringToKey (str, clid);
1461}
1462
1463
1471const std::string* SGImplSvc::keyToString (sgkey_t key) const
1472{
1474 return m_stringpool.keyToString (key);
1475}
1476
1477
1486const std::string*
1488{
1490 return m_stringpool.keyToString (key, clid);
1491}
1492
1493
1507 const std::string& str,
1508 CLID clid)
1509{
1511 if (!m_stringpool.registerKey (key, str, clid)) {
1512 CLID clid2;
1513 const std::string* str2 = m_stringpool.keyToString (key, clid2);
1514 REPORT_MESSAGE (MSG::WARNING) << "The numeric key " << key
1515 << " maps to multiple string key/CLID pairs: "
1516 << *str2 << "/" << clid2 << " and "
1517 << str << "/" << clid;
1518 }
1519}
1520
1521
1530{
1531 // We should hold m_stringPoolMutex before touching the pool.
1532 // But if we acquire the locks for both this and the other store,
1533 // we risk a deadlock. So first copy the other pool, so that we
1534 // don't need to hold both locks at the same time.
1535 SG::StringPool tmp;
1536 {
1537 lock_t lock (other.m_stringPoolMutex);
1538 tmp = other.m_stringpool;
1539 }
1541 return m_stringpool.merge (tmp);
1542}
1543
1544
1545void
1546SGImplSvc::releaseObject(const CLID& id, const std::string& key) {
1547 lock_t lock (m_mutex);
1548 DataProxy *pP(0);
1549 if (0 != (pP = proxy(id, key))) {
1550 // remove all entries from t2p map
1552 SG::DataProxy::CLIDCont_t::const_iterator i(clids.begin()), e(clids.end());
1553 while (i != e) t2pRemove(SG::DataProxy_cast (pP, *i++));
1554 DataBucketBase *pDBB(dynamic_cast<DataBucketBase*>(pP->object()));
1555 //tell the bucket to let go of the data object
1556 if (0 != pDBB) pDBB->relinquish(); //somebody else better took ownership
1557 bool hard_reset = (m_numSlots > 1);
1558 pP->reset (hard_reset);
1559 }
1560}
1561
1562void
1564 lock_t lock (m_mutex);
1565
1566 // Remove transient pointer entries for this proxy.
1567 // But do that only if the proxy has a valid object.
1568 // Otherwise, we could trigger I/O --- which we don't want since it's useless
1569 // (we'd just destroy the object immediately). In some cases it can also
1570 // lead to a deadlock (see ATR-24482).
1571 if (dp->isValidObject()) {
1572 SG::DataProxy::CLIDCont_t clids = dp->transientID();
1573 SG::DataProxy::CLIDCont_t::const_iterator i(clids.begin()), e(clids.end());
1574 while (i != e) {
1575 t2pRemove(SG::DataProxy_cast (dp, *i++));
1576 }
1577 }
1578
1579 bool hard_reset = (m_numSlots > 1);
1580 dp->reset (hard_reset);
1581}
1582
1583
1592 sgkey_t target,
1593 off_t index_offset)
1594{
1595 lock_t lock (m_remapMutex);
1596 SG::RemapImpl::remap_t payload;
1597 payload.target = target;
1598 payload.index_offset = index_offset;
1599 m_remap_impl->m_remaps[source] = payload;
1600}
1601
1602
1611bool SGImplSvc::tryELRemap (sgkey_t sgkey_in, size_t index_in,
1612 sgkey_t& sgkey_out, size_t& index_out)
1613{
1614 lock_t lock (m_remapMutex);
1615 SG::RemapImpl::remap_map_t::iterator i =
1616 m_remap_impl->m_remaps.find (sgkey_in);
1617 if (i == m_remap_impl->m_remaps.end())
1618 return false;
1619 const SG::RemapImpl::remap_t& payload = i->second;
1620 sgkey_out = payload.target;
1621 index_out = index_in + payload.index_offset;
1622 return true;
1623}
1624
1625
1627 const std::string& key)
1628{
1629 lock_t lock (m_mutex);
1630 DataObject* obj = nullptr;
1631 SG::DataProxy* dp = proxy (clid, key);
1632 //we do not want anyone to mess up with our copy hence we release it immediately.
1633 if (dp && dp->isValid()) {
1634 obj = dp->object();
1635 obj->addRef();
1636 clearProxyPayload (dp);
1637 }
1638 return obj;
1639}
1640
1641
1642CLID SGImplSvc::clid( const std::string& key ) const
1643{
1644 lock_t lock (m_mutex);
1646 store()->tRange(s_iter, s_end).ignore();
1647
1648 for ( ; s_iter != s_end; ++s_iter ) {
1649 if ( s_iter->second.find( key ) != s_iter->second.end() ) {
1650 return s_iter->first;
1651 }
1652 }
1653
1654 return CLID_NULL;
1655}
1656
1657
1658std::vector<CLID> SGImplSvc::clids( const std::string& key ) const
1659{
1660 lock_t lock (m_mutex);
1661 std::vector<CLID> clids;
1663 store()->tRange(s_iter, s_end).ignore();
1664
1665 for ( ; s_iter != s_end; ++s_iter ) {
1666 if ( s_iter->second.find( key ) != s_iter->second.end() ) {
1667 clids.push_back(s_iter->first);
1668 }
1669 }
1670
1671 return clids;
1672}
1673
1674
1676void SGImplSvc::addAutoSymLinks (const std::string& key,
1677 CLID clid,
1678 DataProxy* dp,
1679 const std::type_info* tinfo,
1680 bool warn_nobib /*= true*/)
1681{
1682 // Automatically make all legal base class symlinks
1683 if (!tinfo) {
1685 }
1686 const SG::BaseInfoBase* bib = nullptr;
1687 if (tinfo) {
1688 bib = SG::BaseInfoBase::find (*tinfo);
1689 }
1690 if (!bib) {
1691 // Could succeed where the previous fails if clid for DataVector<T>
1692 // but tinfo is for ConstDataVector<DataVector<T> >.
1694 }
1695 if ( bib ) {
1696 const std::vector<CLID>& bases = bib->get_bases();
1697 for ( std::size_t i = 0, iMax = bases.size(); i < iMax; ++i ) {
1698 if ( bases[i] != clid ) {
1699 if ( addSymLink( bases[i], dp ).isSuccess() ) {
1700 // register with t2p
1701 if (dp->object())
1702 this->t2pRegister( SG::DataProxy_cast( dp, bases[i] ), dp ).ignore();
1703 }
1704 else {
1705 warning() << "record_impl: Doing auto-symlinks for object with CLID "
1706 << clid
1707 << " and SG key " << key
1708 << ": Proxy already set for base CLID " << bases[i]
1709 << "; not making auto-symlink." << endmsg;
1710 }
1711 }
1712 }
1713
1714 // Handle copy conversions.
1715 {
1716 for (CLID copy_clid : bib->get_copy_conversions()) {
1717 if (m_pStore->addSymLink (copy_clid, dp).isFailure()) {
1718 warning() << "record_impl: Doing auto-symlinks for object with CLID "
1719 << clid
1720 << " and SG key " << key
1721 << ": Proxy already set for copy-conversion CLID "
1722 << copy_clid
1723 << "; not making auto-symlink." << endmsg;
1724 }
1725 }
1726 }
1727 }
1728 else {
1729 if (warn_nobib) {
1730 warning() << "record_impl: Could not find suitable SG::BaseInfoBase for CLID ["
1731 << clid << "] (" << key << ") !\t"
1732 << "No auto-symlink established !"
1733 << endmsg;
1734 }
1735 }
1736}
1737
1738void
1740 lock_t lock (m_mutex);
1741
1742 // Reset handles added since the last call to commit.
1743 bool hard_reset = (m_numSlots > 1);
1744 std::vector<IResetable*> handles;
1745 m_newBoundHandles[std::this_thread::get_id()].swap (handles);
1746 for (IResetable* h : handles)
1747 h->reset (hard_reset);
1748}
1749
1750
1756void
1758{
1759 m_newBoundHandles[std::this_thread::get_id()].push_back (handle);
1760}
1761
1762
1768void
1770{
1771 std::vector<IResetable*>& v = m_newBoundHandles[std::this_thread::get_id()];
1772 std::vector<IResetable*>::iterator it =
1773 std::find (v.begin(), v.end(), handle);
1774 if (it != v.end())
1775 v.erase (it);
1776}
1777
1778
1782{
1783 lock_t lock (m_mutex);
1784 m_arena.makeCurrent();
1786}
1787
1788
1799StatusCode
1800SGImplSvc::createObj (IConverter* cvt,
1801 IOpaqueAddress* addr,
1802 DataObject*& refpObject)
1803{
1804 // This lock was here originally, but is probably not really needed ---
1805 // both DataProxy and the I/O components have their own locks.
1806 // Further, this was observed to cause deadlocks for the detector store,
1807 // and would in general be expected to be a contention issue.
1808 //lock_t lock (m_mutex);
1809 return cvt->createObj (addr, refpObject);
1810}
1811
1812
1813// This is intended to be called from the debugger.
1815{
1816 std::cout << sg->dump() << "\n";
1817}
1818void SG_dump (SGImplSvc* sg, const char* fname)
1819{
1820 std::ofstream f (fname);
1821 f << sg->dump() << "\n";
1822 f.close();
1823}
1824
1825
1832SG::SourceID SGImplSvc::sourceID (const std::string& key /*= "EventSelector"*/) const
1833{
1834 lock_t lock (m_mutex);
1836 if (dp) {
1838 if (dh) {
1839 return dh->begin()->getToken()->dbID().toString();
1840 }
1841 }
1842 return "";
1843}
1844
1845
1847// Retrieve a list of collections from Transient Store with no Key.
1848// const version
1851 SG::detail::IteratorBase& cibegin,
1852 SG::detail::IteratorBase& ciend) const
1853{
1854 lock_t lock (m_mutex);
1857
1858 if (!(proxyRange(clid,first,end)).isSuccess()) {
1859 std::string typnam;
1860 m_pCLIDSvc->getTypeNameOfID(clid, typnam).ignore();
1861 SG_MSG_DEBUG("retrieve(range): no object found "
1862 << " of type " << typnam
1863 << "(CLID " << clid << ')');
1864 }
1865
1866 (ciend.setState(end, end, true)).ignore();
1867
1868 if (!(cibegin.setState(first, end, true)).isSuccess()) {
1869 std::string typnam;
1870 m_pCLIDSvc->getTypeNameOfID(clid, typnam).ignore();
1871 SG_MSG_DEBUG("retrieve(range): Can't initialize iterator for object range "
1872 << " of type " << typnam
1873 << "(CLID " << clid << ')');
1874 return StatusCode::FAILURE;
1875 }
1876
1877 return StatusCode::SUCCESS;
1878}
1879
1880
1882 const std::string& key,
1883 CLID auxclid) const
1884{
1885 // If we already have the aux store (as should usually be the case), return
1886 // without taking out the SG lock. Otherwise, we can deadlock
1887 // if another thread is also trying to dereference a link to the aux store.
1888 // (Should _not_ be holding the SG lock when dereferencing the link!)
1889 if (ptr->hasStore()) return true;
1890
1891 lock_t lock (m_mutex);
1892 SG_MSG_VERBOSE("called associateAux_impl for key " + key);
1893 // no Aux store set yet
1894 if (!ptr->hasStore()) {
1895 SG::DataProxy* dp = proxy (auxclid, key + "Aux.", true);
1896 if (dp) {
1897 if (!dp->isConst()) {
1899 if (pAux) {
1900 ptr->setStore (pAux);
1901 return true;
1902 }
1903 }
1904
1906 if (pAux) {
1907 ptr->setStore (pAux);
1908 return true;
1909 }
1910 }
1911 }
1912 return false;
1913}
1914
1915
1917 const std::string& key,
1918 CLID auxclid) const
1919{
1920 lock_t lock (m_mutex);
1921 SG_MSG_VERBOSE("called associateAux_impl for key " + key);
1922 // no Aux store set yet
1923 if (!ptr->hasStore()) {
1924 SG::DataProxy* dp = proxy (auxclid, key + "Aux.", true);
1925 if (dp) {
1926 if (!dp->isConst()) {
1928 if (pAux) {
1929 ptr->setStore (pAux);
1930 return true;
1931 }
1932 }
1933
1935 if (pAux) {
1936 ptr->setStore (pAux);
1937 return true;
1938 }
1939 }
1940 }
1941 return false;
1942}
#define endmsg
Proxy for a group of Arenas. See Arena.h for an overview of the arena-based memory allocators.
Manage index tracking and synchronization of auxiliary data.
a static registry of CLID->typeName entries.
Helpers for checking error return status codes and reporting errors.
#define REPORT_MESSAGE(LVL)
Report a message.
#define CHECK(...)
Evaluate an expression and check for errors.
This file contains the class definition for the DataHeader and DataHeaderElement classes.
void swap(DataVector< T > &a, DataVector< T > &b)
See DataVector<T, BASE>::swap().
uint32_t CLID
The Class ID type.
Interface for non-const operations on an auxiliary store.
Interface for const operations on an auxiliary store.
boost::function< StatusCode(IOVSVC_CALLBACK_ARGS) > IOVSvcCallBackFcn
the type of an IOVSvc call back: it wraps both the method and the object the method is called on
Definition IOVSvcDefs.h:58
static Double_t a
static Double_t sc
const bool debug
void SG_dump(SGImplSvc *sg)
These are intended to be easy to call from the debugger.
Hold a pointer to the current event store.
defines a StoreGateSvc key with a version number
Incident sent after a store is cleared.
Maintain a mapping of strings to 64-bit ints.
const char *const fmt
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
Header file for AthHistogramAlgorithm.
static const std::type_info * CLIDToTypeinfo(CLID clid)
Translate between CLID and type_info.
Simple smart pointer for Gaudi-style refcounted objects.
T * get()
Get the pointer.
A non-templated base class for DataBucket, allows to access the transient object address as a void*.
virtual void * object()=0
virtual void relinquish()=0
Give up ownership of the DataBucket contents.
This class provides the layout for summary information stored for data written to POOL.
Definition DataHeader.h:123
StoreMap::const_iterator ConstStoreIterator
a resetable object (e.g.
Definition IResetable.h:15
SG::sgkey_t sgkey_t
Type of the keys.
Definition IStringPool.h:34
The Athena Transient Store API.
Definition SGImplSvc.h:110
virtual SG::DataProxy * proxy(const void *const pTransient) const override final
get proxy for a given data object address in memory
virtual bool tryELRemap(sgkey_t sgkey_in, size_t index_in, sgkey_t &sgkey_out, size_t &index_out) override final
Test to see if the target of an ElementLink has moved.
void addAutoSymLinks(const std::string &key, CLID clid, SG::DataProxy *dp, const std::type_info *tinfo, bool warn_nobib=true)
Add automatically-made symlinks for DP.
void setStoreID(StoreID::type id)
set store ID. request forwarded to DataStore:
StatusCode t2pRegister(const void *const pTrans, SG::DataProxy *const pPers)
forwarded to DataStore
virtual ~SGImplSvc() override final
Standard Destructor.
StatusCode symLink(const void *p2BRegistered, CLID linkID)
make a soft link to the object T* already registered
StatusCode typeless_record(DataObject *obj, const std::string &key, const void *const raw_ptr, bool allowMods, bool resetOnly=true, bool noHist=false)
type-less recording of an object with a key, allow possibility of specifying const-access and history...
virtual void boundHandle(IResetable *handle) override final
Tell the store that a proxy has been bound to a handle.
DataObject * typeless_retrievePrivateCopy(const CLID clid, const std::string &key)
virtual sgkey_t stringToKey(const std::string &str, CLID clid) override final
Find the key for a string/CLID pair.
StatusCode remove(const void *pObject)
Remove pObject, will remove its proxy if not reset only.
virtual void handle(const Incident &) override final
triggered by Incident service
SG::DataProxy * locatePersistent(const SG::TransientAddress *tAddr, bool checkValid=false) const
virtual std::vector< const SG::DataProxy * > proxies() const override final
return the list of all current proxies in store
StatusCode setAlias(CLID clid, const std::string &key, const std::string &aliasKey)
make an alias to a DataObject (provide data type and old key)
virtual SG::DataProxy * recordObject(SG::DataObjectSharedPtr< DataObject > obj, const std::string &key, bool allowMods, bool returnExisting) override final
Record an object in the store.
StatusCode loadEventProxies()
load proxies at begin event
void keys(const CLID &id, std::vector< std::string > &vkeys, bool includeAlias=false, bool onlyValid=true)
provide list of all StoreGate keys associated with an object.
SG::DataStore * store()
SG::RemapImpl * m_remap_impl
Definition SGImplSvc.h:706
int m_slotNumber
The Hive slot number for this store, or -1 if this isn't a Hive store.
Definition SGImplSvc.h:712
ServiceHandle< IProxyProviderSvc > m_pPPSHandle
Definition SGImplSvc.h:681
virtual StatusCode finalize() override final
Service finalization.
std::map< std::thread::id, std::vector< IResetable * > > m_newBoundHandles
Keep track of proxies bound since the last call to commitNewDataObjects or clearStore.
Definition SGImplSvc.h:721
virtual SG::SourceID sourceID(const std::string &key="EventSelector") const override
Return the metadata source ID for the current event slot.
StatusCode setConst(const void *pointer)
prevent downstream clients from modifying the pointed-at dobj
virtual StatusCode createObj(IConverter *cvt, IOpaqueAddress *addr, DataObject *&refpObject) override
Call converter to create an object, with locking.
std::vector< CLID > clids(const std::string &key) const
Retrieve all the CLID s (including symlinks) of the object recorded in StoreGate with the given "key"...
bool m_DumpStore
Dump Property flag: triggers dump() at EndEvent.
Definition SGImplSvc.h:692
StatusCode regFcn(const CallBackID &c1, const CallBackID &c2, const IOVSvcCallBackFcn &fcn, bool trigger=false)
register a callback function(2) with an already registered function(1)
bool m_ActivateHistory
Activate the history service.
Definition SGImplSvc.h:693
CLID clid(const std::string &key) const
Retrieve the main CLID of the object recorded in StoreGate with the given "key" WARNING: slow!
void msg_update_handler(Gaudi::Details::PropertyBase &outputLevel)
callback for output level property
SG::StringPool m_stringpool
Definition SGImplSvc.h:704
virtual StatusCode start() override final
Service start.
mutex_t m_mutex
Definition SGImplSvc.h:725
std::string createKey(const CLID &dataID)
creates a key internally if none specified by client
bool m_DumpArena
DumpArena Property flag : trigger m_arena->report() at clearStore.
Definition SGImplSvc.h:694
StatusCode removeProxy(SG::DataProxy *proxy, const void *pTrans, bool forceRemove=false)
remove proxy from store, unless it is reset only.
StoreID::type storeID() const
get store ID. request forwarded to DataStore:
StatusCode proxyRange(const CLID &id, SG::ConstProxyIterator &beg, SG::ConstProxyIterator &end) const
return a range to all proxies of a given CLID
bool bindHandleToProxyAndRegister(const CLID &id, const std::string &key, IResetable *ir, SG::DataProxy *&dp)
Also do registration with IOVSvc.
void remap_impl(sgkey_t source, sgkey_t target, off_t index_offset)
Declare a remapping.
virtual void registerKey(sgkey_t key, const std::string &str, CLID clidid) override final
Remember an additional mapping from key to string/CLID.
StatusCode addSymLink(const CLID &linkid, SG::DataProxy *dp)
SG::Arena m_arena
Allocation arena to associate with this store.
Definition SGImplSvc.h:709
virtual StatusCode clearStore(bool forceRemove=false) override final
clear DataStore contents: called by the event loop mgrs
bool isSymLinked(const CLID &linkID, SG::DataProxy *dp)
bool bindHandleToProxy(const CLID &id, const std::string &key, IResetable *ir, SG::DataProxy *&dp)
name says it all
std::lock_guard< mutex_t > lock_t
Definition SGImplSvc.h:724
IProxyProviderSvc * m_pPPS
Definition SGImplSvc.h:684
virtual void commitNewDataObjects() override final
Reset handles added since the last call to commit.
int typeCount(const CLID &id) const
Return the number of instances of type T (input CLID)
virtual StatusCode stop() override final
Service stop.
void t2pRemove(const void *const pTrans)
forwarded to DataStore
virtual StatusCode addToStore(CLID id, SG::DataProxy *proxy) override final
Raw addition of a proxy to the store.
SG::DataStore * m_pStore
Definition SGImplSvc.h:688
StatusCode recordAddress(const std::string &skey, CxxUtils::RefCountedPtr< IOpaqueAddress > pAddress, bool clearAddressFlag=true)
Create a proxy object using an IOpaqueAddress and a transient key.
StatusCode record_HistObj(const CLID &id, const std::string &key, const std::string &store, bool allowMods, bool resetOnly=true)
virtual const std::string * keyToString(sgkey_t key) const override final
Find the string corresponding to a given key.
void clearProxyPayload(SG::DataProxy *)
use to reset a proxy (clearing the data object it contains) Unlike DataProxy::reset this method corre...
StatusCode removeDataAndProxy(const void *pObject)
Remove pObject and its proxy no matter what.
mutex_t m_stringPoolMutex
Definition SGImplSvc.h:727
SG::DataProxy * setupProxy(const CLID &dataID, const std::string &gK, DataObject *pDObj, bool allowMods, bool resetOnly)
try to locate a proxy or create it if needed
std::vector< CLID > clids() const
Return all CLIDs in the store.
std::list< DataObject * > m_trash
The Recycle Bin.
Definition SGImplSvc.h:689
ServiceHandle< IHistorySvc > m_pHistorySvc
Definition SGImplSvc.h:686
void releaseObject(const CLID &id, const std::string &key)
release object held by proxy, if any.
IStringPool::sgkey_t sgkey_t
Definition SGImplSvc.h:354
ServiceHandle< IIOVSvc > m_pIOVSvc
get the IOVSvc "just in time" (breaks recursion at initialize)
Definition SGImplSvc.h:700
void makeCurrent()
The current store is becoming the active store.
SGImplSvc(const SGImplSvc &)=delete
int m_numSlots
The total number of slots. 1 if this isn't a Hive store.
Definition SGImplSvc.h:715
bool mergeStringPool(const SGImplSvc &other)
Merge the string pool from another store into this one.
DataObject * accessData(const CLID &id) const
find proxy and access its data. Returns 0 to flag failure
void recycle(DataObject *pBadDObj)
put a bad (unrecordable) dobj away
virtual StatusCode reinitialize() override final
Service reinitialization.
bool m_storeLoaded
FIXME hack needed by loadEventProxies.
Definition SGImplSvc.h:702
virtual SG::DataProxy * proxy_exact(SG::sgkey_t sgkey) const override final
Get proxy given a hashed key+clid.
ServiceHandle< IClassIDSvc > m_pCLIDSvc
Definition SGImplSvc.h:678
bool transientContains(const CLID id, const std::string &key) const
Look up a transient data object in TDS only by CLID.
ServiceHandle< IIncidentSvc > m_pIncSvc
property
Definition SGImplSvc.h:691
std::string dump() const
dump objects in store.
StatusCode addAlias(const std::string &aliasKey, SG::DataProxy *dp)
bool contains(const CLID id, const std::string &key) const
Look up a keyed object in TDS by CLID.
bool transientSwap(const CLID &id, const std::string &keyA, const std::string &keyB)
swap the content of 2 keys payload A indexed by keyA will now be accessed via keyB and vice versa Not...
mutex_t m_remapMutex
Definition SGImplSvc.h:726
void setSlotNumber(int slot, int numSlots)
Set the Hive slot number for this store.
StatusCode retrieve(CLID clid, SG::detail::IteratorBase &cibegin, SG::detail::IteratorBase &ciend) const
Retrieve all objects of type T: returns an SG::ConstIterator range.
virtual void unboundHandle(IResetable *handle) override final
Tell the store that a handle has been unbound from a proxy.
SG::DataProxy * transientProxy(const CLID &id, const std::string &key) const
get proxy with given id and key.
bool associateAux_impl(SG::AuxVectorBase *ptr, const std::string &key, CLID auxclid) const
virtual StatusCode initialize() override final
Service initialization.
StatusCode typeless_overwrite(const CLID &id, DataObject *obj, const std::string &key, const void *const raw_ptr, bool allowMods, bool noHist=false, const std::type_info *tinfo=0)
same as typeless_record, allows to overwrite an object in memory or on disk
SG::DataProxy * record_impl(DataObject *obj, const std::string &key, const void *const raw_ptr, bool allowMods, bool resetOnly, bool allowOverwrite, const std::type_info *tinfo)
real recording of an object with a key, allow possibility of specifying const-access
void emptyTrash()
throw away bad objects
ServiceHandle< IConversionSvc > m_pDataLoader
Definition SGImplSvc.h:679
Proxy for a group of Arenas.
Definition ArenaHeader.h:54
static ArenaHeader * defaultHeader()
Return the global default Header instance.
Base class for elements of a container that can have aux data.
Definition AuxElement.h:483
Manage index tracking and synchronization of auxiliary data.
The non-template portion of the BaseInfo implementation.
static const BaseInfoBase * find(CLID clid)
Find the BaseInfoBase instance for clid.
Definition BaseInfo.cxx:570
const std::vector< CLID > & get_bases() const
Return the class IDs of all known bases of T (that have class IDs).
Definition BaseInfo.cxx:304
std::vector< CLID > get_copy_conversions() const
Return known copy conversions.
Definition BaseInfo.cxx:455
static IProxyDict * setStore(IProxyDict *store)
Set the current store.
bool transientID(CLID id) const
return the list of transient IDs (primary or symLinked):
void reset(bool hard=false)
Other methods of DataProxy (not in Interface IRegistry):
DataObject * accessData()
Access DataObject on-demand using conversion service.
TransientAddress::TransientClidSet CLIDCont_t
Definition DataProxy.h:54
Hold DataProxy instances associated with a store.
int typeCount(const CLID &id) const
Count number of object of a given type in store.
StatusCode tRange(ConstStoreIterator &f, ConstStoreIterator &e) const
Return an iterator over the StoreMap:
virtual StoreID::type storeID() const override
void keys(const CLID &id, std::vector< std::string > &vkeys, bool includeAlias, bool onlyValid)
StoreMap::const_iterator ConstStoreIterator
void setStoreID(StoreID::type id)
const std::vector< DataProxy * > & proxies() const
All proxies managed by this store.
Interface for non-const operations on an auxiliary store.
Definition IAuxStore.h:48
Interface for const operations on an auxiliary store.
a StoreGateSvc key with a version number.
unsigned char version() const
static bool isVersionedKey(const char *)
quickly determine whether a string has the right format to be a VK
const std::string & rawVersionKey() const
static bool isAuto(const std::string &)
quickly determine whether a string has the right format to be a VK with auto-generated version #
const std::string & key() const
Implementation class, not to be used directly Iterates over valid proxies it the range.
Definition SGIterator.h:37
StatusCode setState(SG::ConstProxyIterator itr, SG::ConstProxyIterator itrEnd, bool isConst)
Reset state of the iterator.
@ EVENT_STORE
Definition StoreID.h:26
@ DETECTOR_STORE
Definition StoreID.h:27
static StoreID::type findStoreID(const std::string &storeName)
Definition StoreID.cxx:21
int ir
counter of the current depth
Definition fastadd.cxx:49
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
bool verbose
Definition hcg.cxx:73
Forward declaration.
DATA * DataProxy_cast(DataProxy *proxy)
cast the proxy into the concrete data object it proxies
CxxUtils::RefCountedPtr< T > DataObjectSharedPtr
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition sgkey_t.h:32
ProxyMap::const_iterator ConstProxyIterator
Definition ProxyMap.h:24
DataObject * asStorable(SG::DataObjectSharedPtr< T > pObject)
std::unordered_map< sgkey_t, T > SGKeyMap
A map using sgkey_t as a key.
Definition sgkey_t.h:93
void * ptr(T *p)
Definition SGImplSvc.cxx:74
void print(std::FILE *stream, std::format_string< Args... > fmt, Args &&... args)
Definition SGImplSvc.cxx:70
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
SGKeyMap< remap_t > remap_map_t
Definition SGImplSvc.cxx:92
remap_map_t m_remaps
Definition SGImplSvc.cxx:93
IStringPool::sgkey_t sgkey_t
Definition SGImplSvc.cxx:86