13#ifndef IPCQ_DDT_FORWARDER_HPP
14#define IPCQ_DDT_FORWARDER_HPP
27#include <ipcq/adapter.hpp>
28#include <ipcq/reader.hpp>
30#include <numapp/numapolicies.hpp>
31#include <numapp/thread.hpp>
33#include <fmt/format.h>
38#include <shared_mutex>
47template <
typename Tuple>
50template <
typename... PublisherType>
51struct Wrapper<std::tuple<PublisherType...>> {
52 using ServiceContainer = rtctk::componentFramework::ServiceContainer;
54 static std::tuple<PublisherType...>
55 MakePublishers(
const std::string& db_prefix, ServiceContainer& services) {
56 return std::make_tuple(PublisherType(db_prefix, services)...);
69template <
typename FwdInfo,
typename ReaderType = ipcq::Reader<
typename FwdInfo::Topic>>
72 using Topic =
typename FwdInfo::Topic;
81 static_assert(FwdInfo::ID.find_first_not_of(
"abcdefghijklmnopqrstuvwxyz_0123456789") ==
82 std::string_view::npos,
83 "DDT Forwarder ID contains illegal characters!");
86 :
DdtForwarder(comp_id,
"IpcqDdtForwarder",
std::string(FwdInfo::ID), services)
88 , m_oldb(services.Get<
OldbIf>())
91 , m_oldb_prefix(fmt::format(
"/forwarders/{}",
GetId()))
92 , m_rtr_prefix_static(fmt::format(
"/{}/static/forwarders/{}", comp_id,
GetId()))
93 , m_rtr_prefix_dynamic(fmt::format(
"/{}/dynamic/forwarders/{}", comp_id,
GetId()))
94 , m_publishers(Wrapper<typename FwdInfo::DdtPublisherTupleType>::MakePublishers(
95 fmt::format(
"{}/forwarders/{}/publishers", comp_id,
GetId()), services))
101 {
"forwarder_id",
GetId()},
104 m_samples_forwarded_reg = m_metrics.AddCounter(
106 m_oldb_prefix +
"/samples_forwarded",
107 "Number of samples forwarded",
113 m_last_sample_id_forwarded_reg = m_metrics.AddCounter(
115 m_oldb_prefix +
"/last_sample_id_forwarded",
116 "Last sample id forwarded",
118 "last_sample_id_forwarded"
122 m_freq_estimator = std::make_unique<FrequencyEstimator>(
123 m_metrics,
"Estimated frequency of the data forwarder", m_oldb_prefix);
125 m_dur_monitor = std::make_unique<DurationMonitor>(
126 m_metrics,
"Duration of publishing data to DDT", m_oldb_prefix);
129 std::make_unique<BufferMonitor>(m_metrics,
"SHM read buffer occupancy", m_oldb_prefix);
133 auto queue_name_path =
DataPointPath{m_rtr_prefix_static +
"/shm_queue_name"};
134 m_queue_name = m_rtr.GetDataPoint<std::string>(queue_name_path);
136 auto thread_policies_path =
DataPointPath{m_rtr_prefix_static +
"/thread_policies"};
139 auto subsample_factor_path =
DataPointPath{m_rtr_prefix_dynamic +
"/subsample_factor"};
140 m_subsample_factor = m_rtr.GetDataPoint<int64_t>(subsample_factor_path);
145 if (m_processing_thread.joinable()) {
146 m_processing_thread.join();
156 m_processing_thread = numapp::MakeThread(
GetId().substr(0, 15),
157 m_thread_policies.value_or(numapp::NumaPolicies()),
158 [&]() { Process(); });
161 using namespace std::chrono_literals;
162 std::this_thread::sleep_for(10ms);
184 if (m_processing_thread.joinable()) {
185 m_processing_thread.join();
194 std::scoped_lock lock(m_exception_mutex);
195 m_exception = std::current_exception();
205 LOG4CPLUS_INFO(
m_logger, fmt::format(
"Updating IpcqDdtForwarder '{}'",
GetId()));
207 auto subsample_factor_path =
DataPointPath{m_rtr_prefix_dynamic +
"/subsample_factor"};
208 m_subsample_factor = m_rtr.GetDataPoint<int64_t>(subsample_factor_path);
210 std::apply([&](
auto&&... pub) { ((pub.Update()), ...); }, m_publishers);
215 auto lock = std::shared_lock{m_exception_mutex};
217 std::rethrow_exception(m_exception);
223 using namespace std::chrono_literals;
227 const std::error_code ok{};
228 std::pair<std::error_code, size_t> result;
230 std::vector<Topic> read_buffer;
231 read_buffer.reserve(MAX_SAMPLES_READ);
233 m_samples_forwarded.Store(0);
234 m_last_sample_id_forwarded.Store(0);
236 ReaderType reader(m_queue_name.c_str());
238 size_t reader_capacity = reader.Capacity();
248 if (
auto ret = reader.Reset(); ret == ok) {
251 CII_THROW(
IpcqError,
"Error resetting ipcq Reader");
255 std::this_thread::sleep_for(1ms);
264 to_read = reader.NumAvailable();
268 to_read = std::min(to_read, MAX_SAMPLES_READ);
270 if (m_subsample_factor > 1) {
271 m_sampling_counter = m_sampling_counter % m_subsample_factor;
272 if (m_sampling_counter == 0) {
275 to_skip = std::min(to_read, m_subsample_factor - m_sampling_counter);
280 m_buffer_monitor->Tick(reader.NumAvailable(), reader_capacity);
281 result = reader.Read(ipcq::BackInserter(read_buffer), to_read, 100ms);
282 for (
const auto& sample : read_buffer) {
283 m_last_sample_id_forwarded.Store(sample.sample_id);
284 auto t1 = std::chrono::steady_clock::now();
285 ExtractAndPublish(sample);
286 auto t2 = std::chrono::steady_clock::now();
287 m_dur_monitor->Tick(t2 - t1);
288 m_freq_estimator->Tick();
289 m_samples_forwarded++;
293 result = reader.Skip(to_skip, 100ms);
295 m_sampling_counter += result.second;
297 if (not(result.first == ok or result.first == ipcq::Error::Timeout)) {
298 std::string error =
"Error reading from ipcq: " + result.first.message();
299 CII_THROW(IpcqError, error);
304 std::this_thread::sleep_for(1ms);
312 std::scoped_lock lock(m_exception_mutex);
313 m_exception = std::current_exception();
319 void ExtractAndPublish(
const Topic& sample) {
320 auto func = [&](
auto& pub) {
321 if (pub.IsEnabled()) {
323 auto e = std::remove_reference_t<
decltype(pub)>::StreamInfo::Extract(sample);
325 pub.Publish(std::get<0>(e),
326 reinterpret_cast<const uint8_t*
>(std::get<1>(e).data()),
327 std::get<1>(e).size());
331 std::apply([&](
auto&&... pub) { (func(pub), ...); }, m_publishers);
338 std::string m_comp_id;
339 std::string m_oldb_prefix;
340 std::string m_rtr_prefix_static;
341 std::string m_rtr_prefix_dynamic;
343 typename FwdInfo::DdtPublisherTupleType m_publishers;
345 std::atomic<State> m_requested_state;
346 std::exception_ptr m_exception =
nullptr;
347 std::shared_mutex m_exception_mutex;
349 std::thread m_processing_thread;
354 std::string m_queue_name;
359 std::optional<numapp::NumaPolicies> m_thread_policies;
364 int64_t m_subsample_factor;
369 uint64_t m_sampling_counter;
374 perfc::CounterI64 m_samples_forwarded;
375 perfc::ScopedRegistration m_samples_forwarded_reg;
380 perfc::CounterI64 m_last_sample_id_forwarded;
381 perfc::ScopedRegistration m_last_sample_id_forwarded_reg;
383 std::unique_ptr<FrequencyEstimator> m_freq_estimator;
384 std::unique_ptr<DurationMonitor> m_dur_monitor;
385 std::unique_ptr<BufferMonitor> m_buffer_monitor;
390 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:37
Component metrics interface.
Definition componentMetricsIf.hpp:164
Defines auxiliary information associated with each counter registered with ComponentMetricsIf.
Definition componentMetricsIf.hpp:49
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:77
Monitors min, mean and max duration and publishes them to OLDB.
Definition durationMonitor.hpp:37
Estimates the frequency in which Tick is called and publishes result to OLDB.
Definition frequencyEstimator.hpp:31
Helper class for passing tags in Telegraf.
Definition influxTagMap.hpp:27
This Exception is raised when the ipc queue returns an error that cannot be handled by the Telemetry ...
Definition exceptions.hpp:384
Base interface for all OLDB adapters.
Definition oldbIf.hpp:25
Base interface for all Runtime Configuration Repository adapters.
Definition runtimeRepoIf.hpp:27
Container class that holds services of any type.
Definition serviceContainer.hpp:39
DdtForwarder(const std::string &comp_id, const std::string &fwd_type, const std::string &fwd_id, ServiceContainer &services)
Definition ddtForwarder.hpp:56
void AssertState(const std::set< State > &states)
Definition ddtForwarder.hpp:144
virtual void SetState(State state)
Definition ddtForwarder.hpp:131
State
States a forwarder unit can be in.
Definition ddtForwarder.hpp:54
@ STARTING
Definition ddtForwarder.hpp:54
@ STOPPED
Definition ddtForwarder.hpp:54
@ RUNNING
Definition ddtForwarder.hpp:54
@ IDLE
Definition ddtForwarder.hpp:54
@ ERROR
Definition ddtForwarder.hpp:54
log4cplus::Logger & m_logger
Definition ddtForwarder.hpp:167
State GetState()
Get the state of the forwarder unit.
Definition ddtForwarder.hpp:91
std::string GetId()
Get identifier of the forwarder unit.
Definition ddtForwarder.hpp:84
rtctk::componentFramework::RuntimeRepoIf RuntimeRepoIf
Definition ipcqDdtForwarder.hpp:74
void Idle() override
Stop publishing DDT streams.
Definition ipcqDdtForwarder.hpp:177
rtctk::componentFramework::ComponentMetricsIf ComponentMetricsIf
Definition ipcqDdtForwarder.hpp:76
void Recover() override
Stop the processing thread of the forwarder unit and clear errors.
Definition ipcqDdtForwarder.hpp:189
rtctk::componentFramework::FrequencyEstimator<> FrequencyEstimator
Definition ipcqDdtForwarder.hpp:77
IpcqDdtForwarder(const std::string &comp_id, ServiceContainer &services)
Definition ipcqDdtForwarder.hpp:85
typename FwdInfo::Topic Topic
Definition ipcqDdtForwarder.hpp:72
void Start() override
Start the processing thread of the forwarder unit.
Definition ipcqDdtForwarder.hpp:150
rtctk::componentFramework::BufferMonitor<> BufferMonitor
Definition ipcqDdtForwarder.hpp:79
rtctk::componentFramework::DurationMonitor<> DurationMonitor
Definition ipcqDdtForwarder.hpp:78
void Stop() override
Stop the processing thread of the forwarder unit.
Definition ipcqDdtForwarder.hpp:182
void Update() override
Reload dynamic configuration of the forwarder unit.
Definition ipcqDdtForwarder.hpp:202
~IpcqDdtForwarder() override
Definition ipcqDdtForwarder.hpp:143
void CheckErrors() override
Check for Errors, will rethrow errors thrown in the forwarder.
Definition ipcqDdtForwarder.hpp:213
rtctk::componentFramework::OldbIf OldbIf
Definition ipcqDdtForwarder.hpp:75
rtctk::componentFramework::ServiceContainer ServiceContainer
Definition ipcqDdtForwarder.hpp:73
void Run() override
Start publishing DDT streams.
Definition ipcqDdtForwarder.hpp:172
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.
Definition commandReplier.cpp:22
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:33
Definition businessLogic.cpp:24
Definition ddsSub.hpp:156
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.