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);
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;
358 setGaudiRef(dObject, dobj);
359 m_dObject = dobj;
360 if (0 != dobj) {
361 if (doreg) dobj->setRegistry(this);
362 if (m_const) this->lock (objLock);
363 }
364}
365
366
368void DataProxy::setObject(DataObject* dObject, bool doreg /*= true*/)
369{
370 objLock_t objLock (m_objMutex);
371 setObject (objLock, dObject, doreg);
372}
373
374
375// set IOpaqueAddress
376void DataProxy::setAddress(IOpaqueAddress* address)
377{
379 m_tAddress.setAddress(address);
380}
381
382// set IOpaqueAddress
388
389
390
403std::unique_ptr<DataObject> DataProxy::readData()
404{
405 // Public wrapper for readData().
406 objLock_t objLock (m_objMutex);
407 return readData (objLock, nullptr);
408}
409
410
422std::unique_ptr<DataObject> DataProxy::readData (objLock_t&, ErrNo* errNo)
423{
424 if (errNo) {
425 if (*errNo == RECURSIVEREAD) {
426 // This can end up being called from noexcept functions.
427 // Creating a MsgStream can throw an exception --- don't let
428 // it escape.
429 try {
430 MsgStream gLog(m_ims, "DataProxy");
431 gLog << MSG::ERROR
432 << "readData: ERROR recursive read for object"
433 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
434 <<" Returning NULL DataObject pointer " << endmsg;
435 }
436 catch (const GaudiException&) {
437 std::cerr << "DataProxy::readData: Problem creating MsgStream\n";
438 }
439 return nullptr;
440 }
442 }
443
444 IConverter* dataLoader;
446 IOpaqueAddress* address;
447 {
449 if (0 == m_dataLoader) {
450 //MsgStream gLog(m_ims, "DataProxy");
451 //gLog << MSG::WARNING
452 // << "accessData: IConverter ptr not set" <<endmsg;
453 if (errNo) *errNo=NOCNVSVC;
454 return nullptr;
455 }
456
457 dataLoader = m_dataLoader;
458 store = m_store;
459 address = m_tAddress.address();
460 }
461
462 if (!isValidAddress()) {
463 //MsgStream gLog(m_ims, "DataProxy");
464 //gLog << MSG::WARNING
465 // << "accessData: IOA pointer not set" <<endmsg;
466 if (errNo) *errNo=NOIOA;
467 return nullptr;
468 }
469
470 SG::CurrentEventStore::Push push (store);
471
472 DataObject* obj = nullptr;
473 StatusCode sc;
474 if (store)
475 sc = store->createObj (dataLoader, address, obj);
476 else
477 sc = dataLoader->createObj (address, obj);
478 if (sc.isSuccess()) {
479 if (errNo && *errNo == RECURSIVEREAD) *errNo = ALLOK;
480 return std::unique_ptr<DataObject>(obj);
481 }
482 if (!address) {
483 MsgStream gLog(m_ims, "DataProxy");
484 gLog << MSG::ERROR
485 << "readData: no address for " << clID() << "/" << name()
486 << " but validAddress returned true. You may be trying to retrieve"
487 << " alignments during initialization without having defined a campaign."
488 << endmsg;
489 }
490 if (errNo) *errNo = CNVFAILED;
491 return nullptr;
492}
493
494
497{
498 // This is done in the inlined accessData().
499 //if (0 != m_dObject) return m_dObject; // cached object
500
501 objLock_t objLock (m_objMutex);
502 // Check again after acquiring the lock.
503 if (0 != m_dObject) return m_dObject; // cached object
504
505 if (isValidAddress()) {
506 // An address provider called by isValidAddress may have set the object
507 // pointer directly, rather than filling in the address. So check
508 // the cached object pointer again.
509 if (0 != m_dObject) return m_dObject; // cached object
510 }
511
512 std::unique_ptr<DataObject> obju = readData (objLock, &m_errno);
513 if (!obju) {
514 if (m_errno == NOIOA) {
515 MsgStream gLog(m_ims, "DataProxy");
516 gLog << MSG::WARNING
517 << "accessData: IOA pointer not set" <<endmsg;
518 }
519 else if (m_errno == CNVFAILED) {
520 MsgStream gLog(m_ims, "DataProxy");
521 gLog << MSG::WARNING
522 << "accessData: conversion failed for data object "
523 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
524 <<" Returning NULL DataObject pointer " << endmsg;
525 }
526 setObject(objLock, 0, true);
527 return 0;
528 }
529
530 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(obju.get());
531 if (m_t2p) {
532 if (bucket) {
533 void* payload = bucket->object();
534 m_t2p->t2pRegister(payload, this);
535 m_errno=ALLOK;
536
537 // Register bases as well.
539 if (bi) {
540 std::vector<CLID> base_clids = bi->get_bases();
541 for (unsigned i=0; i < base_clids.size(); ++i) {
542 // nb. DataProxy_cast here will give an infinite recursion!
543 void* bobj = SG::Storable_cast (obju.get(), base_clids[i], nullptr, true);
544 if (bobj && bobj != payload)
545 m_t2p->t2pRegister (bobj, this);
546 }
547 }
548 }
549 else {
550 MsgStream gLog(m_ims, "DataProxy");
551 gLog << MSG::ERROR
552 << "accessData: ERROR registering object in t2p map"
553 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
554 <<" Returning NULL DataObject pointer " << endmsg;
555 obju.reset();
556 m_errno=T2PREGFAILED;
557 }
558 }
559
560 // Must get everything else set up before setting m_dObject, because
561 // once we set it, it's immediately visible to other threads.
562 // In particular, we were previously doing this before the t2p registration.
563 // This meant that another thread could retrieve the pointer from
564 // the proxy, but then fail trying to map the pointer back to the proxy.
565 // See ATEAM-1126.
566 std::atomic_thread_fence (std::memory_order_seq_cst);
567 setObject(objLock, obju.release(), true);
568
569 return m_dObject;
570}
571
572
573/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
575{
576 // Looking up the context is relatively expensive.
577 // So first try isValid() without the context.
578 {
580 if (const_cast<DataProxy*>(this)->m_tAddress.isValid(nullptr)) {
581 return true;
582 }
583 }
584 // Get the context. (Must not be holding m_mutex here.)
585 const EventContext& ctx = contextFromStore();
586 // Try again with the context.
588 return const_cast<DataProxy*>(this)->m_tAddress.isValid(&ctx);
589}
590
592{
593 // Be sure to get the context before acquiring the lock.
594 const EventContext& ctx = contextFromStore();
596 return m_tAddress.isValid(&ctx, true);
597}
598
608void* SG::DataProxy_cast (SG::DataProxy* proxy, CLID clid, const std::type_info* tinfo /*= nullptr*/)
609{
610 if (nullptr == proxy || !proxy->isValid()) {
611 return nullptr;
612 }
613
614 DataObject* pObject = proxy->accessData();
615 if (nullptr == pObject) {
616#ifndef NDEBUG
617 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
618 gLog << MSG::WARNING
619 << "this proxy " << MSG::hex << proxy
620 << MSG::dec << " has a NULL data object ptr" << endmsg;
621#endif
622 return nullptr;
623 }
624
625 void* result = SG::Storable_cast (pObject, clid, tinfo, true, proxy, proxy->isConst());
626 if (nullptr == result) {
627 //if result is null, probably CLID is neither the type the object was
628 // stored with, nor it inherits from it.
629 // Before giving up let's check its transient CLIDs
630 DataBucketBase* db(0);
631 if (proxy->transientID(clid) &&
632 nullptr != (db = dynamic_cast<DataBucketBase*>(pObject)) )
633 {
634 //it is a symlink after all. Let's hard cast and keep our fingers Xed
635 // But first: if this is a non-const proxy, then the cast
636 // may have failed because it needed to go via a copying conversion
637 // that's not allowed for non-const objects. So try the conversion
638 // again as const; if that works, then don't do the hard cast.
639 if (!proxy->isConst() &&
640 SG::Storable_cast(pObject, clid, tinfo, true, proxy, true) != nullptr)
641 {
642#ifndef NDEBUG
643 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
644 gLog << MSG::WARNING
645 << "Request for a non-const object via copying conversion; "
646 << "requested CLID = " << clid
647 << ", proxy primary ID is " << proxy->clID() << endmsg ;
648#endif
649 }
650 else {
651 // ok, hard cast.
652 result = db->object();
653 }
654 }
655 else {
656#ifndef NDEBUG
657 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
658 gLog << MSG::WARNING
659 << "Request for an invalid object; requested CLID = "
660 << clid
661 << ", proxy primary ID is " << proxy->clID() << endmsg ;
662#endif
663 } //try symlink
664 } //result 0
665
666 return result;
667}
668
669
675{
677 if (m_t2p)
678 m_t2p->t2pRegister (p, this);
679}
680
681
688{
689 DataObject* dobj = m_dObject;
690 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(dobj);
691 if (bucket)
692 bucket->lock();
693}
694
695
705const EventContext& DataProxy::contextFromStore() const
706{
708 if (store) {
709 static const SG::sgkey_t ctxkey =
710 store->stringToKey ("EventContext", ClassID_traits<EventContext>::ID());
711 SG::DataProxy* proxy = store->proxy_exact (ctxkey);
712 if (proxy && proxy->object()) {
713 EventContext* ctx = SG::DataProxy_cast<EventContext> (proxy);
714 if (ctx) return *ctx;
715 }
716 }
717 static const EventContext emptyContext;
718 return emptyContext;
719}
#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
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.
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: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.