NVMeMetricStore: handles MetricUpdated signal Add a completeCB parameter to the Metric implementation to call MetricUpdate() method of the MetricStore. Also added the comment for the DBus interface to handle invalid metric signal. Google-Bug-Id: 348660385 Tested: 348660385#comment3 (with all changes from go/gbmcl-ext/q/topic:%22nvme+cache%22) Signed-off-by: Hao Jiang <jianghao@google.com> Change-Id: I4adacc43aec92747fe7830b5e696fabbc79e6df4
diff --git a/src/NVMeCacheImpl.hpp b/src/NVMeCacheImpl.hpp index f31328e..262c4c4 100644 --- a/src/NVMeCacheImpl.hpp +++ b/src/NVMeCacheImpl.hpp
@@ -14,14 +14,18 @@ class ControllerLogPageMetric : public MetricBase<ClockType> { public: - ControllerLogPageMetric(std::weak_ptr<NVMeControllerEnabled> controller_, - std::shared_ptr<Scheduler<ClockType>> scheduler_, - ClockType::duration interval_) : - MetricBase<ClockType>(scheduler_, interval_), controller(controller_) + ControllerLogPageMetric( + std::weak_ptr<NVMeControllerEnabled> controller, + std::shared_ptr<Scheduler<ClockType>> scheduler, + ClockType::duration interval, + std::function<void(std::shared_ptr<MetricBase<ClockType>>)>&& + completeCB) : + MetricBase<ClockType>(scheduler, interval), + controller(std::move(controller)), completeCB(std::move(completeCB)) {} /* interface overrides */ - constexpr std::string_view getIdentifier() const noexcept override + static constexpr std::string_view logpageIdentifier() noexcept { if constexpr (LID == NVME_LOG_LID_SMART) { @@ -35,6 +39,12 @@ return {}; } + + constexpr std::string_view getIdentifier() const noexcept override + { + return logpageIdentifier(); + } + bool isCacheValid() const noexcept override { return cacheValid; @@ -98,6 +108,9 @@ std::cerr << std::format( "[{}, {}]retry exhausted to fresh log page", path, id); self->cacheValid = false; + // Notify the MatrixStore of the for the invalid Cache + self->completeCB(self); + // Notify the RefreshCB with error code; the task will // be reschuduled after this->interval cb(std::make_error_code(std::errc::io_error), 4096, true); @@ -107,14 +120,20 @@ self->cacheValid = true; std::get<0>(self->cache) = startTime; std::get<1>(self->cache) = ClockType::now(); - std::get<2>(self->cache) - .insert(std::get<2>(self->cache).begin(), data.begin(), - data.end()); + + auto& cacheData = std::get<2>(self->cache); + cacheData.clear(); + cacheData.insert(cacheData.begin(), data.begin(), data.end()); + + // notify the MetricStore for completion + self->completeCB(self); + cb({}, data.size(), true); }); } /* member variables */ std::weak_ptr<NVMeControllerEnabled> controller; + std::function<void(std::shared_ptr<MetricBase<ClockType>>)> completeCB; std::tuple<std::chrono::time_point<ClockType>, std::chrono::time_point<ClockType>, std::vector<uint8_t>>
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp index dd3987f..4932970 100644 --- a/src/NVMeController.cpp +++ b/src/NVMeController.cpp
@@ -180,17 +180,58 @@ this->metricStore.emplace(this->NVMeController::io, this->NVMeController::conn, this->NVMeController::path); + // NOLINTBEGIN(performance-unnecessary-value-param) + auto completeCB = + [weakCntrl{weak_from_this()}, path{path}]( + std::string_view name, + std::shared_ptr<MetricBase<std::chrono::steady_clock>> metric) { + auto cntrl = weakCntrl.lock(); + if (!cntrl || !cntrl->metricStore) + { + // TODO: log_level = INFO + std::cerr << std::format( + "[{}]Metrics interface for controller expired, update signal skipped.\n", + path); + } + if (!metric->isCacheValid()) + { + // broadcast invalid metric signal + cntrl->metricStore->metricUpdated(std::string{name}, {}); + return; + } - this->metricStore.emplace( - this->NVMeController::io, this->NVMeController::conn, - this->NVMeController::path, - std::shared_ptr<ControllerLogPageMetric<NVME_LOG_LID_SMART, - std::chrono::steady_clock>>( - new ControllerLogPageMetric<NVME_LOG_LID_SMART, - std::chrono::steady_clock>( - this->weak_from_this(), {}, - std::chrono::duration_cast<std::chrono::steady_clock::duration>( - std::chrono::seconds(60))))); + auto data = metric->getCache(); + std::vector<uint8_t> headerBuf; + headerBuf.resize(sizeof(MetricHeader)); + MetricHeader& header = + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + *reinterpret_cast<MetricHeader*>(headerBuf.data()); + header.lens = boost::endian::little_uint32_t(sizeof(header)); + header.version = 0; + header.dataFormat = 0; + header.startTime = boost::endian::little_uint64_t( + std::get<0>(data).time_since_epoch().count()); + header.finishTime = boost::endian::little_uint64_t( + std::get<1>(data).time_since_epoch().count()); + cntrl->metricStore->metricUpdated(std::string{name}, headerBuf); + }; + // NOLINTEND(performance-unnecessary-value-param) + + using SMARTMetric = + ControllerLogPageMetric<NVME_LOG_LID_SMART, std::chrono::steady_clock>; + + // NOLINTBEGIN(modernize-make-shared) + auto smart = std::shared_ptr<SMARTMetric>(new SMARTMetric( + this->weak_from_this(), {}, + // TODO: configurable interval + std::chrono::duration_cast<std::chrono::steady_clock::duration>( + std::chrono::seconds(60)), + std::bind_front(completeCB, SMARTMetric::logpageIdentifier()))); + // NOLINTEND(modernize-make-shared) + + this->metricStore.emplace(this->NVMeController::io, + this->NVMeController::conn, + this->NVMeController::path, std::move(smart)); status = Status::Enabled; }
diff --git a/yaml/xyz/openbmc_project/NVMe/MetricStore.interface.yaml b/yaml/xyz/openbmc_project/NVMe/MetricStore.interface.yaml index 676f5ce..6a7f403 100644 --- a/yaml/xyz/openbmc_project/NVMe/MetricStore.interface.yaml +++ b/yaml/xyz/openbmc_project/NVMe/MetricStore.interface.yaml
@@ -21,7 +21,9 @@ - name: MetricHeader type: array[byte] description: > - Metric Header being broadcasted as a signal on each update + Metric Header being broadcasted as a signal on each update. A + zero-length header will be transmitted when the Metric turns + into invalid. methods: - name: GetMetric