ATLAS Offline Software
Loading...
Searching...
No Matches
DataProxy.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
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
520 if (isValidAddress()) {
521 // An address provider called by isValidAddress may have set the object
522 // pointer directly, rather than filling in the address. So check
523 // the cached object pointer again.
524 if (0 != m_dObject) return m_dObject; // cached object
525 }
526
527 std::unique_ptr<DataObject> obju = readData (objLock, &m_errno);
528 if (!obju) {
529 if (m_errno == NOIOA) {
530 MsgStream gLog(m_ims, "DataProxy");
531 gLog << MSG::WARNING
532 << "accessData: IOA pointer not set" <<endmsg;
533 }
534 else if (m_errno == CNVFAILED) {
535 MsgStream gLog(m_ims, "DataProxy");
536 gLog << MSG::WARNING
537 << "accessData: conversion failed for data object "
538 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
539 <<" Returning NULL DataObject pointer " << endmsg;
540 }
541 setObject(objLock, 0, true);
542 return 0;
543 }
544
545 DataObject* obj = obju.release();
546 setObject(objLock, obj, true);
547 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(obj);
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 void* bobj = SG::DataProxy_cast (this, base_clids[i]);
560 if (bobj && bobj != payload)
561 m_t2p->t2pRegister (bobj, this);
562 }
563 }
564 }
565 else {
566 MsgStream gLog(m_ims, "DataProxy");
567 gLog << MSG::ERROR
568 << "accessData: ERROR registering object in t2p map"
569 <<m_tAddress.clID() << '/' << m_tAddress.name() << '\n'
570 <<" Returning NULL DataObject pointer " << endmsg;
571 obj=0;
572 setObject(objLock, 0, true);
574 }
575 }
576
577 return obj;
578}
579
580
581/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
583{
584 // Looking up the context is relatively expensive.
585 // So first try isValid() without the context.
586 {
588 if (const_cast<DataProxy*>(this)->m_tAddress.isValid(nullptr)) {
589 return true;
590 }
591 }
592 // Get the context. (Must not be holding m_mutex here.)
593 const EventContext& ctx = contextFromStore();
594 // Try again with the context.
596 return const_cast<DataProxy*>(this)->m_tAddress.isValid(&ctx);
597}
598
600{
601 // Be sure to get the context before acquiring the lock.
602 const EventContext& ctx = contextFromStore();
604 return m_tAddress.isValid(&ctx, true);
605}
606
616void* SG::DataProxy_cast (SG::DataProxy* proxy, CLID clid, const std::type_info* tinfo /*= nullptr*/)
617{
618 if (nullptr == proxy || !proxy->isValid()) {
619 return nullptr;
620 }
621
622 DataObject* pObject = proxy->accessData();
623 if (nullptr == pObject) {
624#ifndef NDEBUG
625 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
626 gLog << MSG::WARNING
627 << "this proxy " << MSG::hex << proxy
628 << MSG::dec << " has a NULL data object ptr" << endmsg;
629#endif
630 return nullptr;
631 }
632
633 void* result = SG::Storable_cast (pObject, clid, tinfo, true, proxy, proxy->isConst());
634 if (nullptr == result) {
635 //if result is null, probably CLID is neither the type the object was
636 // stored with, nor it inherits from it.
637 // Before giving up let's check its transient CLIDs
638 DataBucketBase* db(0);
639 if (proxy->transientID(clid) &&
640 nullptr != (db = dynamic_cast<DataBucketBase*>(pObject)) )
641 {
642 //it is a symlink after all. Let's hard cast and keep our fingers Xed
643 // But first: if this is a non-const proxy, then the cast
644 // may have failed because it needed to go via a copying conversion
645 // that's not allowed for non-const objects. So try the conversion
646 // again as const; if that works, then don't do the hard cast.
647 if (!proxy->isConst() &&
648 SG::Storable_cast(pObject, clid, tinfo, true, proxy, true) != nullptr)
649 {
650#ifndef NDEBUG
651 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
652 gLog << MSG::WARNING
653 << "Request for a non-const object via copying conversion; "
654 << "requested CLID = " << clid
655 << ", proxy primary ID is " << proxy->clID() << endmsg ;
656#endif
657 }
658 else {
659 // ok, hard cast.
660 result = db->object();
661 }
662 }
663 else {
664#ifndef NDEBUG
665 MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast");
666 gLog << MSG::WARNING
667 << "Request for an invalid object; requested CLID = "
668 << clid
669 << ", proxy primary ID is " << proxy->clID() << endmsg ;
670#endif
671 } //try symlink
672 } //result 0
673
674 return result;
675}
676
677
683{
685 if (m_t2p)
686 m_t2p->t2pRegister (p, this);
687}
688
689
696{
697 DataObject* dobj = m_dObject;
698 DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(dobj);
699 if (bucket)
700 bucket->lock();
701}
702
703
713const EventContext& DataProxy::contextFromStore() const
714{
716 if (store) {
717 static const SG::sgkey_t ctxkey =
718 store->stringToKey ("EventContext", ClassID_traits<EventContext>::ID());
719 SG::DataProxy* proxy = store->proxy_exact (ctxkey);
720 if (proxy && proxy->object()) {
721 EventContext* ctx = SG::DataProxy_cast<EventContext> (proxy);
722 if (ctx) return *ctx;
723 }
724 }
725 static const EventContext emptyContext;
726 return emptyContext;
727}
#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.