ATLAS Offline Software
WriteDataReentrant.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
13 #undef NDEBUG
14 #include "WriteDataReentrant.h"
15 
16 #include <list>
17 #include <vector>
18 
20 #include "MyContObj.h"
21 #include "MapStringFloat.h"
23 
25 #include "StoreGate/WriteHandle.h"
26 #include "AthLinks/DataLink.h"
27 #include "AthLinks/ElementLink.h"
29 
32 
34 
36 {
38 
39  // If user did not set a key, use our own name. This cannot be done in the
40  // constructor as "DefaultName" is used during configurable generation (genconf).
41  if (m_dobjKey3.empty()) m_dobjKey3 = name();
43 
44  ATH_MSG_INFO ("in initialize()");
54  ATH_CHECK( m_dobjKeyArray.initialize() );
55 
56  m_testObject =
58  return StatusCode::SUCCESS;
59 }
60 
61 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
62 
63 StatusCode WriteDataReentrant::execute (const EventContext& ctx) const
64 {
65  //this example illustrates how to record objects into the StoreGate(SG)
66  //with and without providing a key
67  //It then covers the new DataLink class and its usage as a persistable
68  //reference among objects in the SG
69  //Finally it shows how to use symlinks to record an object using its
70  //concrete type and its base class(es).
71 
72  ATH_MSG_INFO ("in execute()");
73 
74  // For algorithms that produce new data objects like this one
75  // the SG works like a bulletin board: the algorithm posts the
76  // new object to the SG (optionally providing a "name" for it).
77  // The SG assigns a unique identifier to the object and puts it on display
78  // alongside others of the same type.
79  // At preset intervals all objects are removed from the board to make room
80  // for new ones and filed.
81 
82  // Part 1: Recording objects to SG
84  dobj = std::make_unique<MyDataObj>(1);
85 
86  //now we create a second MyDataObj instance...
87  //...try to record it as we did for the first. Since dobj2 is also a
88  //MyDataObj we expect to see an error
89  ATH_MSG_WARNING ("we expect an error message here");
90  EXPECT_EXCEPTION (std::runtime_error,
91  dobj = std::make_unique<MyDataObj>(2));
92  ATH_MSG_WARNING ("end of error message");
93 
94  //here we go again...
95  //... but this time we register the dobj3 using this algo name as key
96  auto dobj3 = SG::makeHandle (m_dobjKey3, ctx);
97  dobj3 = std::make_unique<MyDataObj>(3);
98 
100  if (m_testObject->refCount() != 1) std::abort();
101  ATH_CHECK( testobj.record (m_testObject) );
102  if (m_testObject->refCount() != 2) std::abort();
103 
104  // Writing an array of objects.
105  size_t i = 0;
108  ATH_CHECK( h.record (std::make_unique<MyDataObj> (i+100)) );
109  ++i;
110  }
111 
113 
114  // Part 2: storing collections in the SG
115 
118  cobj->reserve(10);
119  cobj->push_back (std::make_unique<MyContObj> (11.3, 132));
120  cobj->push_back (std::make_unique<MyContObj> (41.7, 291));
121 
122  // as above with a vector of integers
124  vFloat = std::make_unique<std::vector<float> >();
125  vFloat->push_back(1.0);
126  vFloat->push_back(2.0);
127  vFloat->push_back(3.0);
128 
130  ATH_CHECK( m.record (std::make_unique<MapStringFloat>()) );
131  (*m)["uno"]=1.0;
132  (*m)["due"]=2.0;
133 
135  //
136  // Part 3: Data Links
137  //
138  // Data links are persistable references. Typically they will replace
139  // pointers from one object in the event to another, hence they have
140  // the usual "pointer" syntax (op *, op ->, op !, ...)
141  // (to be pedantic they have the moniker syntax as they don't define ++, --)
142  // For example in Atlfast::Cell
143  // class Cell {
144  // ...
145  // private:
146  // std::vector<const HepMC::Particle*> m_particles;
147  // };
148  // m_particles would become
149  // std::vector<HepMCLink<Particle>::type > m_particles;
150  //
151  // To understand data links it is important to observe that the SG
152  // is not able to identify every single object in the event.
153  // In particular individual elements of a container (the MyContObj
154  // in the vector above or the Particles in McEventCollection) are not
155  // recorded individually into SG, only their owner (the container) is.
156  // For this reason data links are supported by two class templates:
157  // DataLink<DATAOBJ> is a link to a data object i.e. an object
158  // identified by SG
159  // ElementLink<CONTAINER> is a link to an element of a container (which
160  // in turn is a SG data object)
161  // To make a DataLink persistable we need to provide its SG identifier
162  // (its type and key).
163  // To make an ElementLink persistable we need two pieces of information:
164  // i) the SG identifier (type/key) of the data object owning the element
165  // ii) the identifier of the contained object within the owner
166  // For example when we write out a link to the third element of
167  // our vector<float> we want to write the SG id of the vector
168  // and the index (2) of the element in the vector
169  //
170  // Since the indexing mechanism of a container depends on the container
171  // type we need to specialize ElementLink for different containers
172  // Elements of STL sequences (lists, vectors, deques but also DataVector
173  // and DataList) are dealt with automatically.
174  // For other STL or STL-like containers, the data object designer (or the
175  // client must "help" ElementLink identifying the type of container
176  // Three macros in the header StoreGate/DeclareIndexingPolicy.h
177  // are provided to this end:
178  // for sequences use CONTAINER_IS_SEQUENCE( MySequence )
179  // for sets use CONTAINER_IS_SET( MySet )
180  // for maps and related containers use CONTAINER_IS_MAP( MyMap )
181  //
182  // It is also possible to define custom specializations of ElementLink
183  // for custom containers (e.g. GenParticleLink for McEventCollection).
184  //
185  //Enough! Let's now create our first DataLink. It refers to the first
186  // MyDataObj we recorded. DataLink constructors use references
187  // as input arguments
188  //
189  // DataLink referring to a storable object
190  //
191  DataLink<MyDataObj> dobjLink(*dobj);
192  //since dobj is identifiable in the SG a reference to it is all we need
193 
195  dobj2 = std::make_unique<MyDataObj> (2);
196 
197  //Otherwise one could first create an empty link
198  DataLink<MyDataObj> dobjLink2;
199  //and later on set it to refer to its target
200  dobjLink2.toStorableObject(*dobj2);
201 
202 
203  // Added Aug 30, 2001 HMA
204  // DataLink made from a key. This should work for either an object
205  // already registered in the store, or an object that has a
206  // persistency for it. we use dobj3, which is an object registered with
207  // a key.
208 
209  DataLink<MyDataObj> dobjLink3(name());
210  // now access it. DataLink will do a retrieve to get it from the store.
211  (void)dobjLink3.cptr();
212 
213  //
214  // ElementLinks referring to contained objects
215  //
216  typedef ElementLink<std::vector<float> > VecElemLink;
217 
218 
219  VecElemLink thirdElementLink(*vFloat, 2); //THIS CRASHES SUN CC
220 
221  //sometimes we would not know the index of the element we want to refer to
222 
223  //reference to an element of the vector
224  float& anElement = vFloat->operator[](0);
225 
226  //starting from an empty link
227  VecElemLink aLink;
228  //we can refer it to its target without knowing its index
229  aLink.toContainedElement(*vFloat, anElement);
230  //it is better though to remember that toContainedElement for an
231  //ElementLink performs a linear search of "anElement" into "vFloat".
232  // If vFloat has a million elements think twice before using
233  // toContainedElement!
234 
236  pLinkList = std::make_unique<std::list<VecElemLink> >();
237  pLinkList->push_back(aLink);
238  pLinkList->push_back(thirdElementLink);
239 
240  //
241  // Part 3b: create a vector of links to the elements of the map above
242  //
243  typedef ElementLink<MapStringFloat> MapElemLink;
245  linkVector = std::make_unique<std::vector<MapElemLink> >();
246  linkVector->push_back(MapElemLink(*m, "uno"));
247  MapElemLink mLink;
248  mLink.toContainedElement(*m, (*m)["due"]);
249  linkVector->push_back(mLink);
250 
251  // Part 4
252  // make a link to dobj as its base class after it has been registered
253  // this allows later to retrieve different concrete types as a common ABC
254 
255  const BaseClass * pDO = 0;
256  if ( (evtStore()->symLink(dobj.cptr(), pDO)).isFailure() ) {
257  ATH_MSG_ERROR (" could not make link to BaseClass");
258  return( onError() );
259  }
260 
261  // make a link as its base class, with the same name
262  if ( ( evtStore()->symLink(dobj3.cptr(), pDO)).isFailure() ) {
263  ATH_MSG_ERROR (" could not make link to BaseClass");
264  return( onError() );
265  }
266 
267  // Part 5
268  // finally dump the structure of the StoreGate before returning
269  ATH_MSG_INFO (" registered all data objects");
270  ATH_MSG_INFO (" StoreGate structure before returning from execute \n"
271  << evtStore()->dump());
272 
273  return StatusCode::SUCCESS;
274 }
275 
276 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
277 
279 {
280  ATH_MSG_ERROR ("Dumping StoreGate after error occurred\n"
281  << evtStore()->dump());
282  return StatusCode::FAILURE;
283 }
284 
WriteDataReentrant::m_cobjKey
SG::WriteHandleKey< DataVector< MyContObj > > m_cobjKey
Definition: WriteDataReentrant.h:40
StoreGateExample_ClassDEF.h
WriteDataReentrant.h
Testing reentrant algorithms.
WriteDataReentrant::initialize
virtual StatusCode initialize() override final
Definition: WriteDataReentrant.cxx:35
WriteDataReentrant::execute
virtual StatusCode execute(const EventContext &ctx) const override final
Definition: WriteDataReentrant.cxx:63
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
WriteDataReentrant::m_vFloatKey
SG::WriteHandleKey< std::vector< float > > m_vFloatKey
Definition: WriteDataReentrant.h:41
MyContObj.h
make_unique
std::unique_ptr< T > make_unique(Args &&... args)
Definition: SkimmingToolEXOT5.cxx:23
WriteDataReentrant::m_linkVectorKey
SG::WriteHandleKey< std::vector< ElementLink< MapStringFloat > > > m_linkVectorKey
Definition: WriteDataReentrant.h:44
EXPECT_EXCEPTION
#define EXPECT_EXCEPTION(EXC, CODE)
Helper to check that an exception is thrown.
Definition: expect_exception.h:33
SG::WriteHandle::cptr
const_pointer_type cptr() const
Dereference the pointer.
TestDataObject
Definition: MyDataObj.h:35
WriteDataReentrant::m_pLinkListKey
SG::WriteHandleKey< std::list< ElementLink< std::vector< float > > > > m_pLinkListKey
Definition: WriteDataReentrant.h:43
SG::VarHandleKey::empty
bool empty() const
Test if the key is blank.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:150
WriteDataReentrant::m_dobjKey3
SG::WriteHandleKey< MyDataObj > m_dobjKey3
Definition: WriteDataReentrant.h:39
WriteDataReentrant::m_testObject
SG::DataObjectSharedPtr< TestDataObject > m_testObject
Definition: WriteDataReentrant.h:49
run_Egamma1_LArStrip_Fex.dump
dump
Definition: run_Egamma1_LArStrip_Fex.py:87
WriteDataReentrant::onError
StatusCode onError() const
Definition: WriteDataReentrant.cxx:278
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:274
AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
WriteDataReentrant::m_dobjKey
SG::WriteHandleKey< MyDataObj > m_dobjKey
Definition: WriteDataReentrant.h:37
WriteHandle.h
Handle class for recording to StoreGate.
MapStringFloat.h
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
SG::WriteHandleKey< MyDataObj >
lumiFormat.i
int i
Definition: lumiFormat.py:85
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
BaseClass
Definition: HiveDataObj.h:12
extractSporadic.h
list h
Definition: extractSporadic.py:96
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
MyDataObj.h
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
WriteDataReentrant::m_dobjKey2
SG::WriteHandleKey< MyDataObj > m_dobjKey2
Definition: WriteDataReentrant.h:38
WriteDataReentrant::m_dobjKeyArray
SG::WriteHandleKeyArray< MyDataObj > m_dobjKeyArray
Definition: WriteDataReentrant.h:47
errorcheck::ReportMessage::hideErrorLocus
static void hideErrorLocus(bool flag=true)
If set to true, hide the source file and line number in the output.
Definition: errorcheck.cxx:197
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
errorcheck.h
Helpers for checking error return status codes and reporting errors.
WriteDataReentrant::m_mKey
SG::WriteHandleKey< MapStringFloat > m_mKey
Definition: WriteDataReentrant.h:42
expect_exception.h
Helper to check that an exception is thrown.
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:73
DataVector.h
An STL vector of pointers that by default owns its pointed-to elements.
h
SG::WriteHandle::record
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
SG::DataObjectSharedPtr< TestDataObject >
DefaultKey.h
fitman.k
k
Definition: fitman.py:528
python.SystemOfUnits.m
float m
Definition: SystemOfUnits.py:106
WriteDataReentrant::m_testObjectKey
SG::WriteHandleKey< TestDataObject > m_testObjectKey
Definition: WriteDataReentrant.h:45