• Main Page
  • Classes
  • Files
  • File List

timeseries.h

00001 //-< TIMESERIES.H >--------------------------------------------------*--------*
00002 // GigaBASE                  Version 1.0         (c) 1999  GARRET    *     ?  *
00003 // (Post Relational Database Management System)                      *   /\|  *
00004 //                                                                   *  /  \  *
00005 //                          Created:     22-Nov-2002  K.A. Knizhnik  * / [] \ *
00006 //                          Last update: 22-Nov-2002  K.A. Knizhnik  * GARRET *
00007 //-------------------------------------------------------------------*--------*
00008 // Container for time serires data
00009 //-------------------------------------------------------------------*--------*
00010 
00011 #ifndef __TIMESERIES_H__
00012 #define __TIMESERIES_H__
00013 
00014 #include "gigabase.h"
00015 
00016 BEGIN_GIGABASE_NAMESPACE
00017 
00018 #define INFINITE_TIME 0x7fffffff
00019 
00070 template<class T>
00071 class dbTimeSeriesBlock { 
00072   public:
00073     db_int8 blockId;
00074     db_int4 used;
00075     dbArray<T> elements;
00076   
00077     TYPE_DESCRIPTOR((KEY(blockId, INDEXED), FIELD(used), FIELD(elements)));
00078 };
00079 
00080 
00086 template<class T>
00087 class dbTimeSeriesProcessor { 
00088     struct Interval { 
00089         db_int8 from;
00090         db_int8 till;
00091     };
00092 
00093   public:
00098     virtual void process(T const& data) {}
00099     
00105     void add(oid_t oid, T const& data) 
00106     { 
00107         Interval interval;
00108         interval.from = generateBlockId(oid, data.time() - maxBlockTimeInterval);
00109         interval.till = generateBlockId(oid, data.time());
00110         dbCursor< dbTimeSeriesBlock<T> > blocks;
00111         blocks.select(selectBlock, dbCursorForUpdate, &interval);
00112         if (blocks.last()) { 
00113             insertInBlock(oid, blocks, data);
00114         } else { 
00115             addNewBlock(oid, data);
00116         }
00117     }
00118 
00125     void select(oid_t oid, time_t from, time_t till) 
00126     { 
00127         Interval interval;
00128         interval.from = generateBlockId(oid, from - maxBlockTimeInterval);
00129         interval.till = generateBlockId(oid, till);
00130         dbCursor< dbTimeSeriesBlock<T> > blocks;
00131         if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
00132             do { 
00133                 int n = blocks->used;
00134                 T const* e =  blocks->elements.get();
00135                 int l = 0, r = n;
00136                 while (l < r)  {
00137                     int i = (l+r) >> 1;
00138                     if (from > e[i].time()) { 
00139                         l = i+1;
00140                     } else { 
00141                         r = i;
00142                     }
00143                 }
00144                 assert(l == r && (l == n || e[l].time() >= from)); 
00145                 while (l < n && e[l].time() <= till) {
00146                     process(e[l++]);
00147                 }
00148             } while (blocks.next());
00149         }
00150     }
00151     
00157     time_t getFirstTime(oid_t oid) 
00158     {
00159         Interval interval;
00160         interval.from = generateBlockId(oid, 0);
00161         interval.till = generateBlockId(oid, INFINITE_TIME);
00162         dbCursor< dbTimeSeriesBlock<T> > blocks;
00163         blocks.setSelectionLimit(1);
00164         if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
00165             return blocks->elements[0].time();
00166         }
00167         return (time_t)-1;
00168     }
00169     
00175     time_t getLastTime(oid_t oid) 
00176     {
00177         Interval interval;
00178         interval.from = generateBlockId(oid, 0);
00179         interval.till = generateBlockId(oid, INFINITE_TIME);
00180         dbCursor< dbTimeSeriesBlock<T> > blocks;
00181         blocks.setSelectionLimit(1);
00182         if (blocks.select(selectBlockReverse, dbCursorViewOnly, &interval)) { 
00183             return blocks->elements[blocks->used-1].time();
00184         }
00185         return (time_t)-1;
00186     }
00187     
00193     size_t getNumberOfElements(oid_t oid) 
00194     {
00195         Interval interval;
00196         interval.from = generateBlockId(oid, 0);
00197         interval.till = generateBlockId(oid, INFINITE_TIME);
00198         dbCursor< dbTimeSeriesBlock<T> > blocks;
00199         int n = 0;
00200         if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) {
00201             do { 
00202                 n += blocks->used;
00203             } while (blocks.next());
00204         }
00205         return n;
00206     }
00207         
00217     size_t getInterval(oid_t oid, time_t from, time_t till, T* buf, size_t bufSize) 
00218     { 
00219         Interval interval;
00220         interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
00221         interval.till = generateBlockId(oid, till);
00222         dbCursor< dbTimeSeriesBlock<T> > blocks;
00223         size_t nSelected = 0;
00224         if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
00225             do { 
00226                 int n = blocks->used;
00227                 T const* e =  blocks->elements.get();
00228                 int l = 0, r = n;
00229                 while (l < r)  {
00230                     int i = (l+r) >> 1;
00231                     if (from > e[i].time()) { 
00232                         l = i+1;
00233                     } else { 
00234                         r = i;
00235                     }
00236                 }
00237                 assert(l == r && (l == n || e[l].time() >= from)); 
00238                 while (l < n && e[l].time() <= till) {
00239                     if (nSelected < bufSize) { 
00240                         buf[nSelected] = e[l];
00241                     }
00242                     l += 1;
00243                     nSelected += 1;
00244                 }
00245             } while (blocks.next());
00246         }
00247         return nSelected;
00248     }        
00249         
00257     bool getElement(oid_t oid, T& elem, time_t t) 
00258     { 
00259         return getInterval(oid, t, t, &elem, 1) == 1;
00260     }        
00261         
00271     size_t getFirstInterval(oid_t oid, time_t till, T* buf, size_t bufSize) 
00272     {
00273         if (bufSize == 0) { 
00274             return 0;
00275         }
00276         Interval interval;
00277         interval.from = generateBlockId(oid, 0);
00278         interval.till = generateBlockId(oid, till);
00279         dbCursor< dbTimeSeriesBlock<T> > blocks;
00280         size_t nSelected = 0;
00281         if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
00282             do { 
00283                 int n = blocks->used;
00284                 T const* e =  blocks->elements.get();
00285                 for (int i = 0; i < n && e[i].time() <= till; i++) { 
00286                     buf[nSelected++] = e[i];
00287                     if (nSelected == bufSize) { 
00288                         return nSelected;
00289                     }
00290                 }
00291             } while (blocks.next());
00292         }
00293         return nSelected;
00294     }        
00295 
00296 
00306     size_t getLastInterval(oid_t oid, time_t from, T* buf, size_t bufSize) 
00307     {
00308         if (bufSize == 0) { 
00309             return 0;
00310         }
00311         Interval interval;
00312         interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
00313         interval.till = generateBlockId(oid, INFINITE_TIME);
00314         dbCursor< dbTimeSeriesBlock<T> > blocks;
00315 
00316         size_t nSelected = 0;
00317         blocks.select(selectBlock, dbCursorViewOnly, &interval);
00318         if (blocks.last()) { 
00319             do { 
00320                 int n = blocks->used;
00321                 T const* e =  blocks->elements.get();
00322                 for (int i = n; --i >= 0 && e[i].time() >= from;) { 
00323                     buf[nSelected++] = e[i];
00324                     if (nSelected == bufSize) { 
00325                         return nSelected;
00326                     }
00327                 }
00328             } while (blocks.prev());
00329         }
00330         return nSelected;
00331     }        
00332 
00333 
00334 
00341     bool hasElement(oid_t oid, time_t t) 
00342     { 
00343         T dummy;
00344         return getElement(oid, dummy, t);
00345     }        
00346 
00358     dbTimeSeriesProcessor(dbDatabase& database, int minElementsInBlock=100, int maxElementsInBlock=100, time_t maxBlockTimeInterval=0) :
00359         db(database) 
00360     {
00361         assert(minElementsInBlock > 0 && maxElementsInBlock >= minElementsInBlock);
00362         if (maxBlockTimeInterval == 0) { 
00363             maxBlockTimeInterval = 2*(maxElementsInBlock*24*60*60); // doubled interval in seconds, one element per day
00364         }        
00365         this->maxElementsInBlock = maxElementsInBlock;
00366         this->minElementsInBlock = minElementsInBlock;
00367         this->maxBlockTimeInterval = maxBlockTimeInterval;
00368 
00369         // correct instance of interval will be specified in select
00370         Interval* dummy = NULL;
00371         selectBlock = "blockId between",dummy->from,"and",dummy->till;
00372         selectBlockReverse = "blockId between",dummy->from,"and",dummy->till,"order by blockId desc";
00373     }
00374 
00382     int remove(oid_t oid, time_t from, time_t till)
00383     {
00384         Interval interval;
00385         interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
00386         interval.till = generateBlockId(oid, till);
00387         dbCursor< dbTimeSeriesBlock<T> > blocks;
00388         size_t nRemoved = 0;
00389         if (blocks.select(selectBlock, dbCursorForUpdate, &interval)) { 
00390             do { 
00391                 int n = blocks->used;
00392                 T const* e =  blocks->elements.get();
00393                 int l = 0, r = n;
00394                 while (l < r)  {
00395                     int i = (l+r) >> 1;
00396                     if (from > e[i].time()) { 
00397                         l = i+1;
00398                     } else { 
00399                         r = i;
00400                     }
00401                 }
00402                 assert(l == r && (l == n || e[l].time() >= from)); 
00403                 while (r < n && e[r].time() <= till) {
00404                     r += 1;
00405                     nRemoved += 1;
00406                 }
00407                 if (l == 0 && r == n) { 
00408                     blocks.remove();
00409                 } else if (l < n && l != r) { 
00410                     if (l == 0) { 
00411                         blocks->blockId = generateBlockId(oid, e[r].time());
00412                     }
00413                     T* ue = blocks->elements.update();
00414                     while (r < n) { 
00415                         ue[l++] = ue[r++];
00416                     }
00417                     blocks->used = l;
00418                     blocks.update();
00419                 }
00420             } while (blocks.next());
00421         }
00422         return nRemoved;
00423     }        
00424     
00425     virtual~dbTimeSeriesProcessor() {}
00426 
00432     int _openIteratorCursor(dbCursor< dbTimeSeriesBlock<T> >& cursor, oid_t oid, time_t from, time_t till) 
00433     { 
00434         Interval interval;
00435         interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
00436         interval.till = generateBlockId(oid, till);
00437         return cursor.select(selectBlock, dbCursorViewOnly, &interval);
00438     }
00439 
00440    private:
00441      db_int8 generateBlockId(oid_t oid, time_t date) 
00442      {
00443         return cons_int8(oid, date);
00444      }
00445      
00446      
00447      void addNewBlock(oid_t oid, T const& data)
00448      {
00449          dbTimeSeriesBlock<T> block;
00450          block.blockId = generateBlockId(oid, data.time());
00451          block.elements.resize(minElementsInBlock);
00452          block.used = 1;
00453          block.elements.putat(0, data);
00454          insert(block);
00455      }
00456 
00457      void insertInBlock(oid_t oid, dbCursor< dbTimeSeriesBlock<T> >& blocks, T const& data)
00458      {
00459          time_t t = data.time();
00460          int i, n = blocks->used;
00461 
00462          T const* e =  blocks->elements.get();
00463          int l = 0, r = n;
00464          while (l < r)  {
00465              i = (l+r) >> 1;
00466              if (t > e[i].time()) { 
00467                  l = i+1;
00468              } else { 
00469                  r = i;
00470              }
00471          }
00472          assert(l == r && (l == n || e[l].time() >= t));
00473          if (r == 0) { 
00474              if (e[n-1].time() - t > maxBlockTimeInterval || n == maxElementsInBlock) { 
00475                  addNewBlock(oid, data);
00476                  return;
00477              }
00478              blocks->blockId = generateBlockId(oid, t);
00479          } else if (r == n) {
00480              if (t - e[0].time() > maxBlockTimeInterval || n == maxElementsInBlock) { 
00481                  addNewBlock(oid, data);
00482                  return;
00483              } 
00484          }
00485          if ((size_t)n == blocks->elements.length()) { 
00486              if (n == maxElementsInBlock) { 
00487                  T* u = blocks->elements.update();
00488                  addNewBlock(oid, u[n-1]);
00489                  for (i = n; --i > r; ) { 
00490                      u[i] = u[i-1];
00491                  }
00492                  u[r] = data;
00493                  blocks.update();
00494                  return;
00495              }
00496              blocks->elements.resize(n + minElementsInBlock < maxElementsInBlock ? n + minElementsInBlock : maxElementsInBlock);
00497          }
00498          T* u = blocks->elements.update();
00499          for (i = n; i > r; i--) { 
00500              u[i] = u[i-1];
00501          }
00502          u[r] = data;
00503          blocks->used += 1;
00504          blocks.update();
00505      }
00506 
00507      dbDatabase& db;
00508      int         maxElementsInBlock;
00509      int         minElementsInBlock;
00510      time_t      maxBlockTimeInterval;     
00511      dbQuery     selectBlock;
00512      dbQuery     selectBlockReverse; 
00513 };
00514     
00515 
00519 template<class T>
00520 class dbTimeSeriesIterator { 
00521   public:
00529     void start(dbTimeSeriesProcessor<T>* processor, oid_t oid, time_t from, time_t till) { 
00530         first = pos = -1;
00531         this->till = till;
00532         if (processor->_openIteratorCursor(blocks, oid, from, till)) { 
00533             do { 
00534                 int n = blocks->used;
00535                 T const* e =  blocks->elements.get();
00536                 int l = 0, r = n;
00537                 while (l < r)  {
00538                     int i = (l+r) >> 1;
00539                     if (from > e[i].time()) { 
00540                         l = i+1;
00541                     } else { 
00542                         r = i;
00543                     }
00544                 }
00545                 assert(l == r && (l == n || e[l].time() >= from)); 
00546                 if (l < n) { 
00547                     if (e[l].time() <= till) {
00548                         first = pos = l;
00549                     }
00550                     return;
00551                 }
00552             } while (blocks.next());
00553         }        
00554     }
00555             
00560     bool current(T& elem) { 
00561         if (pos >= 0) { 
00562             elem = blocks->elements[pos];
00563             return true;
00564         }
00565         return false;
00566     }
00567     
00572     bool next() { 
00573         if (pos >= 0) { 
00574             if (++pos == blocks->used) { 
00575                 if (!blocks.next()) { 
00576                     pos = -1;
00577                     return false;
00578                 }
00579                 pos = 0;
00580             }
00581             if (blocks->elements[pos].time() <= till) {
00582                 return true;
00583             }
00584             pos = -1;
00585         }
00586         return false;
00587     }
00588 
00592     void reset() { 
00593         blocks.first();
00594         pos = first;
00595     }
00596     
00601     dbTimeSeriesIterator() {
00602         first = pos = -1;
00603     }
00604   private:
00605     dbCursor< dbTimeSeriesBlock<T> > blocks;
00606     int                              pos;
00607     int                              first;
00608     time_t                           till;
00609 };
00610     
00614 template<class T>
00615 class dbTimeSeriesReverseIterator { 
00616   public:
00624     void start(dbTimeSeriesProcessor<T>* processor, oid_t oid, time_t from, time_t till) { 
00625         last = pos = -1;
00626         this->from = from;
00627         if (processor->_openIteratorCursor(blocks, oid, from, till)) { 
00628             do { 
00629                 int n = blocks->used;
00630                 blocks.last();
00631                 T const* e =  blocks->elements.get();
00632                 int l = 0, r = n;
00633                 while (l < r)  {
00634                     int i = (l+r) >> 1;
00635                     if (till >= e[i].time()) { 
00636                         l = i+1;
00637                     } else { 
00638                         r = i;
00639                     }
00640                 }
00641                 assert(l == r && (l == n || e[l].time() > till)); 
00642                 if (l > 0) {
00643                     if (e[l-1].time() >= from) {
00644                         last = pos = l-1;
00645                     }
00646                     return;
00647                 }
00648             } while (blocks.prev());
00649         }        
00650     }
00651             
00656     bool current(T& elem) { 
00657         if (pos >= 0) { 
00658             elem = blocks->elements[pos];
00659             return true;
00660         }
00661         return false;
00662     }
00663     
00668     bool next() { 
00669         if (pos >= 0) { 
00670             if (--pos < 0) {
00671                 if (!blocks.prev()) { 
00672                     return false;
00673                 }
00674                 pos = blocks->used-1;
00675             }
00676             if (blocks->elements[pos].time() >= from) {
00677                 return true;
00678             }
00679             pos = -1;
00680         }
00681         return false;
00682     }
00683 
00687     void reset() { 
00688         blocks.last();
00689         pos = last;
00690     }
00691     
00696     dbTimeSeriesReverseIterator() {
00697         last = pos = -1;
00698     }
00699   private:
00700     dbCursor< dbTimeSeriesBlock<T> > blocks;
00701     int                              pos;
00702     int                              last;
00703     time_t                           from;
00704 };
00705     
00706 END_GIGABASE_NAMESPACE
00707 
00708 #endif

Generated on Mon Aug 23 2010 00:04:01 for GigaBASE by  doxygen 1.7.1