ATLAS Offline Software
T_AthenaPoolCoolMultChanCnv.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 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  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  Token* token = 0;
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  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  delete token; token = 0;
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  Token* token = 0;
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  delete token; token = 0;
230 
231  ATH_MSG_DEBUG("End createRep");
232  return(StatusCode::SUCCESS);
233 }
234 
235 //__________________________________________________________________________
236 template <class COLL_T, class ELEM_T, class ELEM_P>
237 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::fillRepRefs(IOpaqueAddress* /*pAddr*/, DataObject* /*pObj*/)
238 {
239  ATH_MSG_DEBUG("End fillRepRefs");
240  return(StatusCode::SUCCESS);
241 }
242 
243 //__________________________________________________________________________
244 template <class COLL_T, class ELEM_T, class ELEM_P>
245 StatusCode
246 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::attrListCollToObject(CondAttrListCollection* attrListColl,
247  COLL_T*& obj)
248 {
249 
250  ATH_MSG_DEBUG("Creating a collection from a CondAttrListCollection");
251 
252  // Create collection
253  obj = new COLL_T();
254 
255  // Check the sizes of objs and IOVs
256  if (attrListColl->size() != attrListColl->iov_size()) {
257  ATH_MSG_ERROR("CondAttrListCollection incorrect size for IOVs! "
258  << " Number of objects: " << attrListColl->size()
259  << " Number of IOVs: " << attrListColl->iov_size());
260  return(StatusCode::FAILURE);
261  }
262 
263  /// Add the pointer to the CondAttrListCollection to COLL_T
264  /// object. This will allow subsequent addition of IOVRange
265  /// objects added to COLL_T to be propagated to the
266  /// CondAttrListCollection. This is needed for IOV registration
267  /// which may happen AFTER a read back of the COLL_T.
268  obj->implementation()->setAttrListColl(attrListColl);
269 
270  // Loop over objects in COLL_T*
271  std::string token;
272  CondAttrListCollection::const_iterator it = attrListColl->begin();
273  CondAttrListCollection::const_iterator last = attrListColl->end();
274  CondAttrListCollection::iov_const_iterator itIOV = attrListColl->iov_begin();
275  for (; it != last; ++it, ++itIOV) {
276  try {
277  // pool token/ref
278  const coral::AttributeList& attrList = (*it).second;
279  token=attrList["PoolRef"].data<std::string>();
280  }
281  // FIXME exception
282  catch(const std::exception& x) {
283  ATH_MSG_ERROR("PoolRef not found in attribute list");
284  return(StatusCode::FAILURE);
285  }
286  // Allow T/P separation - set token and use createTransient
287  ELEM_T* elem {nullptr};
288  {
289  std::lock_guard<AthenaPoolConverter::CallMutex> lock(this->m_conv_mut);
290  this->setToken( token );
291  elem = this->createTransient();
292  }
293  // Add elem, channel number and IOV
294  obj->push_back(elem);
295  obj->add((*it).first);
296  obj->add((*itIOV).second);
297 
298  ATH_MSG_DEBUG("Read in new object for token: " << token);
299 
300  }
301 
302  ATH_MSG_DEBUG("End attrListCollToObject");
303  return(StatusCode::SUCCESS);
304 }
305 
306 /// Read in CondMultChanCollImpl and the objects for its tokens,
307 /// saving them in the output collection
308 /// @param collImpl [IN] CondMultChanCollImpl token
309 /// @param obj [OUT] pointer to the collection of objects.
310 template <class COLL_T, class ELEM_T, class ELEM_P>
311 StatusCode
312 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::condMultChanCollImplToObject(const std::string& collImplToken,
313  COLL_T*& obj)
314 {
315 
316  ATH_MSG_DEBUG("Creating a collection from a CondMultChanCollImpl for token");
317 
318  // Create collection
319  obj = new COLL_T();
320  ELEM_T* elem = 0;
321 
322  // Read in the CondMultChanCollImpl
323  std::lock_guard<AthenaPoolConverter::CallMutex> lock(this->m_conv_mut);
324  CondMultChanCollImpl* impl = 0;
325  this->setToken(collImplToken);
326  StatusCode sc = this->poolToObject(this->m_i_poolToken, impl);
327  if (sc != StatusCode::SUCCESS) {
328  ATH_MSG_ERROR("Unable to read in CondMultChanCollImpl");
329  return(StatusCode::FAILURE);
330  }
331 
332  // Make sure the channel vector is filled
333  if (impl->token_size() != impl->chan_size()) {
334  ATH_MSG_ERROR("Token and channel vectors are not the same size! Number of tokens: " << impl->token_size()
335  << " Number of channels: " << impl->chan_size());
336  return(StatusCode::FAILURE);
337  }
338 
339  // Fill IOVs if they are there
340  bool hasIOVs = (impl->iov_size() == impl->token_size());
341 
342  // Loop over tokens in Impl and retrieve objects
343  CondMultChanCollImpl::chan_const_iterator itChan = impl->chan_begin();
344  CondMultChanCollImpl::iov_const_iterator itIOV = impl->iov_begin();
345  CondMultChanCollImpl::token_const_iterator itToken = impl->token_begin();
346  for (unsigned int i = 0; i < impl->chan_size(); ++i, ++itChan, ++itIOV, ++itToken) {
347 
348  // Allow T/P separation - set token and use createTransient
349  this->setToken( *itToken );
350  elem = this->createTransient();
351 
352  // Add elem, channel number and IOV
353  obj->push_back(elem);
354  obj->add(*itChan);
355  if (hasIOVs)obj->add(*itIOV);
356 
357  ATH_MSG_DEBUG("Read in new object for token: " << *itToken);
358  }
359 
360  // Now remove impl
361  delete impl;
362 
363  ATH_MSG_DEBUG("End condMultChanCollImplToObject");
364  return(StatusCode::SUCCESS);
365 }
366 
367 /// Dummy methods not needed here
368 //__________________________________________________________________________
369 template <class COLL_T, class ELEM_T, class ELEM_P>
370 inline
371 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::transToPers(COLL_T* /*obj*/, ELEM_T*& /*persObj*/)
372 {
373  return(StatusCode::SUCCESS);
374 }
375 
376 //__________________________________________________________________________
377 template <class COLL_T, class ELEM_T, class ELEM_P>
378 inline
379 StatusCode T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::persToTrans(COLL_T*& /*transObj*/, ELEM_T* /*obj*/)
380 {
381  return(StatusCode::SUCCESS);
382 }
383 
384 //__________________________________________________________________________
385 // Read object of type P. This is an exception-throwing version of poolToObject()
386 // plus reading of all extending objects
387 template <class COLL_T, class ELEM_T, class ELEM_P>
388 template <class P>
389 inline
390 P* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::poolReadObject() {
391  P* persObj = 0;
392  if( this->poolToObject( this->m_i_poolToken , persObj ).isFailure() ) {
393  throw std::runtime_error("POOL read failed");
394  }
395  return(persObj);
396 }
397 
398 //__________________________________________________________________________
399 // Read object of type P. This is an exception-throwing version of poolToObject()
400 // plus reading of all extending objects
401 template <class COLL_T, class ELEM_T, class ELEM_P>
402 inline
403 ELEM_T* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::poolReadObject() {
404  ELEM_T* persObj = 0;
405  if( this->poolToObject( this->m_i_poolToken , persObj ).isFailure() ) {
406  throw std::runtime_error("POOL read failed");
407  }
408  return(persObj);
409 }
410 
411 //__________________________________________________________________________
412 template <class COLL_T, class ELEM_T, class ELEM_P>
413 ELEM_P* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::createPersistent(ELEM_T* tobj)
414 {
415  // Default implementation - ELEM_T == ELEM_P so just return input
416  ELEM_P* obj = dynamic_cast<ELEM_P*>(tobj);
417  return(obj);
418 }
419 
420 //__________________________________________________________________________
421 template <class COLL_T, class ELEM_T, class ELEM_P>
422 ELEM_T* T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::createTransient()
423 {
424  // Default version - no T/P separation. We read in transient
425  // object
426  //ELEM_T* elem = 0;
427  ELEM_T* elem = this->poolReadObject();
428  return(elem);
429 }
430 
431 //__________________________________________________________________________
432 /// specialized version that adds persistency contextID to tokens (for reading)
433 template <class COLL_T, class ELEM_T, class ELEM_P>
434 void
435 T_AthenaPoolCoolMultChanCnv<COLL_T, ELEM_T, ELEM_P>::
436 setToken (const std::string& token)
437 {
438  char context[32];
439  ::sprintf(context, "[CTXT=%08X]", m_persCtx);
440  T_AthenaPoolCustCnv<COLL_T, ELEM_T>::setToken( token + context );
441 }