blob: 607108bb41b896f56649f90b9acb24a1e3ce2515 [file] [log] [blame] [edit]
#pragma once
/**
* This file defines the MetricStore class, which is the DBus inplemention to
* interact with a collection of NVMe Metrics Cache for a Storage
* object(e.g. NVMe Contoller)
*/
#include "NVMeCache.hpp"
#include <boost/asio.hpp>
#include <boost/asio/write.hpp>
#include <boost/endian.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/sdbus.hpp>
#include <sdbusplus/server.hpp>
#include <xyz/openbmc_project/NVMe/MetricStore/server.hpp>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <tuple>
#include <unordered_map>
constexpr bool debug = false;
struct MetricHeader
{
boost::endian::little_uint32_t lens; // Header length
boost::endian::little_uint16_t version; // Header version
uint8_t dataFormat; // the data format. 0x00 = Raw NVMe format
uint8_t reserved;
boost::endian::little_uint64_t
startTime; // time stamp when the Metric started the retrival from the
// device
boost::endian::little_uint64_t
finishTime; // time stamp when the Metric finished the retrival from
// the device
};
class MetricStore :
public sdbusplus::xyz::openbmc_project::NVMe::server::MetricStore
{
public:
template <class... Args>
requires(std::is_base_of_v<MetricBase<std::chrono::steady_clock>,
Args> &&
...)
MetricStore(boost::asio::io_context& io,
const std::shared_ptr<sdbusplus::asio::connection>& conn,
const std::string& objectPath,
std::shared_ptr<Args>&&... metrics) :
sdbusplus::xyz::openbmc_project::NVMe::server::MetricStore(
dynamic_cast<sdbusplus::bus_t&>(*conn), objectPath.c_str()),
path(objectPath), io(io),
metricStore{{std::string{metrics ? metrics->getIdentifier() : ""},
std::move(metrics)}...},
validFlag(std::make_shared<bool>())
{
metricStore.erase("");
auto vuMetrics = getVendorMatrics(path);
for (auto& metric : vuMetrics)
{
if (!metric)
{
continue;
}
auto [itr, res] = metricStore.try_emplace(
std::string{metric->getIdentifier()}, std::move(metric));
if (!res)
{
std::cerr << std::format(
"[{}, {}] drop a duplicated vendor metic\n", path,
itr->first);
}
}
std::vector<std::string> idCollection;
decltype(validFlag)::weak_type weakFlag = validFlag;
for (auto& [identifier, metric] : metricStore)
{
idCollection.push_back(identifier);
std::weak_ptr<MetricBase<std::chrono::steady_clock>> weakMetric =
metric;
metric->registerCompleteCB([this, weakFlag, identifier, weakMetric,
path{objectPath}](std::error_code ec) {
// use validFlag to protect this call
if (weakFlag.expired())
{
// TODO: log_level = INFO
std::cerr << std::format(
"[{}]MetricStore interface expired, update signal skipped.\n",
path);
return;
}
auto metric = weakMetric.lock();
if (ec || !metric)
{
// broadcast invalid metric signal
this->signalHelper(identifier, {});
}
this->signalHelper(identifier, metric);
});
metric->refresh({});
}
metricCollection(std::move(idCollection), true);
emit_added();
}
~MetricStore() override
{
emit_removed();
}
private:
static std::vector<std::shared_ptr<MetricBase<>>>
getVendorMatrics(const std::string& path);
/**
* @brief Writes to file descriptor after getting results from the
* registered callback function
*
* @param[in] data: Vector of raw bytes (header + actual data) to be written
* to file descriptor
*
* @return sdbusplus::message::unix_fd: Returns the read end of the pipe
*/
sdbusplus::message::unix_fd writeToFd(std::span<const uint8_t> header,
std::span<const uint8_t> data);
/**
* @brief Gets Metric using a unique metric name. Metric must be registered
* with that unique name
*
* @param[in] name: Registered metric name
*
* @return file descriptor pointing to the data
*/
sdbusplus::message::unix_fd getMetric(std::string name) override; // NOLINT
/**
* @brief A helper function to signal MetricUpdated
*
* @param[in] name: metric name
* @param[in] metric: metric instance. null instance will trigger invalid
* signal
*/
void signalHelper(
std::string_view name,
const std::shared_ptr<MetricBase<std::chrono::steady_clock>>&
metric) noexcept;
std::string path;
boost::asio::io_context& io;
std::unordered_map<std::string, std::shared_ptr<MetricBase<>>> metricStore;
// A flag to check the validation of this ptr when this is captured by async
// function. No other oject should seize the strong ptr of the flag other
// than this instance.
std::shared_ptr<bool> validFlag;
};