21#include <boost/algorithm/string.hpp>
22#include <ipcq/adapter.hpp>
23#include <ipcq/error.hpp>
24#include <ipcq/reader.hpp>
26#include <numapp/numapolicies.hpp>
27#include <numapp/thread.hpp>
31template <
typename RecInfoType>
33 const std::string& unit_id,
36 , m_queue_name(
m_rtr.GetDataPoint<
std::string>(
38 , m_output(RecInfoType::COLUMNS) {
39 auto queue_name_path =
DataPointPath(fmt::format(OLDB_PATH_QUEUE_NAME, comp_id, unit_id));
40 m_oldb.CreateDataPoint<std::string>(queue_name_path);
41 m_oldb.SetDataPoint<std::string>(queue_name_path, m_queue_name);
43 auto cpu_affinity_path =
DataPointPath(fmt::format(RTR_PATH_CPU_AFFINITY, comp_id, unit_id));
44 if (
m_rtr.DataPointExists(cpu_affinity_path)) {
45 m_cpu_affinity =
m_rtr.GetDataPoint<int32_t>(cpu_affinity_path);
50 m_samples_written_reg =
53 "Number of samples successfully written to file",
57 m_last_observed_sample_id_reg =
58 m_metrics.AddCounter(&m_last_observed_sample_id,
60 "Last sample id successfully written to file",
62 "last_sample_id_written"));
64 m_freq_estimator = std::make_unique<FrequencyEstimator<>>(
65 m_metrics,
"Estimated frequency of the data writer", unit_id);
68 std::make_unique<DurationMonitor<>>(
m_metrics,
"Duration of writing data to file", unit_id);
71 std::make_unique<BufferMonitor<>>(
m_metrics,
"SHM read buffer occupancy", unit_id);
76template <
typename RecInfoType>
79 if (m_process_thread.joinable()) {
80 m_process_thread.join();
84template <
typename RecInfoType>
95 auto policies = numapp::NumaPolicies();
96 if (m_cpu_affinity.has_value()) {
98 numapp::Cpumask::MakeFromCpuStringAll(std::to_string(m_cpu_affinity.value()).c_str());
99 policies.SetCpuAffinity(numapp::CpuAffinity(cpu_mask));
103 numapp::MakeThread(
m_unit_id.substr(0, 15), policies, [&]() { return Process(); });
106template <
typename RecInfoType>
111template <
typename RecInfoType>
114 if (m_process_thread.joinable()) {
115 m_process_thread.join();
117 std::vector<std::filesystem::path> files;
126template <
typename RecInfoType>
136template <
typename RecInfoType>
137void IpcqRecordingUnit<RecInfoType>::LoadDynamicConfig() {
138 auto subsample_factor_path =
139 DataPointPath(fmt::format(RTR_PATH_SUBSAMPLE_FACTOR, m_comp_id, m_unit_id));
140 m_subsample_factor = m_rtr.GetDataPoint<int64_t>(subsample_factor_path);
142 auto disabled_fields = GetDisabled(
143 m_rtr,
DataPointPath(fmt::format(RTR_PATH_TELEMETRY_SUBSET, m_comp_id, m_unit_id)));
144 m_output.SetDisabledFields(disabled_fields);
146 auto start_sample_id_path =
147 DataPointPath(fmt::format(RTR_PATH_START_SAMPLE_ID, m_comp_id, m_unit_id));
148 m_start_sample_id = m_rtr.GetDataPoint<int64_t>(start_sample_id_path);
150 auto stop_after_samples_path =
151 DataPointPath(fmt::format(RTR_PATH_STOP_AFTER_NUM_SAMPLES, m_comp_id, m_unit_id));
152 m_stop_after_num_samples = m_rtr.GetDataPoint<int64_t>(stop_after_samples_path);
155template <
typename RecInfoType>
156void IpcqRecordingUnit<RecInfoType>::Process() {
157 using namespace std::chrono_literals;
160 std::vector<typename RecInfoType::Topic> buffer;
161 buffer.reserve(MAX_SAMPLES_READ);
163 const std::error_code ok{};
164 std::pair<std::error_code, size_t> result;
166 bool files_open =
false;
167 m_samples_written.Store(0);
168 m_last_observed_sample_id.Store(0);
170 auto reader = ipcq::Reader<typename RecInfoType::Topic>(m_queue_name.c_str());
172 size_t reader_capacity = reader.Capacity();
174 if (not SetState(State::IDLE, State::PREPARING)) {
176 CII_THROW(InvalidStateChange,
177 "IpcqRecordingUnit not in preparing before starting thread");
179 SetFailed(std::current_exception());
184 while (m_stop ==
false) {
185 switch (GetState()) {
188 if (
auto ret = reader.Reset(); ret == ok || ret == ipcq::Error::Closed) {
189 SetState(State::WAITING,
191 "IpcqRecordingUnit not in IDLE before entering WAITING");
194 fmt::format(
"Error resetting ipcq Reader: {}", ret.message()));
198 std::this_thread::sleep_for(1ms);
201 case State::WAITING: {
202 result = reader.Read(ipcq::BackInserter(buffer), 1, 100ms);
203 if (not(result.first == ok or result.first == ipcq::Error::Timeout)) {
204 std::string error =
"Error reading from ipcq: " + result.first.message();
207 for (
const auto& element : buffer) {
208 m_last_observed_sample_id.Store(element.sample_id);
212 if ((m_last_observed_sample_id.Load() >= m_start_sample_id - 1) and
213 (not HasLeaders() or (HasLeaders() and HasFirstLeaderStarted()))) {
214 m_sampling_counter = 0;
215 SetState(State::RUNNING,
217 "Expected to be in WAITING, before going RUNNING");
221 case State::RUNNING: {
222 if (HasLeaders() and HasLastLeaderFinished()) {
223 SetState(State::FINISHED,
225 "Expected to be in RUNNING, before going FINISHED");
230 size_t to_read = reader.NumAvailable();
234 to_read = std::min(to_read, MAX_SAMPLES_READ);
236 if (m_subsample_factor > 1) {
237 m_sampling_counter = m_sampling_counter % m_subsample_factor;
238 if (m_sampling_counter == 0) {
241 to_skip = std::min(to_read, m_subsample_factor - m_sampling_counter);
246 m_buffer_monitor->Tick(reader.NumAvailable(), reader_capacity);
247 result = reader.Read(ipcq::BackInserter(buffer), to_read, 100ms);
248 for (
const auto& element : buffer) {
249 m_last_observed_sample_id.Store(element.sample_id);
250 auto t1 = std::chrono::steady_clock::now();
251 auto sample = RecInfoType::AsTuple(element);
252 if (not files_open) {
254 m_output.SetColumnLength(sample);
255 m_output.Open(*m_file_path);
258 m_output.Write(sample);
259 auto t2 = std::chrono::steady_clock::now();
260 m_dur_monitor->Tick(t2 - t1);
261 m_freq_estimator->Tick();
263 if (m_stop_after_num_samples > 0 and
264 m_samples_written.Load() >= m_stop_after_num_samples) {
265 SetState(State::FINISHED,
267 "Expected to be in RUNNING, before going FINISHED");
273 result = reader.Skip(to_skip, 100ms);
275 m_sampling_counter += result.second;
277 if (not(result.first == ok or result.first == ipcq::Error::Timeout)) {
278 std::string error =
"Error reading from ipcq: " + result.first.message();
284 std::this_thread::sleep_for(1ms);
305 SetFailed(std::current_exception());
310template <
typename RecInfoType>
311typename RecInfoType::Recorder::DisabledFields
313 typename RecInfoType::Recorder::DisabledFields result{};
318 auto fields = rtr.
GetDataPoint<std::vector<std::string>>(path);
320 if (fields.empty()) {
324 if (fields.size() > std::tuple_size_v<typename RecInfoType::Recorder::DisabledFields>) {
325 CII_THROW(
InvalidSetting,
"Invalid disabled fields setting. Too many fields");
329 for (
size_t i = 0; i < std::tuple_size_v<typename RecInfoType::Recorder::TupleType>; i++) {
333 for (
const auto& name : fields) {
335 for (
size_t i = 0; i < std::tuple_size_v<typename RecInfoType::Recorder::TupleType>;
337 if (name == RecInfoType::COLUMNS[i].name) {
345 std::string{
"Invalid disabled fields setting: Could not find field '" + name +
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
Definition fitsDataRecorder.hpp:27
Helper class for passing tags in Telegraf.
Definition influxTagMap.hpp:26
This Exception is raised when a invalid setting was used in the runtime repo.
Definition exceptions.hpp:347
This Exception is raised when the state change requested is invalid.
Definition exceptions.hpp:333
This Exception is raised when the ipc queue returns an error that cannot be handled by the Telemetry ...
Definition exceptions.hpp:391
std::vector< std::filesystem::path > Stop() override
Stop the recording thread and wait for it's termination.
Definition ipcqRecordingUnit.ipp:112
void Update() override
Update settings from RuntimeRepo.
Definition ipcqRecordingUnit.ipp:127
void Prepare(const std::filesystem::path &file_path) override
Prepare the recording thread and start recording.
Definition ipcqRecordingUnit.ipp:85
static RecInfoType::Recorder::DisabledFields GetDisabled(RepositoryIf &rtr, const DataPointPath &sub_path)
get disabled fields from a DataPoint in the runtime repo.
Definition ipcqRecordingUnit.ipp:312
IpcqRecordingUnit(const std::string &comp_id, const std::string &unit_id, ServiceContainer &services)
Create a new Ipcq Recorder reading from a given queue and outputting to the given output stage.
Definition ipcqRecordingUnit.ipp:32
void Start() override
Start the recording.
Definition ipcqRecordingUnit.ipp:107
~IpcqRecordingUnit() override
Destructor.
Definition ipcqRecordingUnit.ipp:77
OldbIf & m_oldb
Definition recordingUnit.hpp:177
RecordingUnit(const std::string &comp_id, const std::string &unit_id, const std::string &unit_type, ServiceContainer &services)
Create a new RecordingIngestion.
Definition recordingUnit.cpp:18
virtual void Update()
Update dynamic settings.
Definition recordingUnit.cpp:179
bool IsEnabled() const
Checks whether the Recording Unit is enabled.
Definition recordingUnit.cpp:167
std::string m_unit_id
Definition recordingUnit.hpp:175
ComponentMetricsIf & m_metrics
Definition recordingUnit.hpp:178
const std::string & GetId() const
Get the unit_it of this RecordingUnit.
Definition recordingUnit.cpp:129
RuntimeRepoIf & m_rtr
Definition recordingUnit.hpp:176
void SetStopped()
Set the Unit state to STOPPED independent of the current State.
Definition recordingUnit.cpp:158
@ STOPPED
Definition recordingUnit.hpp:52
@ RUNNING
Definition recordingUnit.hpp:52
@ PREPARING
Definition recordingUnit.hpp:52
State GetState() const
Get the current state of the Recording Unit.
Definition recordingUnit.cpp:163
bool SetState(State state, State precondition)
Sets the new state, only goes to new state, if expected state matches.
Definition recordingUnit.cpp:133
std::optional< std::filesystem::path > m_file_path
Definition recordingUnit.hpp:179
Abstract interface providing basic read and write facilities to a repository.
Definition repositoryIf.hpp:50
T GetDataPoint(const DataPointPath &path) const
Fetches a datapoint from the repository.
Definition repositoryIf.ipp:1864
bool DataPointExists(const DataPointPath &path) const
Checks for the existence of a datapoint in the repository.
Definition repositoryIf.cpp:771
Container class that holds services of any type.
Definition serviceContainer.hpp:38
FitsRecorder allows to write ColumnData to into fits files in a specified directory.
Recording Unit that can record from shared memory queue.
Definition dataPointPath.hpp:464
Definition commandReplier.cpp:21
Definition ddsSub.hpp:155