blob: 7ab5354abb825b5551fbe3105d77f60348e2daeb [file] [log] [blame]
#include "metrics/collection_data.hpp"
#include "metrics/collection_function.hpp"
namespace metrics
{
bool CollectionData::updateLastValue(double value)
{
const bool changed = lastValue != value;
lastValue = value;
return changed;
}
class DataPoint : public CollectionData
{
public:
std::optional<double> update(Milliseconds) override
{
return lastReading;
}
double update(Milliseconds, double reading) override
{
lastReading = reading;
return reading;
}
private:
std::optional<double> lastReading;
};
class DataInterval : public CollectionData
{
public:
DataInterval(std::shared_ptr<CollectionFunction> function,
CollectionDuration duration) :
function(std::move(function)),
duration(duration)
{
if (duration.t.count() == 0)
{
throw errors::InvalidArgument(
"ReadingParameters.CollectionDuration");
}
}
std::optional<double> update(Milliseconds timestamp) override
{
if (readings.empty())
{
return std::nullopt;
}
cleanup(timestamp);
return function->calculate(readings, timestamp);
}
double update(Milliseconds timestamp, double reading) override
{
readings.emplace_back(timestamp, reading);
cleanup(timestamp);
return function->calculate(readings, timestamp);
}
private:
void cleanup(Milliseconds timestamp)
{
auto it = readings.begin();
for (auto kt = std::next(readings.rbegin()); kt != readings.rend();
++kt)
{
const auto& [nextItemTimestamp, nextItemReading] = *std::prev(kt);
if (timestamp >= nextItemTimestamp &&
timestamp - nextItemTimestamp > duration.t)
{
it = kt.base();
break;
}
}
readings.erase(readings.begin(), it);
if (timestamp > duration.t)
{
readings.front().first =
std::max(readings.front().first, timestamp - duration.t);
}
}
std::shared_ptr<CollectionFunction> function;
std::vector<ReadingItem> readings;
CollectionDuration duration;
};
class DataStartup : public CollectionData
{
public:
explicit DataStartup(std::shared_ptr<CollectionFunction> function) :
function(std::move(function))
{}
std::optional<double> update(Milliseconds timestamp) override
{
if (readings.empty())
{
return std::nullopt;
}
return function->calculateForStartupInterval(readings, timestamp);
}
double update(Milliseconds timestamp, double reading) override
{
readings.emplace_back(timestamp, reading);
return function->calculateForStartupInterval(readings, timestamp);
}
private:
std::shared_ptr<CollectionFunction> function;
std::vector<ReadingItem> readings;
};
std::vector<std::unique_ptr<CollectionData>>
makeCollectionData(size_t size, OperationType op,
CollectionTimeScope timeScope,
CollectionDuration duration)
{
using namespace std::string_literals;
std::vector<std::unique_ptr<CollectionData>> result;
result.reserve(size);
switch (timeScope)
{
case CollectionTimeScope::interval:
std::generate_n(std::back_inserter(result), size,
[cf = makeCollectionFunction(op), duration] {
return std::make_unique<DataInterval>(cf,
duration);
});
break;
case CollectionTimeScope::point:
std::generate_n(std::back_inserter(result), size,
[] { return std::make_unique<DataPoint>(); });
break;
case CollectionTimeScope::startup:
std::generate_n(std::back_inserter(result), size,
[cf = makeCollectionFunction(op)] {
return std::make_unique<DataStartup>(cf);
});
break;
}
return result;
}
} // namespace metrics