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