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