ATLAS Offline Software
WriteDataReentrant.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // $Id$
14 #undef NDEBUG
15 #include "WriteDataReentrant.h"
16 
17 #include <list>
18 #include <vector>
19 
21 #include "MyContObj.h"
22 #include "MapStringFloat.h"
24 
26 #include "StoreGate/WriteHandle.h"
27 #include "AthLinks/DataLink.h"
28 #include "AthLinks/ElementLink.h"
30 
33 
35 
36 
38  ISvcLocator* pSvcLocator) :
39  AthReentrantAlgorithm(name, pSvcLocator)
40 {
41  declareProperty ("DObjKey", m_dobjKey = "dobj");
42  declareProperty ("DObjKey2", m_dobjKey2 = "dobj2");
43  declareProperty ("DObjKey3", m_dobjKey3);
44  //declareProperty ("DObjKey4", m_dobjKey4 = "dobj4");
45  declareProperty ("CObjKey", m_cobjKey = "cobj");
46  declareProperty ("VFloatKey", m_vFloatKey = "vFloat");
47  declareProperty ("PLinkListKey", m_pLinkListKey);
48  declareProperty ("MKey", m_mKey = "mkey");
49  declareProperty ("LinkVectorKey", m_linkVectorKey = "linkvec");
50  declareProperty ("TestObjectKey", m_testObjectKey = "testobj");
51  declareProperty ("DObjKeyArray", m_dobjKeyArray = {"dobj_a1", "dobj_a2"});
52 }
53 
54 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
55 
57 {
59 
60  // If user did not set a key, use our own name. This cannot be done in the
61  // constructor as "DefaultName" is used during configurable generation (genconf).
62  if (m_dobjKey3.empty()) m_dobjKey3 = name();
64 
65  ATH_MSG_INFO ("in initialize()");
69  //ATH_CHECK( m_dobjKey4.initialize() );
76  ATH_CHECK( m_dobjKeyArray.initialize() );
77 
78  m_testObject =
80  return StatusCode::SUCCESS;
81 }
82 
83 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
84 
85 StatusCode WriteDataReentrant::execute (const EventContext& ctx) const
86 {
87  //this example illustrates how to record objects into the StoreGate(SG)
88  //with and without providing a key
89  //It then covers the new DataLink class and its usage as a persistable
90  //reference among objects in the SG
91  //Finally it shows how to use symlinks to record an object using its
92  //concrete type and its base class(es).
93 
94  ATH_MSG_INFO ("in execute()");
95 
96  // For algorithms that produce new data objects like this one
97  // the SG works like a bulletin board: the algorithm posts the
98  // new object to the SG (optionally providing a "name" for it).
99  // The SG assigns a unique identifier to the object and puts it on display
100  // alongside others of the same type.
101  // At preset intervals all objects are removed from the board to make room
102  // for new ones and filed.
103 
104  // Part 1: Recording objects to SG
106  dobj = std::make_unique<MyDataObj>(1);
107 
108  //now we create a second MyDataObj instance...
109  //...try to record it as we did for the first. Since dobj2 is also a
110  //MyDataObj we expect to see an error
111  ATH_MSG_WARNING ("we expect an error message here");
112  EXPECT_EXCEPTION (std::runtime_error,
113  dobj = std::make_unique<MyDataObj>(2));
114  ATH_MSG_WARNING ("end of error message");
115 
116  //here we go again...
117  //... but this time we register the dobj3 using this algo name as key
118  auto dobj3 = SG::makeHandle (m_dobjKey3, ctx);
119  dobj3 = std::make_unique<MyDataObj>(3);
120 
122  if (m_testObject->refCount() != 1) std::abort();
123  ATH_CHECK( testobj.record (m_testObject) );
124  if (m_testObject->refCount() != 2) std::abort();
125 
126 #if 0
127  {
128  SG::WriteHandle<MyDataObj> dobj4 (m_dobjKey4, ctx);
129  ATH_CHECK( dobj4.recordOrRetrieve (std::make_unique<MyDataObj>(4)) );
130  MyDataObj* pp = &*dobj4;
131  ATH_CHECK( dobj4.recordOrRetrieve (std::make_unique<MyDataObj>(4)) );
132  assert (pp == &*dobj4);
133  }
134 #endif
135 
136  // Writing an array of objects.
137  size_t i = 0;
140  ATH_CHECK( h.record (std::make_unique<MyDataObj> (i+100)) );
141  ++i;
142  }
143 
145 
146  // Part 2: storing collections in the SG
147 
150  cobj->reserve(10);
151  cobj->push_back (std::make_unique<MyContObj> (11.3, 132));
152  cobj->push_back (std::make_unique<MyContObj> (41.7, 291));
153 
154  // as above with a vector of integers
156  vFloat = std::make_unique<std::vector<float> >();
157  vFloat->push_back(1.0);
158  vFloat->push_back(2.0);
159  vFloat->push_back(3.0);
160 
162  ATH_CHECK( m.record (std::make_unique<MapStringFloat>()) );
163  (*m)["uno"]=1.0;
164  (*m)["due"]=2.0;
165 
167  //
168  // Part 3: Data Links
169  //
170  // Data links are persistable references. Typically they will replace
171  // pointers from one object in the event to another, hence they have
172  // the usual "pointer" syntax (op *, op ->, op !, ...)
173  // (to be pedantic they have the moniker syntax as they don't define ++, --)
174  // For example in Atlfast::Cell
175  // class Cell {
176  // ...
177  // private:
178  // std::vector<const HepMC::Particle*> m_particles;
179  // };
180  // m_particles would become
181  // std::vector<HepMCLink<Particle>::type > m_particles;
182  //
183  // To understand data links it is important to observe that the SG
184  // is not able to identify every single object in the event.
185  // In particular individual elements of a container (the MyContObj
186  // in the vector above or the Particles in McEventCollection) are not
187  // recorded individually into SG, only their owner (the container) is.
188  // For this reason data links are supported by two class templates:
189  // DataLink<DATAOBJ> is a link to a data object i.e. an object
190  // identified by SG
191  // ElementLink<CONTAINER> is a link to an element of a container (which
192  // in turn is a SG data object)
193  // To make a DataLink persistable we need to provide its SG identifier
194  // (its type and key).
195  // To make an ElementLink persistable we need two pieces of information:
196  // i) the SG identifier (type/key) of the data object owning the element
197  // ii) the identifier of the contained object within the owner
198  // For example when we write out a link to the third element of
199  // our vector<float> we want to write the SG id of the vector
200  // and the index (2) of the element in the vector
201  //
202  // Since the indexing mechanism of a container depends on the container
203  // type we need to specialize ElementLink for different containers
204  // Elements of STL sequences (lists, vectors, deques but also DataVector
205  // and DataList) are dealt with automatically.
206  // For other STL or STL-like containers, the data object designer (or the
207  // client must "help" ElementLink identifying the type of container
208  // Three macros in the header StoreGate/DeclareIndexingPolicy.h
209  // are provided to this end:
210  // for sequences use CONTAINER_IS_SEQUENCE( MySequence )
211  // for sets use CONTAINER_IS_SET( MySet )
212  // for maps and related containers use CONTAINER_IS_MAP( MyMap )
213  //
214  // It is also possible to define custom specializations of ElementLink
215  // for custom containers (e.g. GenParticleLink for McEventCollection).
216  //
217  //Enough! Let's now create our first DataLink. It refers to the first
218  // MyDataObj we recorded. DataLink constructors use references
219  // as input arguments
220  //
221  // DataLink referring to a storable object
222  //
223  DataLink<MyDataObj> dobjLink(*dobj);
224  //since dobj is identifiable in the SG a reference to it is all we need
225 
227  dobj2 = std::make_unique<MyDataObj> (2);
228 
229  //Otherwise one could first create an empty link
230  DataLink<MyDataObj> dobjLink2;
231  //and later on set it to refer to its target
232  dobjLink2.toStorableObject(*dobj2);
233 
234 
235  // Added Aug 30, 2001 HMA
236  // DataLink made from a key. This should work for either an object
237  // already registered in the store, or an object that has a
238  // persistency for it. we use dobj3, which is an object registered with
239  // a key.
240 
241  DataLink<MyDataObj> dobjLink3(name());
242  // now access it. DataLink will do a retrieve to get it from the store.
243  dobjLink3->val();
244 
245  //
246  // ElementLinks referring to contained objects
247  //
248  typedef ElementLink<std::vector<float> > VecElemLink;
249 
250 
251  VecElemLink thirdElementLink(*vFloat, 2); //THIS CRASHES SUN CC
252 
253  //sometimes we would not know the index of the element we want to refer to
254 
255  //reference to an element of the vector
256  float& anElement = vFloat->operator[](0);
257 
258  //starting from an empty link
259  VecElemLink aLink;
260  //we can refer it to its target without knowing its index
261  aLink.toContainedElement(*vFloat, anElement);
262  //it is better though to remember that toContainedElement for an
263  //ElementLink performs a linear search of "anElement" into "vFloat".
264  // If vFloat has a million elements think twice before using
265  // toContainedElement!
266 
268  pLinkList = std::make_unique<std::list<VecElemLink> >();
269  pLinkList->push_back(aLink);
270  pLinkList->push_back(thirdElementLink);
271 
272  //
273  // Part 3b: create a vector of links to the elements of the map above
274  //
275  typedef ElementLink<MapStringFloat> MapElemLink;
277  linkVector = std::make_unique<std::vector<MapElemLink> >();
278  linkVector->push_back(MapElemLink(*m, "uno"));
279  MapElemLink mLink;
280  mLink.toContainedElement(*m, (*m)["due"]);
281  linkVector->push_back(mLink);
282 
283  // Part 4
284  // make a link to dobj as its base class after it has been registered
285  // this allows later to retrieve different concrete types as a common ABC
286 
287  const BaseClass * pDO = 0;
288  if ( (evtStore()->symLink(dobj.cptr(), pDO)).isFailure() ) {
289  ATH_MSG_ERROR (" could not make link to BaseClass");
290  return( onError() );
291  }
292 
293  // make a link as its base class, with the same name
294  if ( ( evtStore()->symLink(dobj3.cptr(), pDO)).isFailure() ) {
295  ATH_MSG_ERROR (" could not make link to BaseClass");
296  return( onError() );
297  }
298 
299  // Part 5
300  // finally dump the structure of the StoreGate before returning
301  ATH_MSG_INFO (" registered all data objects");
302  ATH_MSG_INFO (" StoreGate structure before returning from execute \n"
303  << evtStore()->dump());
304 
305  return StatusCode::SUCCESS;
306 }
307 
308 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
309 
311 {
312  ATH_MSG_INFO ("in finalize()");
313  return StatusCode::SUCCESS;
314 }
315 
316 
318 {
319  ATH_MSG_ERROR ("Dumping StoreGate after error occurred\n"
320  << evtStore()->dump());
321  return StatusCode::FAILURE;
322 }
323 
WriteDataReentrant::m_cobjKey
SG::WriteHandleKey< DataVector< MyContObj > > m_cobjKey
Definition: WriteDataReentrant.h:42
StoreGateExample_ClassDEF.h
WriteDataReentrant.h
Testing reentrant algorithms.
WriteDataReentrant::initialize
virtual StatusCode initialize() override final
Definition: WriteDataReentrant.cxx:56
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
WriteDataReentrant::execute
virtual StatusCode execute(const EventContext &ctx) const override final
Definition: WriteDataReentrant.cxx:85
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:43
MyContObj.h
make_unique
std::unique_ptr< T > make_unique(Args &&... args)
Definition: SkimmingToolEXOT5.cxx:23
AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
WriteDataReentrant::m_linkVectorKey
SG::WriteHandleKey< std::vector< ElementLink< MapStringFloat > > > m_linkVectorKey
Definition: WriteDataReentrant.h:46
MyDataObj::val
void val(int i)
Definition: AthExStoreGateExample/MyDataObj.h:24
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: AthExStoreGateExample/MyDataObj.h:35
WriteDataReentrant::m_pLinkListKey
SG::WriteHandleKey< std::list< ElementLink< std::vector< float > > > > m_pLinkListKey
Definition: WriteDataReentrant.h:45
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:40
AthReentrantAlgorithm
An algorithm that can be simultaneously executed in multiple threads.
Definition: AthReentrantAlgorithm.h:83
WriteDataReentrant::m_testObject
SG::DataObjectSharedPtr< TestDataObject > m_testObject
Definition: WriteDataReentrant.h:51
WriteDataReentrant::onError
StatusCode onError() const
Definition: WriteDataReentrant.cxx:317
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:269
WriteDataReentrant::WriteDataReentrant
WriteDataReentrant(const std::string &name, ISvcLocator *pSvcLocator)
Definition: WriteDataReentrant.cxx:37
WriteDataReentrant::finalize
virtual StatusCode finalize() override final
Definition: WriteDataReentrant.cxx:310
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:38
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:92
MyDataObj
Definition: AthExStoreGateExample/MyDataObj.h:16
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:97
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
python.ChapPy.dump
def dump(buf, stdout=sys.stdout)
Definition: ChapPy.py:25
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
WriteDataReentrant::m_dobjKey2
SG::WriteHandleKey< MyDataObj > m_dobjKey2
Definition: WriteDataReentrant.h:39
WriteDataReentrant::m_dobjKeyArray
SG::WriteHandleKeyArray< MyDataObj > m_dobjKeyArray
Definition: WriteDataReentrant.h:49
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:192
errorcheck.h
Helpers for checking error return status codes and reporting errors.
MyDataObj.h
WriteDataReentrant::m_mKey
SG::WriteHandleKey< MapStringFloat > m_mKey
Definition: WriteDataReentrant.h:44
expect_exception.h
Helper to check that an exception is thrown.
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:76
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
WriteDataReentrant::m_testObjectKey
SG::WriteHandleKey< TestDataObject > m_testObjectKey
Definition: WriteDataReentrant.h:47