12#ifndef IPCQ_DDT_FORWARDER_HPP
13#define IPCQ_DDT_FORWARDER_HPP
26#include <ipcq/adapter.hpp>
27#include <ipcq/reader.hpp>
29#include <numapp/numapolicies.hpp>
30#include <numapp/thread.hpp>
32#include <fmt/format.h>
37#include <shared_mutex>
46template <
typename Tuple>
49template <
typename... PublisherType>
50struct Wrapper<std::tuple<PublisherType...>> {
51 using ServiceContainer = rtctk::componentFramework::ServiceContainer;
53 static std::tuple<PublisherType...>
54 MakePublishers(
const std::string& db_prefix, ServiceContainer& services) {
55 return std::make_tuple(PublisherType(db_prefix, services)...);
68template <
typename FwdInfo,
typename ReaderType = ipcq::Reader<
typename FwdInfo::Topic>>
71 using Topic =
typename FwdInfo::Topic;
80 static_assert(FwdInfo::ID.find_first_not_of(
"abcdefghijklmnopqrstuvwxyz_0123456789") ==
81 std::string_view::npos,
82 "DDT Forwarder ID contains illegal characters!");
85 :
DdtForwarder(comp_id,
"IpcqDdtForwarder",
std::string(FwdInfo::ID), services)
87 , m_oldb(services.Get<
OldbIf>())
90 , m_oldb_prefix(
fmt::format(
"/forwarders/{}",
GetId()))
91 , m_rtr_prefix_static(
fmt::format(
"/{}/static/forwarders/{}", comp_id,
GetId()))
92 , m_rtr_prefix_dynamic(
fmt::format(
"/{}/dynamic/forwarders/{}", comp_id,
GetId()))
93 , m_publishers(Wrapper<typename FwdInfo::DdtPublisherTupleType>::MakePublishers(
94 fmt::format(
"{}/forwarders/{}/publishers", comp_id,
GetId()), services))
100 {
"forwarder_id",
GetId()},
103 m_samples_forwarded_reg =
104 m_metrics.AddCounter(&m_samples_forwarded,
106 "Number of samples forwarded",
108 "samples_forwarded"));
110 m_last_sample_id_forwarded_reg =
111 m_metrics.AddCounter(&m_last_sample_id_forwarded,
113 "Last sample id forwarded",
115 "last_sample_id_forwarded"));
117 m_freq_estimator = std::make_unique<FrequencyEstimator>(
118 m_metrics,
"Estimated frequency of the data forwarder", m_oldb_prefix);
120 m_dur_monitor = std::make_unique<DurationMonitor>(
121 m_metrics,
"Duration of publishing data to DDT", m_oldb_prefix);
124 std::make_unique<BufferMonitor>(m_metrics,
"SHM read buffer occupancy", m_oldb_prefix);
128 auto queue_name_path =
DataPointPath{m_rtr_prefix_static +
"/shm_queue_name"};
129 m_queue_name = m_rtr.GetDataPoint<std::string>(queue_name_path);
131 auto thread_policies_path =
DataPointPath{m_rtr_prefix_static +
"/thread_policies"};
134 auto subsample_factor_path =
DataPointPath{m_rtr_prefix_dynamic +
"/subsample_factor"};
135 m_subsample_factor = m_rtr.GetDataPoint<int64_t>(subsample_factor_path);
140 if (m_processing_thread.joinable()) {
141 m_processing_thread.join();
151 m_processing_thread = numapp::MakeThread(
GetId().substr(0, 15),
152 m_thread_policies.value_or(numapp::NumaPolicies()),
153 [&]() { Process(); });
156 using namespace std::chrono_literals;
157 std::this_thread::sleep_for(10ms);
179 if (m_processing_thread.joinable()) {
180 m_processing_thread.join();
189 std::scoped_lock lock(m_exception_mutex);
190 m_exception = std::current_exception();
200 LOG4CPLUS_INFO(
m_logger, fmt::format(
"Updating IpcqDdtForwarder '{}'",
GetId()));
202 auto subsample_factor_path =
DataPointPath{m_rtr_prefix_dynamic +
"/subsample_factor"};
203 m_subsample_factor = m_rtr.GetDataPoint<int64_t>(subsample_factor_path);
205 std::apply([&](
auto&&... pub) { ((pub.Update()), ...); }, m_publishers);
210 auto lock = std::shared_lock{m_exception_mutex};
212 std::rethrow_exception(m_exception);
218 using namespace std::chrono_literals;
222 const std::error_code ok{};
223 std::pair<std::error_code, size_t> result;
225 std::vector<Topic> read_buffer;
226 read_buffer.reserve(MAX_SAMPLES_READ);
228 m_samples_forwarded.Store(0);
229 m_last_sample_id_forwarded.Store(0);
231 ReaderType reader(m_queue_name.c_str());
233 size_t reader_capacity = reader.Capacity();
243 if (
auto ret = reader.Reset(); ret == ok) {
246 CII_THROW(
IpcqError,
"Error resetting ipcq Reader");
250 std::this_thread::sleep_for(1ms);
259 to_read = reader.NumAvailable();
265 to_read = std::min(to_read, MAX_SAMPLES_READ);
267 if (m_subsample_factor > 1) {
268 m_sampling_counter = m_sampling_counter % m_subsample_factor;
269 if (m_sampling_counter == 0) {
272 to_skip = std::min(to_read, m_subsample_factor - m_sampling_counter);
277 m_buffer_monitor->Tick(reader.NumAvailable(), reader_capacity);
278 result = reader.Read(ipcq::BackInserter(read_buffer), to_read, 100ms);
279 for (
const auto& sample : read_buffer) {
280 m_last_sample_id_forwarded.Store(sample.sample_id);
281 auto t1 = std::chrono::steady_clock::now();
282 ExtractAndPublish(sample);
283 auto t2 = std::chrono::steady_clock::now();
284 m_dur_monitor->Tick(t2 - t1);
285 m_freq_estimator->Tick();
286 m_samples_forwarded++;
290 result = reader.Skip(to_skip, 100ms);
292 m_sampling_counter += result.second;
294 if (not(result.first == ok or result.first == ipcq::Error::Timeout)) {
295 std::string error =
"Error reading from ipcq: " + result.first.message();
296 CII_THROW(IpcqError, error);
301 std::this_thread::sleep_for(1ms);
309 std::scoped_lock lock(m_exception_mutex);
310 m_exception = std::current_exception();
316 void ExtractAndPublish(
const Topic& sample) {
317 auto func = [&](
auto& pub) {
318 if (pub.IsEnabled()) {
320 auto e = std::remove_reference_t<
decltype(pub)>::StreamInfo::Extract(sample);
322 pub.Publish(std::get<0>(e),
323 reinterpret_cast<const uint8_t*
>(std::get<1>(e).data()),
324 std::get<1>(e).size());
328 std::apply([&](
auto&&... pub) { (func(pub), ...); }, m_publishers);
335 std::string m_comp_id;
336 std::string m_oldb_prefix;
337 std::string m_rtr_prefix_static;
338 std::string m_rtr_prefix_dynamic;
340 typename FwdInfo::DdtPublisherTupleType m_publishers;
342 std::atomic<State> m_requested_state;
343 std::exception_ptr m_exception =
nullptr;
344 std::shared_mutex m_exception_mutex;
346 std::thread m_processing_thread;
351 std::string m_queue_name;
356 std::optional<numapp::NumaPolicies> m_thread_policies;
361 int64_t m_subsample_factor = -1;
366 uint64_t m_sampling_counter = 0;
371 perfc::CounterI64 m_samples_forwarded;
372 perfc::ScopedRegistration m_samples_forwarded_reg;
377 perfc::CounterI64 m_last_sample_id_forwarded;
378 perfc::ScopedRegistration m_last_sample_id_forwarded_reg;
380 std::unique_ptr<FrequencyEstimator> m_freq_estimator;
381 std::unique_ptr<DurationMonitor> m_dur_monitor;
382 std::unique_ptr<BufferMonitor> m_buffer_monitor;
387 inline static constexpr size_t MAX_SAMPLES_READ = 16;
Header file for Buffer Monitor.
Monitors min, mean and max occupation of a buffer and publishes them to OLDB.
Definition bufferMonitor.hpp:36
Component metrics interface.
Definition componentMetricsIf.hpp:163
Defines auxiliary information associated with each counter registered with ComponentMetricsIf.
Definition componentMetricsIf.hpp:48
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:76
Monitors min, mean and max duration and publishes them to OLDB.
Definition durationMonitor.hpp:36
Estimates the frequency in which Tick is called and publishes result to OLDB.
Definition frequencyEstimator.hpp:30
Helper class for passing tags in Telegraf.
Definition influxTagMap.hpp:26
This Exception is raised when the ipc queue returns an error that cannot be handled by the Telemetry ...
Definition exceptions.hpp:391
Base interface for all OLDB adapters.
Definition oldbIf.hpp:24
Base interface for all Runtime Configuration Repository adapters.
Definition runtimeRepoIf.hpp:26
Container class that holds services of any type.
Definition serviceContainer.hpp:38
DdtForwarder(const std::string &comp_id, const std::string &fwd_type, const std::string &fwd_id, ServiceContainer &services)
Definition ddtForwarder.hpp:55
void AssertState(const std::set< State > &states)
Definition ddtForwarder.hpp:143
virtual void SetState(State state)
Definition ddtForwarder.hpp:130
State
States a forwarder unit can be in.
Definition ddtForwarder.hpp:53
@ STARTING
Definition ddtForwarder.hpp:53
@ STOPPED
Definition ddtForwarder.hpp:53
@ RUNNING
Definition ddtForwarder.hpp:53
@ IDLE
Definition ddtForwarder.hpp:53
@ ERROR
Definition ddtForwarder.hpp:53
log4cplus::Logger & m_logger
Definition ddtForwarder.hpp:166
State GetState() const
Get the state of the forwarder unit.
Definition ddtForwarder.hpp:90
const std::string & GetId() const
Get identifier of the forwarder unit.
Definition ddtForwarder.hpp:83
rtctk::componentFramework::RuntimeRepoIf RuntimeRepoIf
Definition ipcqDdtForwarder.hpp:73
void Idle() override
Stop publishing DDT streams.
Definition ipcqDdtForwarder.hpp:172
rtctk::componentFramework::ComponentMetricsIf ComponentMetricsIf
Definition ipcqDdtForwarder.hpp:75
void Recover() override
Stop the processing thread of the forwarder unit and clear errors.
Definition ipcqDdtForwarder.hpp:184
rtctk::componentFramework::FrequencyEstimator<> FrequencyEstimator
Definition ipcqDdtForwarder.hpp:76
IpcqDdtForwarder(const std::string &comp_id, ServiceContainer &services)
Definition ipcqDdtForwarder.hpp:84
typename FwdInfo::Topic Topic
Definition ipcqDdtForwarder.hpp:71
void Start() override
Start the processing thread of the forwarder unit.
Definition ipcqDdtForwarder.hpp:145
rtctk::componentFramework::BufferMonitor<> BufferMonitor
Definition ipcqDdtForwarder.hpp:78
rtctk::componentFramework::DurationMonitor<> DurationMonitor
Definition ipcqDdtForwarder.hpp:77
void Stop() override
Stop the processing thread of the forwarder unit.
Definition ipcqDdtForwarder.hpp:177
void Update() override
Reload dynamic configuration of the forwarder unit.
Definition ipcqDdtForwarder.hpp:197
~IpcqDdtForwarder() override
Definition ipcqDdtForwarder.hpp:138
void CheckErrors() override
Check for Errors, will rethrow errors thrown in the forwarder.
Definition ipcqDdtForwarder.hpp:208
rtctk::componentFramework::OldbIf OldbIf
Definition ipcqDdtForwarder.hpp:74
rtctk::componentFramework::ServiceContainer ServiceContainer
Definition ipcqDdtForwarder.hpp:72
void Run() override
Start publishing DDT streams.
Definition ipcqDdtForwarder.hpp:167
Header file for ComponentMetricsIf.
Base class defining common interface for all DDT forwarders.
Header file for Duration Monitor.
Provides macros and utilities for exception handling.
Header file for Frequency Estimator.
std::optional< numapp::NumaPolicies > GetNumaPolicies(RepositoryIf &repo, const DataPointPath &path)
Constructs a NumaPolicies object from the configuration datapoints found under the given datapoint pa...
Definition repositoryIfUtils.cpp:32
Definition dataPointPath.hpp:464
Definition commandReplier.cpp:21
Definition businessLogic.cpp:23
Definition ddsSub.hpp:155
Header file for OldbIf, which defines the API for OldbAdapters.
Provides utilities to simplify use of RepositoryIf.
Header file for RuntimeRepoIf, which defines the API for RuntimeRepoAdapters.