ATLAS Offline Software
T_AthenaPoolCoolMultChanCnv.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 /** @file T_AthenaPoolCoolMultChanCnv.icc
6  * @brief This templated class provides the POOL converter to
7  * translate a DataVector<ELEM_T> to and from a CondAttrListCollection. In
8  * this case, the elements of T are written/read and their POOL
9  * tokens are stored in CondAttrListCollection.
10  * @author RD Schaffer <R.D.Schaffer@cern.ch>
11  **/
12 
13 #include "AthenaPoolCnvSvc/IAthenaPoolCnvSvc.h"
14 #include "AthenaPoolUtilities/AthenaAttributeList.h"
15 #include "AthenaPoolUtilities/CondAttrListCollection.h"
16 #include "AthenaPoolUtilities/CondAttrListCollAddress.h"
17 #include "AthenaPoolUtilities/CondMultChanCollection.h"
18 
19 #include "GaudiKernel/ClassID.h"
20 #include "GaudiKernel/StatusCode.h"
21 #include "GaudiKernel/MsgStream.h"
22 
23 #include "AthenaKernel/CLASS_DEF.h"
24 #include "AthenaKernel/StorableConversions.h"
25 
26 #include "CxxUtils/checker_macros.h"
27 
28 #include <exception>
29 #include <string>
30 #include <format>
31 
32 //__________________________________________________________________________
33 template <class COLL_T, class ELEM_T, class ELEM_P>
34 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::T_AthenaPoolCoolMultChanCnv(ISvcLocator* svcloc)
35  :
36  T_AthenaPoolCustCnv<COLL_T, ELEM_T>(svcloc)
37 {
38  ATH_MSG_DEBUG("AthenaPool Converter Constructor for " << this->classID());
39 }
40 
41 //__________________________________________________________________________
42 template <class COLL_T, class ELEM_T, class ELEM_P>
43 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::createObj(IOpaqueAddress* pAddr, DataObject*& pObj)
44 {
45  // This is the "read" method for a collection T (i.e. DataObject
46  // pObj) which contains objects of type T::value_type.
47  //
48  // There are two situations we must allow for:
49  //
50  // 1) When reading from COOL - the "standard production" scenario
51  // 2) When reading directly the collection from a pool file/db.
52  // This is used by "developers" who are testing their
53  // conditions objects
54  //
55  // For 1) the IOpaqueAddress contains a ptr to a
56  // CondAttrListCollection, and this contains tokens to each of the
57  // objects in the collection to be read.
58  //
59  // For 2) the IOpaqueAddress DOES NOT contain a ptr to a
60  // CondAttrListCollection, rather we simply use the collection
61  // token and read in the CondMultChanCollImpl and build a
62  // CondAttrListCollection
63  //
64 
65  ATH_MSG_DEBUG("Read in objects for collection");
66 
67  m_persCtx = pAddr->ipar()[0];
68 
69  CondAttrListCollAddress* addr = dynamic_cast<CondAttrListCollAddress*>(pAddr);
70 
71  std::unique_ptr<COLL_T> obj;
72  if (addr) {
73  // Successful cast - situation 1)
74 
75  // Loop over tokens inside the CondAttrListCollection, read
76  // them in and add them to the data object.
77  CondAttrListCollection* coll = addr->attrListColl();
78  COLL_T* pobj = nullptr;
79  StatusCode sc = attrListCollToObject(coll, pobj);
80  obj = std::unique_ptr<COLL_T>(pobj);
81  if (sc != StatusCode::SUCCESS) {
82  ATH_MSG_ERROR("Unable to read in tokens from CondAttrListCollection");
83  return(StatusCode::FAILURE);
84  }
85  ATH_MSG_DEBUG("Created CondAttrListCollection from an CondAttrListCollAddress");
86  } else {
87  // Situation 2) - read in the CondMultChanCollImpl and build a
88  // CondAttrListCollection from the CondMultChanCollImpl
89  COLL_T* pobj = nullptr;
90  StatusCode sc = condMultChanCollImplToObject( *(pAddr->par()), pobj);
91  obj = std::unique_ptr<COLL_T>(pobj);
92  if (sc != StatusCode::SUCCESS) {
93  ATH_MSG_ERROR("Unable to read in CondMultChanCollImpl");
94  return(StatusCode::FAILURE);
95  }
96  ATH_MSG_DEBUG("Created CondAttrListCollection from an CondMultChanCollImpl");
97  }
98 
99  // Initialize object after having been read in
100  StatusCode sc = obj->initialize();
101  if (sc != StatusCode::SUCCESS) {
102  ATH_MSG_ERROR("Unable to initialize object read in");
103  return(StatusCode::FAILURE);
104  }
105 
106  // Convert to DataObject
107  pObj = SG::asStorable (std::move (obj));
108  if (!pObj) {
109  ATH_MSG_ERROR("Cannot get DataObject from COLL_T");
110  return(StatusCode::FAILURE);
111  }
112  ATH_MSG_DEBUG("End createObj");
113  return(StatusCode::SUCCESS);
114 }
115 
116 //__________________________________________________________________________
117 template <class COLL_T, class ELEM_T, class ELEM_P>
118 StatusCode
119 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::objectToAttrListColl ATLAS_NOT_THREAD_SAFE
120  (COLL_T* obj, IOpaqueAddress*& pAddr,
121  CondAttrListCollection*& attrListColl,
122  std::unique_ptr<Token>& implToken)
123 {
124  ATH_MSG_DEBUG("Creating a CondAttrListCollection from a collection");
125 
126 
127  attrListColl = new CondAttrListCollection(true); // set hasRunEventTime
128 
129  // Make sure the channel vector is filled
130  if (obj->size() != obj->chan_size()) {
131  ATH_MSG_ERROR("Must fill in channel numbers! Number of objects: " << obj->size()
132  << " Number of channels: " << obj->chan_size());
133  return(StatusCode::FAILURE);
134  }
135 
136  // Fill IOVs if they are there
137  bool hasIOVs = (obj->iov_size() == obj->size());
138 
139  // Get the contained object in the COLL_T
140  CondMultChanCollImpl* impl = obj->implementation();
141 
142  // Reset tokens in case this object was previously written out
143  impl->resetTokens();
144 
145  // Loop over objects in COLL_T*
146  typename COLL_T::chan_const_iterator itChan = obj->chan_begin();
147  typename COLL_T::iov_const_iterator itIOV = obj->iov_begin();
148  std::string token_str;
149  std::lock_guard<AthenaPoolConverter::CallMutex> lock(this->m_conv_mut);
150  for (unsigned int chan = 0; chan < obj->size(); ++chan, ++itChan) {
151  ELEM_T* elem = (*obj)[chan];
152  // Allow for T/P separation, convert to persistent object
153  ELEM_P* elem_p = this->createPersistent(elem);
154  std::unique_ptr<Token> token;
155  StatusCode sc = this->objectToPool(elem_p, token, "", *pAddr->par());
156  if (sc != StatusCode::SUCCESS || !token) {
157  ATH_MSG_ERROR("Unable to write out object");
158  return(StatusCode::FAILURE);
159  }
160  token_str = token->toString();
161 
162  // Create a new AthenaAttributeList
163  AthenaAttributeList attrList;
164  attrList.extend("PoolRef","string");
165  attrList["PoolRef"].setValue( token_str );
166  attrListColl->add((*itChan), attrList);
167  if (hasIOVs) {
168  attrListColl->add((*itChan), (*itIOV));
169  ++itIOV;
170  }
171  ATH_MSG_DEBUG("Adding new attrList for token: " << token_str);
172 
173  // Save as well in implementation
174  impl->add(token_str);
175  }
176 
177  // Print out tokens
178  ATH_MSG_DEBUG("Print out tokens in implementaion:");
179  CondMultChanCollImpl::token_const_iterator itToken = impl->token_begin();
180  CondMultChanCollImpl::token_const_iterator itTokenEnd = impl->token_end();
181  CondMultChanCollImpl::chan_const_iterator itChan1 = impl->chan_begin();
182  for (; itToken != itTokenEnd; ++itToken, ++itChan1) {
183  ATH_MSG_DEBUG(*itToken);
184  ATH_MSG_DEBUG("Chan " << *itChan1);
185  }
186 
187  StatusCode sc = this->objectToPool(impl, implToken, "", *pAddr->par());
188  if (sc != StatusCode::SUCCESS || !implToken) {
189  ATH_MSG_ERROR("Unable to write out CondMultChanCollImpl");
190  return(StatusCode::FAILURE);
191  }
192  ATH_MSG_DEBUG("Wrote out CondMultChanCollImpl - token: " << implToken->toString());
193 
194  ATH_MSG_DEBUG("End objectToAttrListColl");
195  return(StatusCode::SUCCESS);
196 }
197 
198 //__________________________________________________________________________
199 template <class COLL_T, class ELEM_T, class ELEM_P>
200 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::createRep(DataObject* pObj, IOpaqueAddress*& pAddr)
201 {
202  // This is the "write" method for a collection of COLL_T*
203  // (i.e. DataObject pObj). Each element of the collection is
204  // written out and the tokens are stored in a
205  // CondAttrListCollection.
206 
207  ATH_MSG_DEBUG("Write out objects in collection");
208 
209  COLL_T* obj = 0;
210  SG::fromStorable(pObj, obj);
211  if (!obj) {
212  ATH_MSG_ERROR("Unable to convert DataObject");
213  return(StatusCode::FAILURE);
214  }
215  CondAttrListCollection* coll = 0;
216  std::unique_ptr<Token> token;
217  // Ok, because it's just creating a new list.
218  StatusCode sc ATLAS_THREAD_SAFE = objectToAttrListColl(obj, pAddr, coll, token);
219  if (sc != StatusCode::SUCCESS || !token) {
220  ATH_MSG_ERROR("Unable to get objects and fill CondAttrListCollection with tokens");
221  return(StatusCode::FAILURE);
222  }
223  CondAttrListCollAddress* addr = new CondAttrListCollAddress(POOL_StorageType,
224  this->classID(),
225  token->toString());
226  addr->setAttrListColl(coll);
227  delete pAddr; pAddr = addr;
228  pAddr->addRef();
229 
230  ATH_MSG_DEBUG("End createRep");
231  return(StatusCode::SUCCESS);
232 }
233 
234 //__________________________________________________________________________
235 template <class COLL_T, class ELEM_T, class ELEM_P>
236 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::fillRepRefs(IOpaqueAddress* /*pAddr*/, DataObject* /*pObj*/)
237 {
238  ATH_MSG_DEBUG("End fillRepRefs");
239  return(StatusCode::SUCCESS);
240 }
241 
242 //__________________________________________________________________________
243 template <class COLL_T, class ELEM_T, class ELEM_P>
244 StatusCode
245 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::attrListCollToObject(CondAttrListCollection* attrListColl,
246  COLL_T*& obj)
247 {
248 
249  ATH_MSG_DEBUG("Creating a collection from a CondAttrListCollection");
250 
251  // Create collection
252  obj = new COLL_T();
253 
254  // Check the sizes of objs and IOVs
255  if (attrListColl->size() != attrListColl->iov_size()) {
256  ATH_MSG_ERROR("CondAttrListCollection incorrect size for IOVs! "
257  << " Number of objects: " << attrListColl->size()
258  << " Number of IOVs: " << attrListColl->iov_size());
259  return(StatusCode::FAILURE);
260  }
261 
262  /// Add the pointer to the CondAttrListCollection to COLL_T
263  /// object. This will allow subsequent addition of IOVRange
264  /// objects added to COLL_T to be propagated to the
265  /// CondAttrListCollection. This is needed for IOV registration
266  /// which may happen AFTER a read back of the COLL_T.
267  obj->implementation()->setAttrListColl(attrListColl);
268 
269  // Loop over objects in COLL_T*
270  std::string token;
271  CondAttrListCollection::const_iterator it = attrListColl->begin();
272  CondAttrListCollection::const_iterator last = attrListColl->end();
273  CondAttrListCollection::iov_const_iterator itIOV = attrListColl->iov_begin();
274  for (; it != last; ++it, ++itIOV) {
275  try {
276  // pool token/ref
277  const coral::AttributeList& attrList = (*it).second;
278  token=attrList["PoolRef"].data<std::string>();
279  }
280  // FIXME exception
281  catch(const std::exception& x) {
282  ATH_MSG_ERROR("PoolRef not found in attribute list");
283  return(StatusCode::FAILURE);
284  }
285  // Allow T/P separation - set token and use createTransient
286  ELEM_T* elem {nullptr};
287  {
288  std::lock_guard<AthenaPoolConverter::CallMutex> lock(this->m_conv_mut);
289  this->setToken( token );
290  elem = this->createTransient();
291  }
292  // Add elem, channel number and IOV
293  obj->push_back(elem);
294  obj->add((*it).first);
295  obj->add((*itIOV).second);
296 
297  ATH_MSG_DEBUG("Read in new object for token: " << token);
298 
299  }
300 
301  ATH_MSG_DEBUG("End attrListCollToObject");
302  return(StatusCode::SUCCESS);
303 }
304 
305 /// Read in CondMultChanCollImpl and the objects for its tokens,
306 /// saving them in the output collection
307 /// @param collImpl [IN] CondMultChanCollImpl token
308 /// @param obj [OUT] pointer to the collection of objects.
309 template <class COLL_T, class ELEM_T, class ELEM_P>
310 StatusCode
311 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::condMultChanCollImplToObject(const std::string& collImplToken,
312  COLL_T*& obj)
313 {
314 
315  ATH_MSG_DEBUG("Creating a collection from a CondMultChanCollImpl for token");
316 
317  // Create collection
318  obj = new COLL_T();
319  ELEM_T* elem = 0;
320 
321  // Read in the CondMultChanCollImpl
322  std::lock_guard<AthenaPoolConverter::CallMutex> lock(this->m_conv_mut);
323  CondMultChanCollImpl* impl = 0;
324  this->setToken(collImplToken);
325  StatusCode sc = this->poolToObject(this->m_i_poolToken, impl);
326  if (sc != StatusCode::SUCCESS) {
327  ATH_MSG_ERROR("Unable to read in CondMultChanCollImpl");
328  return(StatusCode::FAILURE);
329  }
330 
331  // Make sure the channel vector is filled
332  if (impl->token_size() != impl->chan_size()) {
333  ATH_MSG_ERROR("Token and channel vectors are not the same size! Number of tokens: " << impl->token_size()
334  << " Number of channels: " << impl->chan_size());
335  return(StatusCode::FAILURE);
336  }
337 
338  // Fill IOVs if they are there
339  bool hasIOVs = (impl->iov_size() == impl->token_size());
340 
341  // Loop over tokens in Impl and retrieve objects
342  CondMultChanCollImpl::chan_const_iterator itChan = impl->chan_begin();
343  CondMultChanCollImpl::iov_const_iterator itIOV = impl->iov_begin();
344  CondMultChanCollImpl::token_const_iterator itToken = impl->token_begin();
345  for (unsigned int i = 0; i < impl->chan_size(); ++i, ++itChan, ++itIOV, ++itToken) {
346 
347  // Allow T/P separation - set token and use createTransient
348  this->setToken( *itToken );
349  elem = this->createTransient();
350 
351  // Add elem, channel number and IOV
352  obj->push_back(elem);
353  obj->add(*itChan);
354  if (hasIOVs)obj->add(*itIOV);
355 
356  ATH_MSG_DEBUG("Read in new object for token: " << *itToken);
357  }
358 
359  // Now remove impl
360  delete impl;
361 
362  ATH_MSG_DEBUG("End condMultChanCollImplToObject");
363  return(StatusCode::SUCCESS);
364 }
365 
366 /// Dummy methods not needed here
367 //__________________________________________________________________________
368 template <class COLL_T, class ELEM_T, class ELEM_P>
369 inline
370 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::transToPers(COLL_T* /*obj*/, ELEM_T*& /*persObj*/)
371 {
372  return(StatusCode::SUCCESS);
373 }
374 
375 //__________________________________________________________________________
376 template <class COLL_T, class ELEM_T, class ELEM_P>
377 inline
378 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::persToTrans(COLL_T*& /*transObj*/, ELEM_T* /*obj*/)
379 {
380  return(StatusCode::SUCCESS);
381 }
382 
383 //__________________________________________________________________________
384 // Read object of type P. This is an exception-throwing version of poolToObject()
385 // plus reading of all extending objects
386 template <class COLL_T, class ELEM_T, class ELEM_P>
387 template <class P>
388 inline
389 P* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::poolReadObject() {
390  P* persObj = 0;
391  if( this->poolToObject( this->m_i_poolToken , persObj ).isFailure() ) {
392  throw std::runtime_error("POOL read failed");
393  }
394  return(persObj);
395 }
396 
397 //__________________________________________________________________________
398 // Read object of type P. This is an exception-throwing version of poolToObject()
399 // plus reading of all extending objects
400 template <class COLL_T, class ELEM_T, class ELEM_P>
401 inline
402 ELEM_T* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::poolReadObject() {
403  ELEM_T* persObj = 0;
404  if( this->poolToObject( this->m_i_poolToken , persObj ).isFailure() ) {
405  throw std::runtime_error("POOL read failed");
406  }
407  return(persObj);
408 }
409 
410 //__________________________________________________________________________
411 template <class COLL_T, class ELEM_T, class ELEM_P>
412 ELEM_P* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::createPersistent(ELEM_T* tobj)
413 {
414  // Default implementation - ELEM_T == ELEM_P so just return input
415  ELEM_P* obj = dynamic_cast<ELEM_P*>(tobj);
416  return(obj);
417 }
418 
419 //__________________________________________________________________________
420 template <class COLL_T, class ELEM_T, class ELEM_P>
421 ELEM_T* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::createTransient()
422 {
423  // Default version - no T/P separation. We read in transient
424  // object
425  //ELEM_T* elem = 0;
426  ELEM_T* elem = this->poolReadObject();
427  return(elem);
428 }
429 
430 //__________________________________________________________________________
431 /// specialized version that adds persistency contextID to tokens (for reading)
432 template <class COLL_T, class ELEM_T, class ELEM_P>
433 void
434 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::
435 setToken (const std::string& token)
436 {
437  char context[32];
438  const std::string contextStr = std::format("[CTXT={:08X}]", m_persCtx);
439  std::strncpy(context, contextStr.c_str(), sizeof(context) - 1);
440  context[sizeof(context) - 1] = '\0';
441  T_AthenaPoolCustCnv<COLL_T, ELEM_T>::setToken( token + context );
442 }