blob: 7ab5354abb825b5551fbe3105d77f60348e2daeb [file] [log] [blame]
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +01001#include "metrics/collection_data.hpp"
2
3#include "metrics/collection_function.hpp"
4
5namespace metrics
6{
7
8bool CollectionData::updateLastValue(double value)
9{
10 const bool changed = lastValue != value;
11 lastValue = value;
12 return changed;
13}
14
15class DataPoint : public CollectionData
16{
17 public:
18 std::optional<double> update(Milliseconds) override
19 {
20 return lastReading;
21 }
22
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
33class DataInterval : public CollectionData
34{
35 public:
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 {
Krzysztof Grobelny62c08e92022-09-16 10:28:53 +020043 throw errors::InvalidArgument(
44 "ReadingParameters.CollectionDuration");
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010045 }
46 }
47
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
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:
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 =
89 std::max(readings.front().first, timestamp - duration.t);
90 }
91 }
92
93 std::shared_ptr<CollectionFunction> function;
94 std::vector<ReadingItem> readings;
95 CollectionDuration duration;
96};
97
98class DataStartup : public CollectionData
99{
100 public:
101 explicit DataStartup(std::shared_ptr<CollectionFunction> function) :
102 function(std::move(function))
103 {}
104
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
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
126std::vector<std::unique_ptr<CollectionData>>
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,
143 duration);
144 });
145 break;
146 case CollectionTimeScope::point:
147 std::generate_n(std::back_inserter(result), size,
148 [] { return std::make_unique<DataPoint>(); });
149 break;
150 case CollectionTimeScope::startup:
151 std::generate_n(std::back_inserter(result), size,
152 [cf = makeCollectionFunction(op)] {
153 return std::make_unique<DataStartup>(cf);
154 });
155 break;
156 }
157
158 return result;
159}
160
161} // namespace metrics