📄 timeseries.h
字号:
* to doubled number of seconds in day multipied on maxElementsInBlock
*/
dbTimeSeriesProcessor(dbDatabase& database, int minElementsInBlock=100, int maxElementsInBlock=100, time_t maxBlockTimeInterval=0) :
db(database)
{
assert(minElementsInBlock > 0 && maxElementsInBlock >= minElementsInBlock);
if (maxBlockTimeInterval == 0) {
maxBlockTimeInterval = 2*(maxElementsInBlock*24*60*60); // doubled interval in seconds, one element per day
}
this->maxElementsInBlock = maxElementsInBlock;
this->minElementsInBlock = minElementsInBlock;
this->maxBlockTimeInterval = maxBlockTimeInterval;
// correct instance of interval will be specified in select
Interval* dummy = NULL;
selectBlock = "blockId between",dummy->from,"and",dummy->till;
selectBlockReverse = "blockId between",dummy->from,"and",dummy->till,"order by blockId desc";
}
/**
* Remove elements for the sepcified period
* @param oid time series identifer (OID of the object associated with this time series)
* @param from inclusive low bound for element timestamp (set 0 to disable this criteria)
* @param till inclusive high bound for element timestamp (set INFINITE_TIME to disable this criteria)
* @return number of removed elements
*/
int remove(oid_t oid, time_t from, time_t till)
{
Interval interval;
interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
interval.till = generateBlockId(oid, till);
dbCursor< dbTimeSeriesBlock<T> > blocks;
size_t nRemoved = 0;
if (blocks.select(selectBlock, dbCursorForUpdate, &interval)) {
do {
int n = blocks->used;
T const* e = blocks->elements.get();
int l = 0, r = n;
while (l < r) {
int i = (l+r) >> 1;
if (from > e[i].time()) {
l = i+1;
} else {
r = i;
}
}
assert(l == r && (l == n || e[l].time() >= from));
while (r < n && e[r].time() <= till) {
r += 1;
nRemoved += 1;
}
if (l == 0 && r == n) {
blocks.remove();
} else if (l < n && l != r) {
if (l == 0) {
blocks->blockId = generateBlockId(oid, e[r].time());
}
T* ue = blocks->elements.update();
while (r < n) {
ue[l++] = ue[r++];
}
blocks->used = l;
blocks.update();
}
} while (blocks.nextAvailable());
}
return nRemoved;
}
virtual~dbTimeSeriesProcessor() {}
/**
* This method should be actually private but since there is no portable way of declaration
* of friend templates classes recognized by all C++ compiler, it is made public.
* Do not use this method yourself.
*/
int _openIteratorCursor(dbCursor< dbTimeSeriesBlock<T> >& cursor, oid_t oid, time_t from, time_t till)
{
Interval interval;
interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
interval.till = generateBlockId(oid, till);
return cursor.select(selectBlock, dbCursorViewOnly, &interval);
}
private:
db_int8 generateBlockId(oid_t oid, time_t date)
{
return cons_int8(oid, date);
}
void addNewBlock(oid_t oid, T const& data)
{
dbTimeSeriesBlock<T> block;
block.blockId = generateBlockId(oid, data.time());
block.elements.resize(minElementsInBlock);
block.used = 1;
block.elements.putat(0, data);
insert(block);
}
void insertInBlock(oid_t oid, dbCursor< dbTimeSeriesBlock<T> >& blocks, T const& data)
{
time_t t = data.time();
int i, n = blocks->used;
T const* e = blocks->elements.get();
int l = 0, r = n;
while (l < r) {
i = (l+r) >> 1;
if (t > e[i].time()) {
l = i+1;
} else {
r = i;
}
}
assert(l == r && (l == n || e[l].time() >= t));
if (r == 0) {
if (e[n-1].time() - t > maxBlockTimeInterval || n == maxElementsInBlock) {
addNewBlock(oid, data);
return;
}
blocks->blockId = generateBlockId(oid, t);
} else if (r == n) {
if (t - e[0].time() > maxBlockTimeInterval || n == maxElementsInBlock) {
addNewBlock(oid, data);
return;
}
}
if ((size_t)n == blocks->elements.length()) {
if (n == maxElementsInBlock) {
T* u = blocks->elements.update();
addNewBlock(oid, u[n-1]);
for (i = n; --i > r; ) {
u[i] = u[i-1];
}
u[r] = data;
blocks.update();
return;
}
blocks->elements.resize(n + minElementsInBlock < maxElementsInBlock ? n + minElementsInBlock : maxElementsInBlock);
}
T* u = blocks->elements.update();
for (i = n; i > r; i--) {
u[i] = u[i-1];
}
u[r] = data;
blocks->used += 1;
blocks.update();
}
dbDatabase& db;
int maxElementsInBlock;
int minElementsInBlock;
time_t maxBlockTimeInterval;
dbQuery selectBlock;
dbQuery selectBlockReverse;
};
/**
* Time series forward iterator
*/
template<class T>
class dbTimeSeriesIterator {
public:
/**
* Start iteration through elements belonging to the specified range.
* @param processor pointer to time series processor
* @param oid time series identifer (OID of the object associated with this time series)
* @param from inclusive low bound for element timestamp (set 0 to disable this criteria)
* @param till inclusive high bound for element timestamp (set INFINITE_TIME to disable this criteria)
*/
void start(dbTimeSeriesProcessor<T>* processor, oid_t oid, time_t from, time_t till) {
first = pos = -1;
this->till = till;
if (processor->_openIteratorCursor(blocks, oid, from, till)) {
do {
int n = blocks->used;
T const* e = blocks->elements.get();
int l = 0, r = n;
while (l < r) {
int i = (l+r) >> 1;
if (from > e[i].time()) {
l = i+1;
} else {
r = i;
}
}
assert(l == r && (l == n || e[l].time() >= from));
if (l < n) {
if (e[l].time() <= till) {
first = pos = l;
}
return;
}
} while (blocks.next());
}
}
/**
* Get current iterator element
* @return <code>true</code> if there is current element, <code>false</code> otherwise
*/
bool current(T& elem) {
if (pos >= 0) {
elem = blocks->elements[pos];
return true;
}
return false;
}
/**
* Move iterator position to next element.
* @return <code>true</code> if next element exists, <code>false</code> otherwise
*/
bool next() {
if (pos >= 0) {
if (++pos == blocks->used) {
if (!blocks.next()) {
pos = -1;
return false;
}
pos = 0;
}
if (blocks->elements[pos].time() <= till) {
return true;
}
pos = -1;
}
return false;
}
/**
* Reset iterator to the initial state
*/
void reset() {
blocks.first();
pos = first;
}
/**
* Iterator costructor. If current() or next() method will always return false if
* them are invoked prior to start()
*/
dbTimeSeriesIterator() {
first = pos = -1;
}
private:
dbCursor< dbTimeSeriesBlock<T> > blocks;
int pos;
int first;
time_t till;
};
/**
* Time series reverse iterator
*/
template<class T>
class dbTimeSeriesReverseIterator {
public:
/**
* Start iteration through elements belonging to the specified range.
* @param processor pointer to time series processor
* @param oid time series identifer (OID of the object associated with this time series)
* @param from inclusive low bound for element timestamp (set 0 to disable this criteria)
* @param till inclusive high bound for element timestamp (set INFINITE_TIME to disable this criteria)
*/
void start(dbTimeSeriesProcessor<T>* processor, oid_t oid, time_t from, time_t till) {
last = pos = -1;
this->from = from;
if (processor->_openIteratorCursor(blocks, oid, from, till)) {
do {
int n = blocks->used;
blocks.last();
T const* e = blocks->elements.get();
int l = 0, r = n;
while (l < r) {
int i = (l+r) >> 1;
if (till >= e[i].time()) {
l = i+1;
} else {
r = i;
}
}
assert(l == r && (l == n || e[l].time() > till));
if (l > 0) {
if (e[l-1].time() >= from) {
last = pos = l-1;
}
return;
}
} while (blocks.prev());
}
}
/**
* Get current iterator element
* @return <code>true</code> if there is current element, <code>false</code> otherwise
*/
bool current(T& elem) {
if (pos >= 0) {
elem = blocks->elements[pos];
return true;
}
return false;
}
/**
* Move iterator position to next element.
* @return <code>true</code> if next element exists, <code>false</code> otherwise
*/
bool next() {
if (pos >= 0) {
if (--pos < 0) {
if (!blocks.prev()) {
return false;
}
pos = blocks->used-1;
}
if (blocks->elements[pos].time() >= from) {
return true;
}
pos = -1;
}
return false;
}
/**
* Reset iterator to the initial state
*/
void reset() {
blocks.last();
pos = last;
}
/**
* Iterator costructor. If current() or next() method will always return false if
* them are invoked prior to start()
*/
dbTimeSeriesReverseIterator() {
last = pos = -1;
}
private:
dbCursor< dbTimeSeriesBlock<T> > blocks;
int pos;
int last;
time_t from;
};
END_FASTDB_NAMESPACE
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -