LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
DBFolder.cxx
Go to the documentation of this file.
1 #ifndef DBFOLDER_CXX
2 #define DBFOLDER_CXX 1
3 
4 #include "DBFolder.h"
5 #include "WebDBIConstants.h"
6 #include "larevt/CalibrationDBI/IOVData/IOVDataConstants.h"
7 #include "larevt/CalibrationDBI/IOVData/TimeStampDecoder.h"
8 #include "WebError.h"
9 #include <sstream>
10 #include <limits>
11 #include <iomanip>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <cstring>
15 #include "wda.h"
16 
17 namespace lariov {
18 
19  typedef struct {
20  size_t ncolumns; // Number of columns in CSV row
21  size_t nelements; // Number of elements in data array
22  char **columns; // Pointers to columns
23  } DataRec;
24 
25  DBFolder::DBFolder(const std::string& name, const std::string& url, const std::string& tag /*= ""*/) :
26  fCachedStart(0,0), fCachedEnd(0,0) {
27 
28  fFolderName = name;
29  fURL = url;
30  fTag = tag;
31  if (fURL[fURL.length()-1] == '/') {
32  fURL = fURL.substr(0, fURL.length()-1);
33  }
34 
35  fCachedDataset = 0;
36  fNRows =0;
37  fColumns.clear();
38  fTypes.clear();
39  fCachedRow = -1;
40  fCachedChannel = 0;
41 
42  fMaximumTimeout = 4*60; //4 minutes
43  }
44 
46  if (fCachedDataset) releaseDataset(fCachedDataset);
47  }
48 
49  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, bool& data) {
50 
51  Tuple tup;
52  size_t col = this->GetTupleColumn(channel, name, tup);
53  int err=0;
54  char buf[kBUFFER_SIZE];
55  int str_size = getStringValue(tup, col, buf, kBUFFER_SIZE, &err);
56  data = false;
57  if (std::string(buf, str_size)=="True") {
58  data = true;
59  }
60  else if (std::string(buf, str_size)=="False") {
61  data = false;
62  }
63  else std::cout<<"(DBFolder) ERROR: Can't identify data: "<<std::string(buf, str_size)<<" as boolean!"<<std::endl;
64 
65  releaseTuple(tup);
66  return err;
67  }
68 
69  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, long& data) {
70 
71  Tuple tup;
72  size_t col = this->GetTupleColumn(channel, name, tup);
73  int err=0;
74 
75  //first handle special case that the db data is boolean, but user mistakenly used long version of this function
76  char buf[kBUFFER_SIZE];
77  int str_size = getStringValue(tup, col, buf, kBUFFER_SIZE, &err);
78  if (std::string(buf, str_size)=="True") {
79  data = 1;
80  }
81  else if (std::string(buf, str_size)=="False") {
82  data = 0;
83  }
84  else { //ok, we really have a long (hopefully)
85  data = getLongValue(tup, col, &err);
86  }
87  releaseTuple(tup);
88  return err;
89  }
90 
91  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, double& data) {
92 
93  Tuple tup;
94  size_t col = this->GetTupleColumn(channel, name, tup);
95  int err=0;
96  data = getDoubleValue(tup, col, &err);
97  releaseTuple(tup);
98  return err;
99  }
100 
101  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, std::string& data) {
102 
103  Tuple tup;
104  size_t col = this->GetTupleColumn(channel, name, tup);
105  int err=0;
106  char buf[kBUFFER_SIZE];
107  int str_size = getStringValue(tup, col, buf, kBUFFER_SIZE, &err);
108  data = std::string(buf, str_size);
109  releaseTuple(tup);
110  return err;
111  }
112 
113  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, std::vector<double>& data) {
114 
115  data.clear();
116 
117  Tuple tup;
118  size_t col = this->GetTupleColumn(channel, name, tup);
119  int err=0;
120  double buf[kBUFFER_SIZE];
121 
122  DataRec *dataRec = (DataRec *)tup;
123  // for c2: col is an unsigned int and cannot be less than 0
124  // if (col < 0 || col >= dataRec->ncolumns) {
125  if (col >= dataRec->ncolumns) {
126  err=-1;
127  return err;
128  }
129 
130  char* sptr = dataRec->columns[col];
131  if ( *sptr == '[') sptr +=1; //expect an initial bracket and skip it
132  else {
133  err=-2;
134  return err;
135  }
136 
137  char* eptr;
138  double val;
139  unsigned int array_size=0;
140  for (unsigned int i=0; i < kBUFFER_SIZE; ++i) {
141  val = strtod(sptr, &eptr); //Try to convert
142  if (sptr==eptr) break; //conversion failed
143  if (*sptr=='\0') break; //end loop if buffer ends
144 
145  buf[array_size++] = val;
146 
147  if ( *eptr == ']') break; //found the closing bracket, we're done
148  else sptr = eptr+1; //point to the next value
149  }
150 
151  data.insert(data.begin(), buf, buf + array_size);
152  releaseTuple(tup);
153  return err;
154  }
155 
156  int DBFolder::GetChannelList( std::vector<DBChannelID_t>& channels ) const {
157 
158  channels.clear();
159  if (!fCachedDataset) return 1;
160 
161  Tuple tup;
162  int err=0;
163  for ( int row = 0; row != fNRows; ++row) {
164  tup = getTuple(fCachedDataset, row + kNUMBER_HEADER_ROWS);
165  channels.push_back( (DBChannelID_t)getLongValue(tup,0,&err) );
166  releaseTuple(tup);
167  }
168  return err;
169  }
170 
171 
172  size_t DBFolder::GetTupleColumn(DBChannelID_t channel, const std::string& name, Tuple& tup ) {
173 
174  //check if cached row is still valid
175  int err;
176  int row = -1;
177  if (fCachedRow != -1 && fCachedChannel == channel) {
178  tup = getTuple(fCachedDataset, fCachedRow + kNUMBER_HEADER_ROWS);
179  if ( channel == (DBChannelID_t)getLongValue(tup,0,&err) ) {
180  row = fCachedRow;
181  }
182  else releaseTuple(tup);
183  }
184 
185  //if cached row is not valid, find the new row
186  if (row == -1) {
187 //std::cout<<"Channel "<<channel<<" not cached"<<std::endl;
188  //binary search for channel
189  DBChannelID_t val;
190  int l = 0, h = fNRows - 1;
191  row = (l + h )/2;
192  while ( l <= h ) {
193 //std::cout<<" "<<l<<" "<<h<<" "<<row<<std::endl;
194  tup = getTuple(fCachedDataset, row + kNUMBER_HEADER_ROWS);
195  val = getLongValue(tup, 0, &err);
196  releaseTuple(tup);
197 
198  if (val == channel ) break;
199 
200  if (val > channel) h = row - 1;
201  else l = row + 1;
202 
203  row = (l + h)/2;
204  }
205 
206  //get the tuple to be returned, check that the found row matches the requested channel
207  tup = getTuple(fCachedDataset, row + kNUMBER_HEADER_ROWS);
208  if ( channel != (DBChannelID_t)getLongValue(tup, 0, &err) ) {
209  releaseTuple(tup);
210  std::string msg = "Channel " + std::to_string(channel) + " is not found in database!";
211  throw WebError(msg);
212  }
213 
214 
215  //update caching info
216  fCachedChannel = channel;
217  fCachedRow = row;
218 
219  }
220 
221  //get the column corresponding to input string name and return
222  for (size_t c=1; c < fColumns.size(); ++c ) {
223  if (name == fColumns[c]) return c;
224  }
225 
226  std::string msg = "Column named " + name + " is not found in the database!";
227  throw WebError(msg);
228  return 0;
229  }
230 
231  //returns true if an Update is performed, false if not
232  bool DBFolder::UpdateData( DBTimeStamp_t raw_time) {
233 
234  //convert to IOVTimeStamp
235  IOVTimeStamp ts = TimeStampDecoder::DecodeTimeStamp(raw_time);
236 
237  //check if cache is updated
238  if (this->IsValid(ts)) return false;
239 
240  int err=0;
241 
242  //release old dataset
243  if (fCachedDataset) releaseDataset(fCachedDataset);
244 
245  //get full url string
246  std::stringstream fullurl;
247  fullurl << fURL << "/data?f=" << fFolderName
248  << "&t=" << ts.DBStamp();
249  if (fTag.length() > 0) fullurl << "&tag=" << fTag;
250 
251  //get new dataset
252  int status = -1;
253  fCachedDataset = getDataWithTimeout(fullurl.str().c_str(), NULL, fMaximumTimeout, &err);
254  status = getHTTPstatus(fCachedDataset);
255 
256  //Can add some more queries here if we get http error 504
257  /*if (status == 504) {
258  //try again
259  }*/
260 
261  if (status != 200) {
262  std::string msg = "HTTP error from " + fullurl.str()+": status: " + std::to_string(status) + ": " + std::string(getHTTPmessage(fCachedDataset));
263  throw WebError(msg);
264  }
265 
266  //update info about cached data
267  fNRows = getNtuples(fCachedDataset) - kNUMBER_HEADER_ROWS;
268  //std::cout<<"Retrieved "<<fNRows<<" rows from "<<fullurl.str()<<std::endl;
269  if (fNRows < 1) {
270  std::stringstream msg;
271  msg << "Time " << ts.DBStamp() << ": Data not found in database.";
272  throw WebError(msg.str());
273  fCachedStart = fCachedEnd = ts;
274  }
275 
276  //start and end times
277  Tuple tup;
278  tup = getTuple(fCachedDataset, 0);
279  char buf[kBUFFER_SIZE];
280  getStringValue(tup,0, buf, kBUFFER_SIZE, &err);
281  fCachedStart = IOVTimeStamp::GetFromString(std::string(buf));
282  releaseTuple(tup);
283 
284  tup = getTuple(fCachedDataset, 1);
285  getStringValue(tup,0, buf, kBUFFER_SIZE, &err);
286  if ( 0 == strcmp(buf,"-") ) {
287  fCachedEnd = IOVTimeStamp::MaxTimeStamp();
288  }
289  else {
290  fCachedEnd = IOVTimeStamp::GetFromString(std::string(buf));
291  }
292  releaseTuple(tup);
293 
294  //column names
295  tup = getTuple(fCachedDataset, 2);
296  fColumns.clear();
297  for (int c=0; c < getNfields(tup); ++c) {
298  getStringValue(tup, c, buf, kBUFFER_SIZE, &err);
299  fColumns.push_back(buf);
300  }
301  releaseTuple(tup);
302 
303  //column types
304  tup = getTuple(fCachedDataset, 3);
305  fTypes.clear();
306  for (int c=0; c < getNfields(tup); ++c) {
307  getStringValue(tup, c, buf, kBUFFER_SIZE, &err);
308  fTypes.push_back(buf);
309  }
310  releaseTuple(tup);
311 
312  return true;
313  }
314 
315 }//end namespace lariov
316 
317 #endif
318 
319 
320 
const unsigned int kNUMBER_HEADER_ROWS
std::string fURL
Definition: DBFolder.h:47
virtual ~DBFolder()
Definition: DBFolder.cxx:45
int GetNamedChannelData(DBChannelID_t channel, const std::string &name, bool &data)
Definition: DBFolder.cxx:49
bool UpdateData(DBTimeStamp_t raw_time)
Definition: DBFolder.cxx:232
size_t GetTupleColumn(DBChannelID_t channel, const std::string &name, Tuple &tup)
Definition: DBFolder.cxx:172
IOVTimeStamp fCachedStart
Definition: DBFolder.h:54
DBFolder(const std::string &name, const std::string &url, const std::string &tag="")
Definition: DBFolder.cxx:25
void * Tuple
Definition: DBFolder.h:13
char ** columns
Definition: DBFolder.cxx:22
int GetChannelList(std::vector< DBChannelID_t > &channels) const
Definition: DBFolder.cxx:156
DBChannelID_t fCachedChannel
Definition: DBFolder.h:59
int fMaximumTimeout
Definition: DBFolder.h:50
bool IsValid(const IOVTimeStamp &time) const
Definition: DBFolder.h:41
std::vector< std::string > fTypes
Definition: DBFolder.h:57
Int_t col[ntarg]
Definition: Style.C:29
std::string fFolderName
Definition: DBFolder.h:48
const unsigned int kBUFFER_SIZE
IOVTimeStamp fCachedEnd
Definition: DBFolder.h:55
std::string fTag
Definition: DBFolder.h:49
Filters for channels, events, etc.
Dataset fCachedDataset
Definition: DBFolder.h:52
std::vector< std::string > fColumns
Definition: DBFolder.h:56
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
size_t ncolumns
Definition: DBFolder.cxx:20
Collection of exception classes for WebDBI.
size_t nelements
Definition: DBFolder.cxx:21