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
95
96// DataProxy constructor with Transient Address
97// (typically called from Proxy Provider)
99 IConverter* svc,
100 bool constFlag, bool resetOnly)
101 : DataProxy (std::move(*tAddr),
102 svc, constFlag, resetOnly)
103{
104 delete tAddr;
105}
106
107// DataProxy constructor with Transient Address
108// (typically called from Proxy Provider)
109DataProxy::DataProxy(std::unique_ptr<TransientAddress> tAddr,
110 IConverter* svc,
111 bool constFlag, bool resetOnly)
112 : DataProxy (std::move(*tAddr), svc, constFlag, resetOnly)
113{
114 //assert( tAddr->clID() != 0 );
115 if (svc) svc->addRef();
116}
117
119 IConverter* svc,
120 bool constFlag, bool resetOnly):
122 m_const(constFlag),
123 m_origConst(constFlag),
124 m_tAddress(std::move(tAddr)),
125 m_dataLoader(svc)
126{
127 //assert( tAddr->clID() != 0 );
128 if (svc) svc->addRef();
129}
130
131// with Data Object:
132// (typically called from a StoreGate record
133DataProxy::DataProxy(DataObject* dObject,
134 TransientAddress* tAddr,
135 bool constFlag, bool resetOnly):
137 m_const(constFlag),
138 m_origConst(constFlag),
139 m_tAddress(std::move(*tAddr))
140{
141 setObject(dObject);
142 delete tAddr;
143}
144
145DataProxy::DataProxy(DataObject* dObject,
146 TransientAddress&& tAddr,
147 bool constFlag, bool resetOnly):
149 m_const(constFlag),
150 m_origConst(constFlag),
151 m_tAddress(std::move(tAddr))
152{
153 setObject(dObject);
154}
155
156// Destructor
161
163{
165 m_t2p = t2p;
166}
167
168
176{
177 objLock_t objLock (m_objMutex);
179 if (!m_const) {
180 m_const = true;
181 this->lock (objLock, m_dObject);
182 }
183}
184
186 assert(ir);
188 if (ir->isSet()) {
189 return false;
190 } else {
191 m_handles.push_back(ir);
192 m_boundHandles = true;
193 if (IProxyDict* store = m_store)
194 store->boundHandle(ir);
195 return true;
196 }
197}
198
199
201inline
203{
204 // Skip calling resetGaudiRef for the case where the proxy has never
205 // been defererenced.
206 if (m_dObject) {
207 DataObject* dobj = m_dObject;
208 resetGaudiRef(dobj);
209 m_dObject = dobj;
210 }
211 m_tAddress.reset();
213}
214
215
216void DataProxy::reset (bool hard /*= false*/)
217{
218 resetBoundHandles (hard);
219
220 objLock_t objLock (m_objMutex);
222 resetRef();
223}
224
225
227{
228 handleList_t handles;
229 {
230 objLock_t objLock (m_objMutex);
232 m_const=false; //hack to force the resetting of proxy ptr in VarHandleBase
233
234 handles = m_handles;
235
236 DataObject* dobj = m_dObject;
237 resetGaudiRef(dobj);
238 m_dObject = dobj;
239 resetGaudiRef(m_dataLoader);
240
241 if (m_handles.empty()) {
242 m_boundHandles = false;
243 }
244 }
245
246 for (auto ih: handles) {
247 if (0 != ih) ih->finalReset();
248 }
249}
250
253 handleList_t handles;
254 {
256 // Early exit if the list is empty.
257 if (!m_boundHandles) return;
258
259 // Make a copy and drop the lock, so we're not holding the lock
260 // during the callback.
261 handles = m_handles;
262 }
263
264 for (IResetable* h : handles) {
265 h->reset(hard);
266 }
267}
268
270 assert(ir);
272 auto ifr = find(m_handles.begin(), m_handles.end(), ir );
273 if (ifr != m_handles.end()) {
274 m_handles.erase(ifr);
275 if (IProxyDict* store = m_store)
276 store->unboundHandle(ir);
277 }
278 m_boundHandles = !m_handles.empty();
279}
280
282unsigned long DataProxy::refCount() const
283{
285 return m_refCount;
286}
287
289unsigned long DataProxy::addRef()
290{
292 return ++m_refCount;
293}
294
296unsigned long DataProxy::release()
297{
298 unsigned long count;
299 {
301 count = --m_refCount;
302 }
303 if ( 0 == count ) delete this;
304 return count;
305}
306
307
329bool DataProxy::requestRelease(bool force, bool hard) {
330
331 if (m_boundHandles) {
332 resetBoundHandles(hard);
333 }
334 bool canRelease = force;
335 if (!m_resetFlag) canRelease = true;
336#if 0
337 MsgStream gLog(m_ims, "DataProxy");
338 if (gLog.level() <= MSG::VERBOSE) {
339 gLog << MSG::VERBOSE << "requestRelease(): "
340 << (canRelease ? " release " : " reset")
341 <<" object "
342 << name() << " CLID " << clID() << " address " << MSG::hex
343 << object() << MSG::dec << endmsg;
344 }
345#endif
346 if (!canRelease) {
347 resetRef();
348 }
349 return canRelease;
350}
351
355void DataProxy::setObject(objLock_t& objLock, DataObject* dObject, bool doreg)
356{
357 DataObject* dobj = m_dObject.exchange (nullptr);
358 std::atomic_thread_fence (std::memory_order_seq_cst);
359 setGaudiRef(dObject, dobj);
360 if (0 != dobj) {
361 if (doreg) dobj->setRegistry(this);
362 if (m_const) this->lock (objLock, dobj);
363 }
364 // Be sure the settings above happen before we set m_dObject.
365 // Otherwise other threads may be able to see the object before those
366 // settings have been made.
367 std::atomic_thread_fence (std::memory_order_seq_cst);
368 m_dObject = dobj;
369}
370
371
373void DataProxy::setObject(DataObject* dObject, bool doreg /*= true*/)
374{
375 objLock_t objLock (m_objMutex);
376 setObject (objLock, dObject, doreg);
377}
378
379
380// set IOpaqueAddress
381void DataProxy::setAddress(IOpaqueAddress* address)
382{
384 m_tAddress.setAddress(address);
385}
386
387// set IOpaqueAddress
393
394
395
408std::unique_ptr<DataObject> DataProxy::readData()
409{
410 // Public wrapper for readData().
411 objLock_t objLock (m_objMutex);
412 return readData (objLock, nullptr);
413}
414
415
427std::unique_ptr<DataObject> DataProxy::readData (objLock_t&, ErrNo* errNo)
428{
429 if (errNo) {
430 if (*errNo == RECURSIVEREAD) {
431 // This can end up being called from noexcept functions.
432 // Creating a MsgStream can throw an exception --- don't let
433 // it escape.
434 try {
435 MsgStream gLog(m_ims, "DataProxy");
436 gLog << MSG::ERROR
437 << "readData: ERROR recursive read for object"
438 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
439 <<" Returning NULL DataObject pointer " << endmsg;
440 }
441 catch (const GaudiException&) {
442 std::cerr << "DataProxy::readData: Problem creating MsgStream\n";
443 }
444 return nullptr;
445 }
447 }
448
449 IConverter* dataLoader;
451 IOpaqueAddress* address;
452 {
454 if (0 == m_dataLoader) {
455 //MsgStream gLog(m_ims, "DataProxy");
456 //gLog << MSG::WARNING
457 // << "accessData: IConverter ptr not set" <<endmsg;
458 if (errNo) *errNo=NOCNVSVC;
459 return nullptr;
460 }
461
462 dataLoader = m_dataLoader;
463 store = m_store;
464 address = m_tAddress.address();
465 }
466
467 if (!isValidAddress()) {
468 //MsgStream gLog(m_ims, "DataProxy");
469 //gLog << MSG::WARNING
470 // << "accessData: IOA pointer not set" <<endmsg;
471 if (errNo) *errNo=NOIOA;
472 return nullptr;
473 }
474
475 SG::CurrentEventStore::Push push (store);
476
477 DataObject* obj = nullptr;
478 StatusCode sc;
479 if (store)
480 sc = store->createObj (dataLoader, address, obj);
481 else
482 sc = dataLoader->createObj (address, obj);
483 if (sc.isSuccess()) {
484 if (errNo && *errNo == RECURSIVEREAD) *errNo = ALLOK;
485 return std::unique_ptr<DataObject>(obj);
486 }
487 if (!address) {
488 MsgStream gLog(m_ims, "DataProxy");
489 gLog << MSG::ERROR
490 << "readData: no address for " << clID() << "/" << name()
491 << " but validAddress returned true. You may be trying to retrieve"
492 << " alignments during initialization without having defined a campaign."
493 << endmsg;
494 }
495 if (errNo) *errNo = CNVFAILED;
496 return nullptr;
497}
498
499
502{
503 // This is done in the inlined accessData().
504 //if (0 != m_dObject) return m_dObject; // cached object
505
506 objLock_t objLock (m_objMutex);
507 // Check again after acquiring the lock.
508 if (0 != m_dObject) return m_dObject; // cached object
509
510 if (isValidAddress()) {
511 // An address provider called by isValidAddress may have set the object
512 // pointer directly, rather than filling in the address. So check
513 // the cached object pointer again.
514 if (0 != m_dObject) return m_dObject; // cached object
515 }
516
517 std::unique_ptr<DataObject> obju = readData (objLock, &m_errno);
518 if (!obju) {
519 if (m_errno == NOIOA) {
520 MsgStream gLog(m_ims, "DataProxy");
521 gLog << MSG::WARNING
522 << "accessData: IOA pointer not set" <<endmsg;
523 }
524 else if (m_errno == CNVFAILED) {
525 MsgStream gLog(m_ims, "DataProxy");
526 gLog << MSG::WARNING
527 << "accessData: conversion failed for data object "
528 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
529 <<" Returning NULL DataObject pointer " << endmsg;
530 }
531 setObject(objLock, 0, true);
532 return 0;
533 }
534
535 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(obju.get());
536 if (m_t2p) {
537 if (bucket) {
538 void* payload = bucket->object();
539 m_t2p->t2pRegister(payload, this);
540 m_errno=ALLOK;
541
542 // Register bases as well.
544 if (bi) {
545 std::vector<CLID> base_clids = bi->get_bases();
546 for (unsigned i=0; i < base_clids.size(); ++i) {
547 // nb. DataProxy_cast here will give an infinite recursion!
548 void* bobj = SG::Storable_cast (obju.get(), base_clids[i], nullptr, true);
549 if (bobj && bobj != payload)
550 m_t2p->t2pRegister (bobj, this);
551 }
552 }
553 }
554 else {
555 MsgStream gLog(m_ims, "DataProxy");
556 gLog << MSG::ERROR
557 << "accessData: ERROR registering object in t2p map"
558 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
559 <<" Returning NULL DataObject pointer " << endmsg;
560 obju.reset();
561 m_errno=T2PREGFAILED;
562 }
563 }
564
565 // Must get everything else set up before setting m_dObject, because
566 // once we set it, it's immediately visible to other threads.
567 // In particular, we were previously doing this before the t2p registration.
568 // This meant that another thread could retrieve the pointer from
569 // the proxy, but then fail trying to map the pointer back to the proxy.
570 // See ATEAM-1126.
571 std::atomic_thread_fence (std::memory_order_seq_cst);
572 setObject(objLock, obju.release(), true);
573
574 return m_dObject;
575}
576
577
578/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
580{
581 // Looking up the context is relatively expensive.
582 // So first try isValid() without the context.
583 {
585 if (const_cast<DataProxy*>(this)->m_tAddress.isValid(nullptr)) {
586 return true;
587 }
588 }
589 // Get the context. (Must not be holding m_mutex here.)
590 const EventContext& ctx = contextFromStore();
591 // Try again with the context.
593 return const_cast<DataProxy*>(this)->m_tAddress.isValid(&ctx);
594}
595
597{
598 // Be sure to get the context before acquiring the lock.
599 const EventContext& ctx = contextFromStore();
601 return m_tAddress.isValid(&ctx, true);
602}
603
613void* SG::DataProxy_cast (SG::DataProxy* proxy, CLID clid, const std::type_info* tinfo /*= nullptr*/)
614{
615 if (nullptr == proxy || !proxy->isValid()) {
616 return nullptr;
617 }
618
619 DataObject* pObject = proxy->accessData();
620 if (nullptr == pObject) {
621#ifndef NDEBUG
622 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
623 gLog << MSG::WARNING
624 << "this proxy " << MSG::hex << proxy
625 << MSG::dec << " has a NULL data object ptr" << endmsg;
626#endif
627 return nullptr;
628 }
629
630 void* result = SG::Storable_cast (pObject, clid, tinfo, true, proxy, proxy->isConst());
631 if (nullptr == result) {
632 //if result is null, probably CLID is neither the type the object was
633 // stored with, nor it inherits from it.
634 // Before giving up let's check its transient CLIDs
635 DataBucketBase* db(0);
636 if (proxy->transientID(clid) &&
637 nullptr != (db = dynamic_cast<DataBucketBase*>(pObject)) )
638 {
639 //it is a symlink after all. Let's hard cast and keep our fingers Xed
640 // But first: if this is a non-const proxy, then the cast
641 // may have failed because it needed to go via a copying conversion
642 // that's not allowed for non-const objects. So try the conversion
643 // again as const; if that works, then don't do the hard cast.
644 if (!proxy->isConst() &&
645 SG::Storable_cast(pObject, clid, tinfo, true, proxy, true) != nullptr)
646 {
647#ifndef NDEBUG
648 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
649 gLog << MSG::WARNING
650 << "Request for a non-const object via copying conversion; "
651 << "requested CLID = " << clid
652 << ", proxy primary ID is " << proxy->clID() << endmsg ;
653#endif
654 }
655 else {
656 // ok, hard cast.
657 result = db->object();
658 }
659 }
660 else {
661#ifndef NDEBUG
662 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
663 gLog << MSG::WARNING
664 << "Request for an invalid object; requested CLID = "
665 << clid
666 << ", proxy primary ID is " << proxy->clID() << endmsg ;
667#endif
668 } //try symlink
669 } //result 0
670
671 return result;
672}
673
674
680{
682 if (m_t2p)
683 m_t2p->t2pRegister (p, this);
684}
685
686
692void DataProxy::lock (objLock_t&, DataObject* dobj)
693{
694 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(dobj);
695 if (bucket)
696 bucket->lock();
697}
698
699
709const EventContext& DataProxy::contextFromStore() const
710{
712 if (store) {
713 static const SG::sgkey_t ctxkey =
714 store->stringToKey ("EventContext", ClassID_traits<EventContext>::ID());
715 SG::DataProxy* proxy = store->proxy_exact (ctxkey);
716 if (proxy && proxy->object()) {
717 EventContext* ctx = SG::DataProxy_cast<EventContext> (proxy);
718 if (ctx) return *ctx;
719 }
720 }
721 static const EventContext emptyContext;
722 return emptyContext;
723}
#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:587
const std::vector< CLID > & get_bases() const
Return the class IDs of all known bases of T (that have class IDs).
Definition BaseInfo.cxx:307
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 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.
TransientAddress m_tAddress
Definition DataProxy.h:325
void resetOnly(const bool &flag)
set the reset only flag: Clear Store will reset and not delete.
void lock(objLock_t &, DataObject *dobj)
Lock the data object we're holding, if any.
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:140
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
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
virtual void lock() override
Lock the container.
STL namespace.