1 #include "metrics/collection_data.hpp" 2 3 #include "metrics/collection_function.hpp" 4 5 namespace metrics 6 { 7 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: 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 33 class 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 { 43 throw errors::InvalidArgument( 44 "ReadingParameters.CollectionDuration"); 45 } 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 98 class 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 126 std::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 162