added support for onChange report
Report is now notified when metric changes and updates reading values.
Tested:
- Added new unit tests
- OnChange report updates Readings when metric values changes
Change-Id: I3be9ef7aa0486cb15bac627aa1de5cc632613b3b
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
diff --git a/src/report.cpp b/src/report.cpp
index 12d88c7..d9d89b8 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -6,6 +6,7 @@
#include "report_manager.hpp"
#include "utils/clock.hpp"
#include "utils/contains.hpp"
+#include "utils/ensure.hpp"
#include "utils/transform.hpp"
#include <phosphor-logging/log.hpp>
@@ -13,6 +14,7 @@
#include <limits>
#include <numeric>
+#include <optional>
Report::Report(boost::asio::io_context& ioc,
const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
@@ -71,10 +73,7 @@
persistency = storeConfiguration();
reportIface = makeReportInterface(reportFactory);
- if (reportingType == ReportingType::periodic)
- {
- scheduleTimer(interval);
- }
+ updateReportingType(reportingType);
if (enabled)
{
@@ -119,7 +118,7 @@
}
uint64_t Report::getSensorCount(
- std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
+ const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
{
uint64_t sensorCount = 0;
for (auto& metric : metrics)
@@ -188,7 +187,7 @@
{
if (true == newVal && ReportingType::periodic == reportingType)
{
- scheduleTimer(interval);
+ scheduleTimerForPeriodicReport(interval);
}
if (newVal)
{
@@ -260,12 +259,6 @@
ReportingType tmp = utils::toReportingType(newVal);
if (tmp != reportingType)
{
- if (tmp == ReportingType::onChange)
- {
- throw sdbusplus::exception::SdBusError(
- static_cast<int>(std::errc::invalid_argument),
- "Invalid reportingType");
- }
if (tmp == ReportingType::periodic)
{
if (interval < ReportManager::minInterval)
@@ -274,20 +267,13 @@
static_cast<int>(std::errc::invalid_argument),
"Invalid interval");
}
- if (enabled == true)
- {
- scheduleTimer(interval);
- }
}
- else
- {
- timer.cancel();
- }
- reportingType = tmp;
+
+ updateReportingType(tmp);
setReadingBuffer(reportUpdates);
persistency = storeConfiguration();
+ oldVal = std::move(newVal);
}
- oldVal = std::move(newVal);
return 1;
},
[this](const auto&) { return utils::enumToString(reportingType); });
@@ -377,7 +363,8 @@
return dbusIface;
}
-void Report::timerProc(boost::system::error_code ec, Report& self)
+void Report::timerProcForPeriodicReport(boost::system::error_code ec,
+ Report& self)
{
if (ec)
{
@@ -385,14 +372,58 @@
}
self.updateReadings();
- self.scheduleTimer(self.interval);
+ self.scheduleTimerForPeriodicReport(self.interval);
}
-void Report::scheduleTimer(Milliseconds timerInterval)
+void Report::timerProcForOnChangeReport(boost::system::error_code ec,
+ Report& self)
{
+ if (ec)
+ {
+ return;
+ }
+
+ const auto ensure =
+ utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
+
+ self.onChangeContext.emplace(self);
+
+ const auto steadyTimestamp = self.clock->steadyTimestamp();
+
+ for (auto& metric : self.metrics)
+ {
+ metric->updateReadings(steadyTimestamp);
+ }
+
+ self.scheduleTimerForOnChangeReport();
+}
+
+void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
+{
+ if (!enabled)
+ {
+ return;
+ }
+
timer.expires_after(timerInterval);
- timer.async_wait(
- [this](boost::system::error_code ec) { timerProc(ec, *this); });
+ timer.async_wait([this](boost::system::error_code ec) {
+ timerProcForPeriodicReport(ec, *this);
+ });
+}
+
+void Report::scheduleTimerForOnChangeReport()
+{
+ if (!enabled)
+ {
+ return;
+ }
+
+ constexpr Milliseconds timerInterval{100};
+
+ timer.expires_after(timerInterval);
+ timer.async_wait([this](boost::system::error_code ec) {
+ timerProcForOnChangeReport(ec, *this);
+ });
}
void Report::updateReadings()
@@ -495,3 +526,62 @@
return result;
}
+
+void Report::metricUpdated()
+{
+ if (onChangeContext)
+ {
+ onChangeContext->metricUpdated();
+ return;
+ }
+
+ updateReadings();
+}
+
+void Report::updateReportingType(ReportingType newReportingType)
+{
+ if (reportingType != newReportingType)
+ {
+ timer.cancel();
+ unregisterFromMetrics = nullptr;
+ }
+
+ reportingType = newReportingType;
+
+ switch (reportingType)
+ {
+ case ReportingType::periodic:
+ {
+ scheduleTimerForPeriodicReport(interval);
+ break;
+ }
+ case ReportingType::onChange:
+ {
+ unregisterFromMetrics = [this] {
+ for (auto& metric : metrics)
+ {
+ metric->unregisterFromUpdates(*this);
+ }
+ };
+
+ bool isTimerRequired = false;
+
+ for (auto& metric : metrics)
+ {
+ metric->registerForUpdates(*this);
+ if (metric->isTimerRequired())
+ {
+ isTimerRequired = true;
+ }
+ }
+
+ if (isTimerRequired)
+ {
+ scheduleTimerForOnChangeReport();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}