ATLAS Offline Software
Loading...
Searching...
No Matches
CoraCoolObjectIter.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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) :
35 m_refValid(false),m_allDone(false),
36 m_folder(coracoolfolder),m_coolitr(std::move(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
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
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);
124 m_folder->setOutputSpec(query);
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
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
190bool 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
225bool 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
231long 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
260
261unsigned 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
353std::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}
#define QB_TERMS
#define QB_SIZE
#define OI_BUFLEN
#define OI_ROWCACHE
boost::shared_ptr< CoraCoolObject > CoraCoolObjectPtr
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
std::pair< std::vector< unsigned int >, bool > res
int upper(int c)
static Double_t a
std::string addKey(unsigned int &key, coral::AttributeList &fkeys, const coral::AttributeSpecification &spec, const long long value)
unsigned int add(const long long value)
void getQuery(std::string &where, const std::string &coralkey, coral::AttributeList &fkeys, const coral::AttributeSpecification &spec)
CoraCoolObjectPtr next()
cool::IObjectIteratorPtr m_coolitr
bool isNumAttr(const std::string &spec) const
long long numAttr(const std::string &spec, const coral::Attribute &a) const
bool equalAttr(const coral::Attribute &a1, const coral::Attribute &a2) const
coral::AttributeListSpecification * m_spec
std::vector< CoraCoolObjectPtr > m_data
CoraCoolFolder * m_folder
CoraCoolObject & currentRef()
Definition query.py:1
STL namespace.