1 from __future__ import absolute_import
2 from __future__ import division
6 from p2pool.util import math as math2
9 class DataViewDescription(object):
10 def __init__(self, bin_count, total_width):
11 self.bin_count = bin_count
12 self.bin_width = total_width/bin_count
14 def _shift(x, shift, pad_item):
15 left_pad = math2.clip(shift, (0, len(x)))
16 right_pad = math2.clip(-shift, (0, len(x)))
17 return [pad_item]*left_pad + x[right_pad:-left_pad if left_pad else None] + [pad_item]*right_pad
19 class DataView(object):
20 def __init__(self, desc, ds_desc, last_bin_end, bins):
21 assert len(bins) == desc.bin_count
24 self.ds_desc = ds_desc
25 self.last_bin_end = last_bin_end
28 def _add_datum(self, t, value):
29 shift = max(0, int(math.ceil((t - self.last_bin_end)/self.desc.bin_width)))
30 self.bins = _shift(self.bins, shift, (0, 0))
31 self.last_bin_end += shift*self.desc.bin_width
33 bin = int(math.ceil((self.last_bin_end - self.desc.bin_width - t)/self.desc.bin_width))
35 if bin >= self.desc.bin_count:
38 prev_total, prev_count = self.bins[bin]
39 self.bins[bin] = prev_total + value, prev_count + 1
41 def get_data(self, t):
42 shift = max(0, int(math.ceil((t - self.last_bin_end)/self.desc.bin_width)))
43 bins = _shift(self.bins, shift, (0, 0))
44 last_bin_end = self.last_bin_end + shift*self.desc.bin_width
46 assert last_bin_end - self.desc.bin_width <= t <= last_bin_end
49 last_bin_end - self.desc.bin_width*(i + 1/2),
50 (total/count if count else None) if self.ds_desc.source_is_cumulative
51 else total/(min(t, last_bin_end - self.desc.bin_width*i) - (last_bin_end - self.desc.bin_width*(i + 1))),
52 ) for i, (total, count) in enumerate(bins)]
55 class DataStreamDescription(object):
56 def __init__(self, source_is_cumulative, dataview_descriptions):
57 self.source_is_cumulative = source_is_cumulative
58 self.dataview_descriptions = dataview_descriptions
60 class DataStream(object):
61 def __init__(self, desc, dataviews):
63 self.dataviews = dataviews
65 def add_datum(self, t, value=1):
66 for dv_name, dv in self.dataviews.iteritems():
67 dv._add_datum(t, value)
70 class HistoryDatabase(object):
72 def from_obj(cls, datastream_descriptions, obj={}):
73 def get_dataview(ds_name, ds_desc, dv_name, dv_desc):
75 ds_data = obj[ds_name]
76 if dv_name in ds_data:
77 dv_data = ds_data[dv_name]
78 if dv_data['bin_width'] == dv_desc.bin_width and len(dv_data['bins']) == dv_desc.bin_count:
79 return DataView(dv_desc, ds_desc, dv_data['last_bin_end'], dv_data['bins'])
80 return DataView(dv_desc, ds_desc, 0, dv_desc.bin_count*[(0, 0)])
82 (ds_name, DataStream(ds_desc, dict(
83 (dv_name, get_dataview(ds_name, ds_desc, dv_name, dv_desc))
84 for dv_name, dv_desc in ds_desc.dataview_descriptions.iteritems()
86 for ds_name, ds_desc in datastream_descriptions.iteritems()
89 def __init__(self, datastreams):
90 self.datastreams = datastreams
93 return dict((ds_name, dict((dv_name, dict(last_bin_end=dv.last_bin_end, bin_width=dv.desc.bin_width, bins=dv.bins))
94 for dv_name, dv in ds.dataviews.iteritems())) for ds_name, ds in self.datastreams.iteritems())