ATLAS Offline Software
Loading...
Searching...
No Matches
DataProxy.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
6#include "SGTools/DataProxy.h"
10
11#include "GaudiKernel/DataObject.h"
12#include "GaudiKernel/IConverter.h"
13#include "GaudiKernel/GenericAddress.h"
14#include "GaudiKernel/MsgStream.h"
15#include "GaudiKernel/EventContext.h"
16#include "GaudiKernel/GaudiException.h"
17
19#include "SGTools/T2pMap.h"
24#include <algorithm>
25#include <cassert>
26#include <stdexcept>
27
28using SG::DataProxy;
30using std::find;
31
32
33namespace SG {
34 typedef IProxyDict** getDataSourcePointerFunc_t (const std::string&);
36
37 class DataProxyHolder
38 {
39 public:
40 static void resetCachedSource();
41 };
42}
43
44namespace {
45
46class PushStore
47{
48public:
49 PushStore (IProxyDict* store)
50 {
51 static std::string storeName = "StoreGateSvc";
52 m_storePtr = (*SG::getDataSourcePointerFunc) (storeName);
53 m_store = *m_storePtr;
54 if (store && store != m_store) {
55 *m_storePtr = store;
57 }
58 }
59
60 ~PushStore()
61 {
62 if (*m_storePtr != m_store) {
63 *m_storePtr = m_store;
65 }
66 }
67
68private:
69 IProxyDict** m_storePtr;
70 IProxyDict* m_store;
71};
72
73}
74
75
76namespace {
78 template <class GAUDIREF>
79 void setGaudiRef(GAUDIREF* pgref, GAUDIREF*& pMember) {
80 if (0 != pgref) pgref->addRef();
81 if (0 != pMember) pMember->release();
82 pMember = pgref;
83 }
84
86 template <class GAUDIREF>
87 void resetGaudiRef(GAUDIREF*& pMember) { setGaudiRef((GAUDIREF*)0, pMember); }
88
89} //end of unnamed namespace
90
91// Default Constructor
93 m_refCount(0),
94 m_resetFlag(true),
95 m_boundHandles(false),
96 m_const(false),
97 m_origConst(false),
98 m_dObject(nullptr),
99 m_dataLoader(nullptr),
100 m_t2p(nullptr),
101 m_store(nullptr),
103{
104}
105
106// DataProxy constructor with Transient Address
107// (typically called from Proxy Provider)
109 IConverter* svc,
110 bool constFlag, bool resetOnly)
111 : DataProxy (std::move(*tAddr),
112 svc, constFlag, resetOnly)
113{
114 delete tAddr;
115}
116
117// DataProxy constructor with Transient Address
118// (typically called from Proxy Provider)
119DataProxy::DataProxy(std::unique_ptr<TransientAddress> tAddr,
120 IConverter* svc,
121 bool constFlag, bool resetOnly)
122 : DataProxy (std::move(*tAddr), svc, constFlag, resetOnly)
123{
124 //assert( tAddr->clID() != 0 );
125 if (svc) svc->addRef();
126}
127
129 IConverter* svc,
130 bool constFlag, bool resetOnly):
131 m_refCount(0),
133 m_boundHandles(false),
134 m_const(constFlag),
135 m_origConst(constFlag),
136 m_dObject(0),
137 m_tAddress(std::move(tAddr)),
138 m_dataLoader(svc),
139 m_t2p(nullptr),
140 m_store(nullptr),
142{
143 //assert( tAddr->clID() != 0 );
144 if (svc) svc->addRef();
145}
146
147// with Data Object:
148// (typically called from a StoreGate record
149DataProxy::DataProxy(DataObject* dObject,
150 TransientAddress* tAddr,
151 bool constFlag, bool resetOnly):
152 m_refCount(0),
154 m_boundHandles(false),
155 m_const(constFlag),
156 m_origConst(constFlag),
157 m_dObject(0),
158 m_tAddress(std::move(*tAddr)),
159 m_dataLoader(nullptr),
160 m_t2p(nullptr),
161 m_store(nullptr),
163{
164 setObject(dObject);
165 delete tAddr;
166}
167
168DataProxy::DataProxy(DataObject* dObject,
169 TransientAddress&& tAddr,
170 bool constFlag, bool resetOnly):
171 m_refCount(0),
173 m_boundHandles(false),
174 m_const(constFlag),
175 m_origConst(constFlag),
176 m_dObject(0),
177 m_tAddress(std::move(tAddr)),
178 m_dataLoader(nullptr),
179 m_t2p(nullptr),
180 m_store(nullptr),
182{
183 setObject(dObject);
184}
185
186// Destructor
191
193{
195 m_t2p = t2p;
196}
197
198
206{
207 objLock_t objLock (m_objMutex);
209 if (!m_const) {
210 m_const = true;
211 this->lock (objLock);
212 }
213}
214
216 assert(ir);
218 if (ir->isSet()) {
219 return false;
220 } else {
221 m_handles.push_back(ir);
222 m_boundHandles = true;
223 if (IProxyDict* store = m_store)
224 store->boundHandle(ir);
225 return true;
226 }
227}
228
229
232{
233 DataObject* dobj = m_dObject;
234 resetGaudiRef(dobj);
235 m_dObject = dobj;
236 m_tAddress.reset();
238}
239
240
241void DataProxy::reset (bool hard /*= false*/)
242{
243 resetBoundHandles (hard);
244
245 objLock_t objLock (m_objMutex);
247 resetRef();
248}
249
250
252{
253 handleList_t handles;
254 {
255 objLock_t objLock (m_objMutex);
257 m_const=false; //hack to force the resetting of proxy ptr in VarHandleBase
258
259 handles = m_handles;
260
261 DataObject* dobj = m_dObject;
262 resetGaudiRef(dobj);
263 m_dObject = dobj;
264 resetGaudiRef(m_dataLoader);
265
266 if (m_handles.empty()) {
267 m_boundHandles = false;
268 }
269 }
270
271 for (auto ih: handles) {
272 if (0 != ih) ih->finalReset();
273 }
274}
275
278 handleList_t handles;
279 {
281 // Early exit if the list is empty.
282 if (!m_boundHandles) return;
283
284 // Make a copy and drop the lock, so we're not holding the lock
285 // during the callback.
286 handles = m_handles;
287 }
288
289 for (IResetable* h : handles) {
290 h->reset(hard);
291 }
292}
293
295 assert(ir);
297 auto ifr = find(m_handles.begin(), m_handles.end(), ir );
298 if (ifr != m_handles.end()) {
299 m_handles.erase(ifr);
300 if (IProxyDict* store = m_store)
301 store->unboundHandle(ir);
302 }
303 m_boundHandles = !m_handles.empty();
304}
305
307unsigned long DataProxy::refCount() const
308{
310 return m_refCount;
311}
312
314unsigned long DataProxy::addRef()
315{
317 return ++m_refCount;
318}
319
321unsigned long DataProxy::release()
322{
323 unsigned long count;
324 {
326 count = --m_refCount;
327 }
328 if ( 0 == count ) delete this;
329 return count;
330}
331
332
354bool DataProxy::requestRelease(bool force, bool hard) {
355
356 if (m_boundHandles) {
357 resetBoundHandles(hard);
358 }
359 bool canRelease = force;
360 if (!m_resetFlag) canRelease = true;
361#ifndef NDEBUG
362 MsgStream gLog(m_ims, "DataProxy");
363 if (gLog.level() <= MSG::VERBOSE) {
364 gLog << MSG::VERBOSE << "requestRelease(): "
365 << (canRelease ? " release " : " reset")
366 <<" object "
367 << name() << " CLID " << clID() << " address " << MSG::hex
368 << object() << MSG::dec << endmsg;
369 }
370#endif
371 if (!canRelease) {
372 resetRef();
373 }
374 return canRelease;
375}
376
380void DataProxy::setObject(objLock_t& objLock, DataObject* dObject, bool doreg)
381{
382 DataObject* dobj = m_dObject;
383 setGaudiRef(dObject, dobj);
384 m_dObject = dobj;
385 if (0 != dobj) {
386 if (doreg) dobj->setRegistry(this);
387 if (m_const) this->lock (objLock);
388 }
389}
390
391
393void DataProxy::setObject(DataObject* dObject, bool doreg /*= true*/)
394{
395 objLock_t objLock (m_objMutex);
396 setObject (objLock, dObject, doreg);
397}
398
399
400// set IOpaqueAddress
401void DataProxy::setAddress(IOpaqueAddress* address)
402{
404 m_tAddress.setAddress(address);
405}
406
407// set IOpaqueAddress
413
414
415
428std::unique_ptr<DataObject> DataProxy::readData()
429{
430 // Public wrapper for readData().
431 objLock_t objLock (m_objMutex);
432 return readData (objLock, nullptr);
433}
434
435
447std::unique_ptr<DataObject> DataProxy::readData (objLock_t&, ErrNo* errNo)
448{
449 if (errNo) {
450 if (*errNo == RECURSIVEREAD) {
451 // This can end up being called from noexcept functions.
452 // Creating a MsgStream can throw an exception --- don't let
453 // it escape.
454 try {
455 MsgStream gLog(m_ims, "DataProxy");
456 gLog << MSG::ERROR
457 << "readData: ERROR recursive read for object"
458 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
459 <<" Returning NULL DataObject pointer " << endmsg;
460 }
461 catch (const GaudiException&) {
462 std::cerr << "DataProxy::readData: Problem creating MsgStream\n";
463 }
464 return nullptr;
465 }
467 }
468
469 IConverter* dataLoader;
471 IOpaqueAddress* address;
472 {
474 if (0 == m_dataLoader) {
475 //MsgStream gLog(m_ims, "DataProxy");
476 //gLog << MSG::WARNING
477 // << "accessData: IConverter ptr not set" <<endmsg;
478 if (errNo) *errNo=NOCNVSVC;
479 return nullptr;
480 }
481
482 dataLoader = m_dataLoader;
483 store = m_store;
484 address = m_tAddress.address();
485 }
486
487 if (!isValidAddress()) {
488 //MsgStream gLog(m_ims, "DataProxy");
489 //gLog << MSG::WARNING
490 // << "accessData: IOA pointer not set" <<endmsg;
491 if (errNo) *errNo=NOIOA;
492 return nullptr;
493 }
494
496
497 DataObject* obj = nullptr;
498 StatusCode sc;
499 if (store)
500 sc = store->createObj (dataLoader, address, obj);
501 else
502 sc = dataLoader->createObj (address, obj);
503 if (sc.isSuccess()) {
504 if (errNo && *errNo == RECURSIVEREAD) *errNo = ALLOK;
505 return std::unique_ptr<DataObject>(obj);
506 }
507 if (errNo) *errNo = CNVFAILED;
508 return nullptr;
509}
510
511
514{
515 // This is done in the inlined accessData().
516 //if (0 != m_dObject) return m_dObject; // cached object
517
518 objLock_t objLock (m_objMutex);
519 // Check again after acquiring the lock.
520 if (0 != m_dObject) return m_dObject; // cached object
521
522 if (isValidAddress()) {
523 // An address provider called by isValidAddress may have set the object
524 // pointer directly, rather than filling in the address. So check
525 // the cached object pointer again.
526 if (0 != m_dObject) return m_dObject; // cached object
527 }
528
529 std::unique_ptr<DataObject> obju = readData (objLock, &m_errno);
530 if (!obju) {
531 if (m_errno == NOIOA) {
532 MsgStream gLog(m_ims, "DataProxy");
533 gLog << MSG::WARNING
534 << "accessData: IOA pointer not set" <<endmsg;
535 }
536 else if (m_errno == CNVFAILED) {
537 MsgStream gLog(m_ims, "DataProxy");
538 gLog << MSG::WARNING
539 << "accessData: conversion failed for data object "
540 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
541 <<" Returning NULL DataObject pointer " << endmsg;
542 }
543 setObject(objLock, 0, true);
544 return 0;
545 }
546
547 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(obju.get());
548 if (m_t2p) {
549 if (bucket) {
550 void* payload = bucket->object();
551 m_t2p->t2pRegister(payload, this);
553
554 // Register bases as well.
556 if (bi) {
557 std::vector<CLID> base_clids = bi->get_bases();
558 for (unsigned i=0; i < base_clids.size(); ++i) {
559 // nb. DataProxy_cast here will give an infinite recursion!
560 void* bobj = SG::Storable_cast (obju.get(), base_clids[i], nullptr, true);
561 if (bobj && bobj != payload)
562 m_t2p->t2pRegister (bobj, this);
563 }
564 }
565 }
566 else {
567 MsgStream gLog(m_ims, "DataProxy");
568 gLog << MSG::ERROR
569 << "accessData: ERROR registering object in t2p map"
570 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
571 <<" Returning NULL DataObject pointer " << endmsg;
572 obju.reset();
574 }
575 }
576
577 // Must get everything else set up before setting m_dObject, because
578 // once we set it, it's immediately visible to other threads.
579 // In particular, we were previously doing this before the t2p registration.
580 // This meant that another thread could retrieve the pointer from
581 // the proxy, but then fail trying to map the pointer back to the proxy.
582 // See ATEAM-1126.
583 std::atomic_thread_fence (std::memory_order_seq_cst);
584 setObject(objLock, obju.release(), true);
585
586 return m_dObject;
587}
588
589
590/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
592{
593 // Looking up the context is relatively expensive.
594 // So first try isValid() without the context.
595 {
597 if (const_cast<DataProxy*>(this)->m_tAddress.isValid(nullptr)) {
598 return true;
599 }
600 }
601 // Get the context. (Must not be holding m_mutex here.)
602 const EventContext& ctx = contextFromStore();
603 // Try again with the context.
605 return const_cast<DataProxy*>(this)->m_tAddress.isValid(&ctx);
606}
607
609{
610 // Be sure to get the context before acquiring the lock.
611 const EventContext& ctx = contextFromStore();
613 return m_tAddress.isValid(&ctx, true);
614}
615
625void* SG::DataProxy_cast (SG::DataProxy* proxy, CLID clid, const std::type_info* tinfo /*= nullptr*/)
626{
627 if (nullptr == proxy || !proxy->isValid()) {
628 return nullptr;
629 }
630
631 DataObject* pObject = proxy->accessData();
632 if (nullptr == pObject) {
633#ifndef NDEBUG
634 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
635 gLog << MSG::WARNING
636 << "this proxy " << MSG::hex << proxy
637 << MSG::dec << " has a NULL data object ptr" << endmsg;
638#endif
639 return nullptr;
640 }
641
642 void* result = SG::Storable_cast (pObject, clid, tinfo, true, proxy, proxy->isConst());
643 if (nullptr == result) {
644 //if result is null, probably CLID is neither the type the object was
645 // stored with, nor it inherits from it.
646 // Before giving up let's check its transient CLIDs
647 DataBucketBase* db(0);
648 if (proxy->transientID(clid) &&
649 nullptr != (db = dynamic_cast<DataBucketBase*>(pObject)) )
650 {
651 //it is a symlink after all. Let's hard cast and keep our fingers Xed
652 // But first: if this is a non-const proxy, then the cast
653 // may have failed because it needed to go via a copying conversion
654 // that's not allowed for non-const objects. So try the conversion
655 // again as const; if that works, then don't do the hard cast.
656 if (!proxy->isConst() &&
657 SG::Storable_cast(pObject, clid, tinfo, true, proxy, true) != nullptr)
658 {
659#ifndef NDEBUG
660 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
661 gLog << MSG::WARNING
662 << "Request for a non-const object via copying conversion; "
663 << "requested CLID = " << clid
664 << ", proxy primary ID is " << proxy->clID() << endmsg ;
665#endif
666 }
667 else {
668 // ok, hard cast.
669 result = db->object();
670 }
671 }
672 else {
673#ifndef NDEBUG
674 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
675 gLog << MSG::WARNING
676 << "Request for an invalid object; requested CLID = "
677 << clid
678 << ", proxy primary ID is " << proxy->clID() << endmsg ;
679#endif
680 } //try symlink
681 } //result 0
682
683 return result;
684}
685
686
692{
694 if (m_t2p)
695 m_t2p->t2pRegister (p, this);
696}
697
698
705{
706 DataObject* dobj = m_dObject;
707 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(dobj);
708 if (bucket)
709 bucket->lock();
710}
711
712
722const EventContext& DataProxy::contextFromStore() const
723{
725 if (store) {
726 static const SG::sgkey_t ctxkey =
727 store->stringToKey ("EventContext", ClassID_traits<EventContext>::ID());
728 SG::DataProxy* proxy = store->proxy_exact (ctxkey);
729 if (proxy && proxy->object()) {
730 EventContext* ctx = SG::DataProxy_cast<EventContext> (proxy);
731 if (ctx) return *ctx;
732 }
733 }
734 static const EventContext emptyContext;
735 return emptyContext;
736}
#define endmsg
Helpers for retrieving the payload held by a DataProxy.
Assign a CLID to EventContext.
uint32_t CLID
The Class ID type.
static Double_t sc
Hold a pointer to the current event store.
Header file for AthHistogramAlgorithm.
Simple smart pointer for Gaudi-style refcounted objects.
A non-templated base class for DataBucket, allows to access the transient object address as a void*.
virtual void lock()=0
If the held object derives from ILockable, call lock() on it.
virtual void * object()=0
a resetable object (e.g.
Definition IResetable.h:15
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
Temporarily change the current store.
Manage DataProxy reference in ElementLink/DataLink.
static void resetCachedSource()
CLID clID() const
Retrieve clid.
void resetBoundHandles(bool hard)
reset the bound DataHandles If HARD is true, then the bound objects should also clear any data that d...
std::lock_guard< objMutex_t > objLock_t
Definition DataProxy.h:355
handleList_t m_handles
Definition DataProxy.h:333
virtual const name_type & name() const override final
Retrieve data object key == string.
unsigned int m_refCount
Definition DataProxy.h:306
ErrNo errNo() const
std::vector< IResetable * > handleList_t
list of bound DataHandles
Definition DataProxy.h:332
IConverter * m_dataLoader
Definition DataProxy.h:327
void setConst()
Mark this object as const.
DataObject * accessDataOol()
Out-of-line part of accessData().
bool requestRelease(bool force, bool hard)
Reset/release a proxy at the end of an event.
virtual void setAddress(IOpaqueAddress *ioa) override final
set an IOpaqueAddress
std::unique_ptr< DataObject > readData()
Read in a new copy of the object referenced by this proxy.
bool m_resetFlag
reset and not delete: default is true
Definition DataProxy.h:309
bool m_boundHandles
True if there are any bound handles.
Definition DataProxy.h:316
virtual void registerTransient(void *p) override final
Register a transient object in a t2p map.
virtual IOpaqueAddress * address() const override final
Retrieve IOpaqueAddress.
virtual unsigned long release() override final
release reference to object
void finalReset()
void reset(bool hard=false)
Other methods of DataProxy (not in Interface IRegistry):
void lock(objLock_t &)
Lock the data object we're holding, if any.
void setObject(DataObject *obj, bool doreg=true)
set DataObject If doreg is true, then call setRegistry to set the backpointer from obj to the proxt.
IProxyDict * store()
Return the store of which we're a part.
bool isValidAddress() const
is the address valid?
void resetRef()
Drop the reference to the data object.
enum ErrNo m_errno
errno-style error code for accessData
Definition DataProxy.h:350
TransientAddress m_tAddress
Definition DataProxy.h:325
void resetOnly(const bool &flag)
set the reset only flag: Clear Store will reset and not delete.
std::atomic< IProxyDict * > m_store
The store of which we are a part.
Definition DataProxy.h:347
Athena::IMessageSvcHolder m_ims
Definition DataProxy.h:344
std::atomic< DataObject * > m_dObject
Definition DataProxy.h:323
void setT2p(T2pMap *t2p)
void unbindHandle(IResetable *ir)
std::atomic< bool > m_const
Is the proxy currently const?
Definition DataProxy.h:319
unsigned long refCount() const
return refCount
virtual ~DataProxy()
bool m_origConst
Was the proxy created as const?
Definition DataProxy.h:321
bool bindHandle(IResetable *ir)
const EventContext & contextFromStore() const
Retrieve the EventContext saved in the owning store.
objMutex_t m_objMutex
Definition DataProxy.h:356
bool updateAddress()
std::lock_guard< mutex_t > lock_t
Definition DataProxy.h:341
mutex_t m_mutex
Definition DataProxy.h:342
virtual unsigned long addRef() override final
Add reference to object.
T2pMap * m_t2p
Definition DataProxy.h:329
int ir
counter of the current depth
Definition fastadd.cxx:49
singleton-like access to IMessageSvc via open function and helper
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:138
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
IMessageSvc * getMessageSvc(bool quiet=false)
Forward declaration.
DATA * DataProxy_cast(DataProxy *proxy)
cast the proxy into the concrete data object it proxies
T * Storable_cast(DataObject *pDObj, bool quiet=true, IRegisterTransient *irt=0, bool isConst=true)
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition sgkey_t.h:32
IProxyDict ** getDataSourcePointerFunc_t(const std::string &)
Definition DataProxy.cxx:34
getDataSourcePointerFunc_t * getDataSourcePointerFunc
STL namespace.