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)), duration(duration) 39 { 40 if (duration.t.count() == 0) 41 { 42 throw errors::InvalidArgument( 43 "ReadingParameters.CollectionDuration"); 44 } 45 } 46 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 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: 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: 100 explicit DataStartup(std::shared_ptr<CollectionFunction> function) : 101 function(std::move(function)) 102 {} 103 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 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>> 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