ATLAS Offline Software
CoraCoolObjectIter.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // CoraCoolObjectIter.cxx
6 // Implementation for CoraCoolObjectIter
7 // Richard Hawkings, started 10/2006
8 
9 #include <sstream>
10 #include "RelationalAccess/ISessionProxy.h"
11 #include "RelationalAccess/ITransaction.h"
12 #include "RelationalAccess/ITable.h"
13 #include "RelationalAccess/IQuery.h"
14 #include "RelationalAccess/ICursor.h"
15 #include "CoolKernel/IObject.h"
16 #include "CoolKernel/Record.h"
21 #include <unordered_map>
22 
23 // performance tuning parameters
24 // maximum number of ranges and query terms to use for CORAL query
25 #define QB_SIZE 16
26 #define QB_TERMS 20
27 // buffer length for number of COOL channels and DB backend rowcache size
28 // tuned to be slightly larger than number of SCT modules
29 #define OI_BUFLEN 4200
30 #define OI_ROWCACHE 4200
31 
33  cool::IObjectIteratorPtr coolitr) :
34  m_buflen(OI_BUFLEN),m_inbuf(0),m_nextobj(0),
35  m_refValid(false),m_allDone(false),
36  m_folder(coracoolfolder),m_coolitr(coolitr) {
37  m_data.resize(m_buflen);
38  // assemble an AttributeListSpecification to share with the data objects
39  const cool::RecordSpecification recspec=m_folder->payloadSpecification();
40  const coral::AttributeList speclist = cool::Record(recspec).attributeList();
41  m_spec=new coral::AttributeListSpecification();
42  for (coral::AttributeList::const_iterator itr=speclist.begin();
43  itr!=speclist.end();++itr) {
44  const coral::AttributeSpecification& aspec=itr->specification();
45  m_spec->extend(aspec.name(),aspec.typeName());
46  }
47 }
48 
50  if (m_spec!=0) m_spec->release();
51 }
52 
54  if (m_inbuf>m_nextobj) {
55  // return data directly from the buffer - just increment counter
56  ++m_nextobj;
57  } else if (iHasNext()) {
59  } else {
60  throw CoraCoolException("No more data in CoraCoolObjectIter",
61  "CoraCoolObjectIter::next");
62  }
63  return m_data.at(m_nextobj-1);
64 }
65 
67  // read some data from the database - initialise buffer to empty
68  m_inbuf=0;
69  // coloumn name of the FK in the CORAL table
70  const std::string& coralkey=m_folder->coralFKey();
71  // buffer to build the query
72  QueryBuilder qbuf(QB_SIZE);
73  coral::AttributeList fktype;
74  std::string fktypestr;
75  // keep map of FKvalue to list of associated COOL channels
76  typedef std::vector<unsigned int> KeyVec;
77  typedef std::unordered_map<long long,KeyVec > KeyMap;
78  KeyMap keymap;
79 
80  while (m_inbuf<m_buflen && iHasNext() &&
81  qbuf.size()<QB_SIZE && qbuf.terms()<QB_TERMS) {
82  // get the COOL object
83  const cool::IObject& coolobj=m_coolitr->currentRef();
84  // reset so that next call to iHasNext will read the next one
85  m_refValid=false;
86  // prepare CoraCoolObject to receive the payload data
87  CoraCoolObjectPtr data(new CoraCoolObject(coolobj.since(),
88  coolobj.until(),coolobj.channelId(),m_spec));
90  // setup the foreign key reference
91  const coral::AttributeList& payload=coolobj.payload().attributeList();
92  // remember the type of the FK
93  if (m_inbuf==0) {
94  fktypestr=payload[0].specification().typeName();
95  fktype=payload;
96  }
97  long long ikeyval=numAttr(fktypestr,payload[0]);
98  qbuf.add(ikeyval);
99  KeyMap::iterator kdata=keymap.find(ikeyval);
100  if (kdata==keymap.end()) {
101  // new FK value - create vector of buffer positions for this one
102  kdata=keymap.insert(kdata,
103  KeyMap::value_type(ikeyval,KeyVec(8)));
104  KeyVec& keyvec=kdata->second;
105  keyvec.resize(1);
106  keyvec[0]=m_inbuf;
107  } else {
108  // add to list of buffers using this key
109  KeyVec& keyvec=kdata->second;
110  keyvec.push_back(m_inbuf);
111  }
112  ++m_inbuf;
113  }
114  // setup the query
115  std::string bwhere;
116  coral::AttributeList bfkeys;
117  qbuf.getQuery(bwhere,coralkey,bfkeys,fktype[0].specification());
118  // execute the query
119  try {
120  m_folder->proxy()->transaction().start(true);
121  coral::IQuery* query=m_folder->table()->newQuery();
122  query->setCondition(bwhere,bfkeys);
123  query->setRowCacheSize(OI_ROWCACHE);
125  coral::ICursor& cursor=query->execute();
126  KeyMap::const_iterator kdata=keymap.end();
127  long long okeyval=0;
128  while (cursor.next()) {
129  const coral::AttributeList& res=cursor.currentRow();
130  // check which buffer(s) this data is associated with
131  // maybe associated with more than one if referenceObject has been used
132  // so have to check all - no optimisation possible
133  const long long keyval=numAttr(fktypestr,res[coralkey]);
134  if (keyval!=okeyval || kdata==keymap.end()) {
135  kdata=keymap.find(keyval);
136  okeyval=keyval;
137  }
138  if (kdata!=keymap.end()) {
139  KeyVec keyvec=kdata->second;
140  for (KeyVec::const_iterator kitr=keyvec.begin();
141  kitr!=keyvec.end();++kitr) {
142  m_data[*kitr]->add(res);
143  }
144  } else {
145  std::ostringstream skey;
146  skey << "CoraCool key remapping error for key " << keyval;
147  throw CoraCoolException(skey.str(),"CoraCoolObjectIter::next");
148  }
149  }
150  delete query;
151  m_folder->proxy()->transaction().commit();
152  }
153  catch (coral::Exception& e) {
154  throw CoraCoolException(e.what(),"CoraCoolObjectIter::next");
155  }
156  // next read will access next object from buffer (if existing)
157  // this invocation will return first object
158  m_nextobj=1;
159  return;
160 }
161 
163  return (m_inbuf>m_nextobj || iHasNext());
164 }
165 
167  const bool nextExists=hasNext();
168  if (m_inbuf>m_nextobj){
169  ++m_nextobj;//just update the index
170  } else if (iHasNext()){
172  } else {
173  //throw CoraCoolException("No more data in CoraCoolObjectIter","CoraCoolObjectIter::goToNext");
174  }
175  return nextExists;
176 }
177 
179  return *(m_data.at(m_nextobj-1));
180 }
181 
183  // release any resources associated with the query
184  // close underlying COOL query
185  m_coolitr->close();
186  // release ownership of any CoraCoolObjects we have
187  for (unsigned int i=0;i<m_buflen;++i) m_data[i].reset();
188 }
189 
190 bool CoraCoolObjectIter::equalAttr(const coral::Attribute& a1, const coral::Attribute& a2) const
191 {
192  // compare two Attributes based on type and value
193  // deal with some special cases where the types are not the same
194  // the easy part - if types are same
195  std::string spec1=a1.specification().typeName();
196  std::string spec2=a2.specification().typeName();
197  if (spec1==spec2) {
198  return (a1==a2);
199  } else if (isNumAttr(spec1) && isNumAttr(spec2)) {
200  // convert to long long and compare
201  long long v1=numAttr(spec1,a1);
202  long long v2=numAttr(spec2,a2);
203  return (v1==v2);
204  } else {
205  // unhandled case
206  return false;
207  }
208 }
209 
211  // implement old-COOL-style iterator behaviour - return if next is valid
212  // can be called multiple times - after call currentRef will give data
213  if (m_refValid) return true;
214  if (m_allDone) return false;
215  if (m_coolitr->goToNext()) {
216  m_refValid=true;
217  return true;
218  } else {
219  m_refValid=false;
220  m_allDone=true;
221  return false;
222  }
223 }
224 
225 bool CoraCoolObjectIter::isNumAttr(const std::string& spec) const {
226  return (spec=="long long" || spec=="unsigned long long" ||
227  spec=="int" || spec=="unsigned int" ||
228  spec=="long" || spec=="unsigned long");
229 }
230 
231 long long CoraCoolObjectIter::numAttr(const std::string& spec,
232  const coral::Attribute& a) const {
233  long long v=0;
234  if (spec=="long long") {
235  v=a.data<long long>();
236  } else if (spec=="unsigned long long") {
237  v=static_cast<long long>(a.data<unsigned long long>());
238  } else if (spec=="int") {
239  v=static_cast<long long>(a.data<int>());
240  } else if (spec=="unsigned int") {
241  v=static_cast<long long>(a.data<unsigned int>());
242  } else if (spec=="long") {
243  v=static_cast<long long>(a.data<long>());
244  } else if (spec=="unsigned long") {
245  v=static_cast<long long>(a.data<unsigned long>());
246  }
247  return v;
248 }
249 
251  m_terms(0), m_size(0), m_maxsize(size) {
252  m_lower=new long long[m_maxsize];
253  m_upper=new long long[m_maxsize];
254 }
255 
257  delete [] m_lower;
258  delete [] m_upper;
259 }
260 
261 unsigned int CoraCoolObjectIter::QueryBuilder::add(const long long value) {
262  // add the given value to the query sequence
263  // find where it must be inserted
264  unsigned int i=0;
265  unsigned int j=0;
266  bool done=false;
267  for (unsigned int i=0;i<m_size;++i) {
268  if (m_lower[i]-value<2 && value-m_upper[i]<2) {
269  // current range contains object or can be extended by one to contain it
270  // value is in current range or extends it
271  if (m_lower[i]-value==1) --m_lower[i];
272  if (value-m_upper[i]==1) ++m_upper[i];
273  // if range is of size 1, just changed from one to two-term query
274  if (m_upper[i]-m_lower[i]==1) ++m_terms;
275  done=true;
276  break;
277  }
278  // check if value has to be inserted after this position, if not found
279  if (m_upper[i]<value) ++j;
280  }
281  if (not done) {
282  // did not add to an existing range - make a new one at j
283  // move existing values up
284  if (m_size<m_maxsize) {
285  for (i=m_size;i!=j;--i) {
286  m_lower[i]=m_lower[i-1];
287  m_upper[i]=m_upper[i-1];
288  }
289  ++m_size;
290  // add new range at j
291  m_lower[j]=value;
292  m_upper[j]=value;
293  ++m_terms;
294  } else {
295  // if not enough room, return zero to signal error
296  return 0;
297  }
298  }
299  return m_terms;
300 }
301 
303  const std::string& coralkey,
304  coral::AttributeList& fkeys,const coral::AttributeSpecification& spec) {
305  // try to compress the query by joining existing ranges if possible
306  unsigned int j=0;
307  for (unsigned int i=0;i<m_size;++i) {
308  long long lower=m_lower[i];
309  long long upper=m_upper[i];
310  // check if this range can be absorbed into previous one
311  if (i>0) {
312  if (m_lower[i]-m_upper[j]<2) {
313  // if so, adjust upper limit of previous range to encompass this one
314  // and do not copy current range
315  m_upper[j]=m_upper[i];
316  } else {
317  // note this never gets executed on first iteration - j lags 1 behind i
318  ++j;
319  m_lower[j]=lower;
320  m_upper[j]=upper;
321  }
322  }
323  }
324  m_size=j+1;
325  // build the query string and list of FK values to be used
326  unsigned int ikey=0;
327  for (unsigned int i=0;i<m_size;++i) {
328  if (where.size()>0) where+=" OR ";
329  if (m_lower[i]==m_upper[i]) {
330  // bounds are equal - simple equivalence term
331  std::string keyname=addKey(ikey,fkeys,spec,m_lower[i]);
332  where+=coralkey;
333  where+="=:";
334  where+=keyname;
335  } else {
336  // bounds are not equal - need A>=B and A<=C
337  std::string keyname=addKey(ikey,fkeys,spec,m_lower[i]);
338  where+='(';
339  where+=coralkey;
340  where+=">=:";
341  where+=keyname;
342  where+=" AND ";
343  where+=coralkey;
344  where+="<=:";
345 
346  keyname=addKey(ikey,fkeys,spec,m_upper[i]);
347  where+=keyname;
348  where+=')';
349  }
350  }
351 }
352 
353 std::string CoraCoolObjectIter::QueryBuilder::addKey(unsigned int& ikey,
354  coral::AttributeList& fkeys,const coral::AttributeSpecification& spec,
355  const long long value) {
356  // return the name of the FK and add it to the list of FK bind variables
357  std::ostringstream skey;
358  skey << "B" << ikey;
359  std::string keyname=skey.str();
360  fkeys.extend(keyname,spec.type());
361  std::string typeName=spec.typeName();
362  if (typeName=="long long") {
363  fkeys[keyname].data<long long>()=value;
364  } else if (typeName=="unsigned long long") {
365  fkeys[keyname].data<unsigned long long>()=value;
366  } else if (typeName=="int") {
367  fkeys[keyname].data<int>()=value;
368  } else if (typeName=="unsigned int") {
369  fkeys[keyname].data<unsigned int>()=value;
370  } else if (typeName=="long") {
371  fkeys[keyname].data<long>()=value;
372  } else if (typeName=="unsigned long") {
373  fkeys[keyname].data<unsigned long>()=value;
374  } else {
375  throw CoraCoolException("Unregognised type "+typeName,
376  "CoraCoolObjectIter::QueryBuilder::addKey");
377  }
378  ++ikey;
379  return keyname;
380 }
CoraCoolObjectIter::m_refValid
bool m_refValid
Definition: CoraCoolObjectIter.h:109
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
CoraCoolObjectIter::numAttr
long long numAttr(const std::string &spec, const coral::Attribute &a) const
Definition: CoraCoolObjectIter.cxx:231
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
CoraCoolObjectIter::m_nextobj
unsigned int m_nextobj
Definition: CoraCoolObjectIter.h:108
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
CoraCoolObject
Definition: CoraCoolObject.h:20
CoraCoolObjectIter::isNumAttr
bool isNumAttr(const std::string &spec) const
Definition: CoraCoolObjectIter.cxx:225
CoraCoolObjectIter::m_spec
coral::AttributeListSpecification * m_spec
Definition: CoraCoolObjectIter.h:113
CoraCoolObjectIter::QueryBuilder::QueryBuilder
QueryBuilder()
CaloCondBlobAlgs_fillNoiseFromASCII.spec
spec
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:47
CoraCoolObjectIter::QueryBuilder::getQuery
void getQuery(std::string &where, const std::string &coralkey, coral::AttributeList &fkeys, const coral::AttributeSpecification &spec)
Definition: CoraCoolObjectIter.cxx:302
CoraCoolFolder
Definition: CoraCoolFolder.h:37
CoraCoolObjectIter::QueryBuilder::size
unsigned int size() const
Definition: CoraCoolObjectIter.h:117
CoraCoolObjectIter::QueryBuilder::terms
unsigned int terms() const
Definition: CoraCoolObjectIter.h:119
CoraCoolObjectIter::CoraCoolObjectIter
CoraCoolObjectIter()
CoraCoolObjectIter::m_coolitr
cool::IObjectIteratorPtr m_coolitr
Definition: CoraCoolObjectIter.h:112
athena.value
value
Definition: athena.py:124
upper
int upper(int c)
Definition: LArBadChannelParser.cxx:49
python.PyKernel.AttributeList
AttributeList
Definition: PyKernel.py:36
CoraCoolFolder::table
coral::ITable * table()
Definition: CoraCoolFolder.cxx:575
CoraCoolObject.h
CoraCoolObjectIter::equalAttr
bool equalAttr(const coral::Attribute &a1, const coral::Attribute &a2) const
Definition: CoraCoolObjectIter.cxx:190
query
Definition: query.py:1
CoraCoolFolder::coralFKey
const std::string & coralFKey() const
Definition: CoraCoolFolder.h:191
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
CoraCoolObjectIter::QueryBuilder
Definition: CoraCoolObjectIter.h:68
CoraCoolObjectIter::m_folder
CoraCoolFolder * m_folder
Definition: CoraCoolObjectIter.h:111
lumiFormat.i
int i
Definition: lumiFormat.py:85
CoraCoolObjectIter::goToNext
bool goToNext()
Definition: CoraCoolObjectIter.cxx:166
OI_BUFLEN
#define OI_BUFLEN
Definition: CoraCoolObjectIter.cxx:29
CoraCoolObjectIter::QueryBuilder::m_upper
long long * m_upper
Definition: CoraCoolObjectIter.h:98
CoraCoolFolder::payloadSpecification
const cool::RecordSpecification payloadSpecification() const
Definition: CoraCoolFolder.cxx:107
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:14
python.Utils.unixtools.where
def where(filename, prepath=[])
"which" for python files -------------------------------------------------—
Definition: unixtools.py:53
CoraCoolObjectIter::next
CoraCoolObjectPtr next()
Definition: CoraCoolObjectIter.cxx:53
query_example.query
query
Definition: query_example.py:15
CoraCoolFolder::proxy
coral::ISessionProxy * proxy()
Definition: CoraCoolFolder.h:200
CoraCoolObjectIter::m_data
std::vector< CoraCoolObjectPtr > m_data
Definition: CoraCoolObjectIter.h:114
CoraCoolFolder.h
QB_TERMS
#define QB_TERMS
Definition: CoraCoolObjectIter.cxx:26
CoraCoolObjectIter::QueryBuilder::m_maxsize
unsigned int m_maxsize
Definition: CoraCoolObjectIter.h:96
CoraCoolFolder::setOutputSpec
void setOutputSpec(coral::IQuery *query)
Definition: CoraCoolFolder.cxx:489
QB_SIZE
#define QB_SIZE
Definition: CoraCoolObjectIter.cxx:25
CoraCoolObjectIter::m_allDone
bool m_allDone
Definition: CoraCoolObjectIter.h:110
PixelModuleFeMask_create_db.payload
string payload
Definition: PixelModuleFeMask_create_db.py:69
CoraCoolObjectIter::~CoraCoolObjectIter
~CoraCoolObjectIter()
Definition: CoraCoolObjectIter.cxx:49
CoraCoolObjectIter::iHasNext
bool iHasNext()
Definition: CoraCoolObjectIter.cxx:210
ReadCellNoiseFromCoolCompare.v2
v2
Definition: ReadCellNoiseFromCoolCompare.py:364
python.PyAthena.v
v
Definition: PyAthena.py:154
CoraCoolException
Definition: CoraCoolException.h:13
a
TList * a
Definition: liststreamerinfos.cxx:10
query_example.cursor
cursor
Definition: query_example.py:21
CoraCoolObjectIter::m_inbuf
unsigned int m_inbuf
Definition: CoraCoolObjectIter.h:107
CoraCoolObjectIter::currentRef
CoraCoolObject & currentRef()
Definition: CoraCoolObjectIter.cxx:178
CoraCoolObjectPtr
boost::shared_ptr< CoraCoolObject > CoraCoolObjectPtr
Definition: CoraCoolTypes.h:18
CxxUtils::reset
constexpr std::enable_if_t< is_bitmask_v< E >, E & > reset(E &lhs, E rhs)
Convenience function to clear bits in a class enum bitmask.
Definition: bitmask.h:251
ReadCalibFromCool.typeName
typeName
Definition: ReadCalibFromCool.py:477
CoraCoolObjectIter.h
CoraCoolObjectIter::QueryBuilder::~QueryBuilder
~QueryBuilder()
Definition: CoraCoolObjectIter.cxx:256
CoraCoolObjectIter::readDataToBuffer
void readDataToBuffer()
Definition: CoraCoolObjectIter.cxx:66
OI_ROWCACHE
#define OI_ROWCACHE
Definition: CoraCoolObjectIter.cxx:30
CoraCoolObjectIter::hasNext
bool hasNext()
Definition: CoraCoolObjectIter.cxx:162
CoraCoolObjectIter::QueryBuilder::m_lower
long long * m_lower
Definition: CoraCoolObjectIter.h:97
CoraCoolException.h
CoraCoolObjectIter::m_buflen
unsigned int m_buflen
Definition: CoraCoolObjectIter.h:106
CoraCoolObjectIter::QueryBuilder::addKey
std::string addKey(unsigned int &key, coral::AttributeList &fkeys, const coral::AttributeSpecification &spec, const long long value)
Definition: CoraCoolObjectIter.cxx:353
CoraCoolObjectIter::close
void close()
Definition: CoraCoolObjectIter.cxx:182
CoraCoolObjectIter::QueryBuilder::add
unsigned int add(const long long value)
Definition: CoraCoolObjectIter.cxx:261