1 #include "metrics/collection_data.hpp"
2
3 #include "metrics/collection_function.hpp"
4
5 namespace metrics
6 {
7
updateLastValue(double value)8 bool CollectionData::updateLastValue(double value)
9 {
10 const bool changed = lastValue != value;
11 lastValue = value;
12 return changed;
13 }
14
15 class DataPoint : public CollectionData
16 {
17 public:
update(Milliseconds)18 std::optional<double> update(Milliseconds) override
19 {
20 return lastReading;
21 }
22
update(Milliseconds,double reading)23 double update(Milliseconds, double reading) override
24 {
25 lastReading = reading;
26 return reading;
27 }
28
29 private:
30 std::optional<double> lastReading;
31 };
32
33 class DataInterval : public CollectionData
34 {
35 public:
DataInterval(std::shared_ptr<CollectionFunction> function,CollectionDuration duration)36 DataInterval(std::shared_ptr<CollectionFunction> function,
37 CollectionDuration duration) :
38 function(std::move(function)), duration(duration)
39 {
40 if (duration.t.count() == 0)
41 {
42 throw errors::InvalidArgument(
43 "ReadingParameters.CollectionDuration");
44 }
45 }
46
update(Milliseconds timestamp)47 std::optional<double> update(Milliseconds timestamp) override
48 {
49 if (readings.empty())
50 {
51 return std::nullopt;
52 }
53
54 cleanup(timestamp);
55
56 return function->calculate(readings, timestamp);
57 }
58
update(Milliseconds timestamp,double reading)59 double update(Milliseconds timestamp, double reading) override
60 {
61 readings.emplace_back(timestamp, reading);
62
63 cleanup(timestamp);
64
65 return function->calculate(readings, timestamp);
66 }
67
68 private:
cleanup(Milliseconds timestamp)69 void cleanup(Milliseconds timestamp)
70 {
71 auto it = readings.begin();
72 for (auto kt = std::next(readings.rbegin()); kt != readings.rend();
73 ++kt)
74 {
75 const auto& [nextItemTimestamp, nextItemReading] = *std::prev(kt);
76 if (timestamp >= nextItemTimestamp &&
77 timestamp - nextItemTimestamp > duration.t)
78 {
79 it = kt.base();
80 break;
81 }
82 }
83 readings.erase(readings.begin(), it);
84
85 if (timestamp > duration.t)
86 {
87 readings.front().first = std::max(readings.front().first,
88 timestamp - duration.t);
89 }
90 }
91
92 std::shared_ptr<CollectionFunction> function;
93 std::vector<ReadingItem> readings;
94 CollectionDuration duration;
95 };
96
97 class DataStartup : public CollectionData
98 {
99 public:
DataStartup(std::shared_ptr<CollectionFunction> function)100 explicit DataStartup(std::shared_ptr<CollectionFunction> function) :
101 function(std::move(function))
102 {}
103
update(Milliseconds timestamp)104 std::optional<double> update(Milliseconds timestamp) override
105 {
106 if (readings.empty())
107 {
108 return std::nullopt;
109 }
110
111 return function->calculateForStartupInterval(readings, timestamp);
112 }
113
update(Milliseconds timestamp,double reading)114 double update(Milliseconds timestamp, double reading) override
115 {
116 readings.emplace_back(timestamp, reading);
117 return function->calculateForStartupInterval(readings, timestamp);
118 }
119
120 private:
121 std::shared_ptr<CollectionFunction> function;
122 std::vector<ReadingItem> readings;
123 };
124
125 std::vector<std::unique_ptr<CollectionData>>
makeCollectionData(size_t size,OperationType op,CollectionTimeScope timeScope,CollectionDuration duration)126 makeCollectionData(size_t size, OperationType op,
127 CollectionTimeScope timeScope,
128 CollectionDuration duration)
129 {
130 using namespace std::string_literals;
131
132 std::vector<std::unique_ptr<CollectionData>> result;
133
134 result.reserve(size);
135
136 switch (timeScope)
137 {
138 case CollectionTimeScope::interval:
139 std::generate_n(std::back_inserter(result), size,
140 [cf = makeCollectionFunction(op), duration] {
141 return std::make_unique<DataInterval>(cf, duration);
142 });
143 break;
144 case CollectionTimeScope::point:
145 std::generate_n(std::back_inserter(result), size,
146 [] { return std::make_unique<DataPoint>(); });
147 break;
148 case CollectionTimeScope::startup:
149 std::generate_n(std::back_inserter(result), size,
150 [cf = makeCollectionFunction(op)] {
151 return std::make_unique<DataStartup>(cf);
152 });
153 break;
154 }
155
156 return result;
157 }
158
159 } // namespace metrics
160