22#include <boost/algorithm/string.hpp>
23#include <ipcq/adapter.hpp>
24#include <ipcq/error.hpp>
25#include <ipcq/reader.hpp>
27#include <numapp/numapolicies.hpp>
28#include <numapp/thread.hpp>
32template <
typename RecInfoType>
34 const std::string& unit_id,
37 , m_queue_name(
m_rtr.GetDataPoint<
std::string>(
38 DataPointPath(fmt::format(RTR_PATH_QUEUE_NAME, comp_id, unit_id))))
39 , m_output(RecInfoType::COLUMNS) {
40 auto queue_name_path =
DataPointPath(fmt::format(OLDB_PATH_QUEUE_NAME, comp_id, unit_id));
41 m_oldb.CreateDataPoint<std::string>(queue_name_path);
42 m_oldb.SetDataPoint<std::string>(queue_name_path, m_queue_name);
44 auto cpu_affinity_path =
DataPointPath(fmt::format(RTR_PATH_CPU_AFFINITY, comp_id, unit_id));
45 if (
m_rtr.DataPointExists(cpu_affinity_path)) {
46 m_cpu_affinity =
m_rtr.GetDataPoint<int32_t>(cpu_affinity_path);
51 m_samples_written_reg =
54 "Number of samples successfully written to file",
58 m_last_observed_sample_id_reg =
59 m_metrics.AddCounter(&m_last_observed_sample_id,
61 "Last sample id successfully written to file",
63 "last_sample_id_written"));
65 m_freq_estimator = std::make_unique<FrequencyEstimator<>>(
66 m_metrics,
"Estimated frequency of the data writer", unit_id);
69 std::make_unique<DurationMonitor<>>(
m_metrics,
"Duration of writing data to file", unit_id);
72 std::make_unique<BufferMonitor<>>(
m_metrics,
"SHM read buffer occupancy", unit_id);
77template <
typename RecInfoType>
80 if (m_process_thread.joinable()) {
81 m_process_thread.join();
85template <
typename RecInfoType>
96 auto policies = numapp::NumaPolicies();
97 if (m_cpu_affinity.has_value()) {
99 numapp::Cpumask::MakeFromCpuStringAll(std::to_string(m_cpu_affinity.value()).c_str());
100 policies.SetCpuAffinity(numapp::CpuAffinity(cpu_mask));
104 numapp::MakeThread(
m_unit_id.substr(0, 15), policies, [&]() { return Process(); });
107template <
typename RecInfoType>
112template <
typename RecInfoType>
115 if (m_process_thread.joinable()) {
116 m_process_thread.join();
118 std::vector<std::filesystem::path> files;
127template <
typename RecInfoType>
137template <
typename RecInfoType>
138void IpcqRecordingUnit<RecInfoType>::LoadDynamicConfig() {
139 auto subsample_factor_path =
140 DataPointPath(fmt::format(RTR_PATH_SUBSAMPLE_FACTOR, m_comp_id, m_unit_id));
141 m_subsample_factor = m_rtr.GetDataPoint<int64_t>(subsample_factor_path);
143 auto disabled_fields = GetDisabled(
144 m_rtr,
DataPointPath(fmt::format(RTR_PATH_TELEMETRY_SUBSET, m_comp_id, m_unit_id)));
145 m_output.SetDisabledFields(disabled_fields);
147 auto start_sample_id_path =
148 DataPointPath(fmt::format(RTR_PATH_START_SAMPLE_ID, m_comp_id, m_unit_id));
149 m_start_sample_id = m_rtr.GetDataPoint<int64_t>(start_sample_id_path);
151 auto stop_after_samples_path =
152 DataPointPath(fmt::format(RTR_PATH_STOP_AFTER_NUM_SAMPLES, m_comp_id, m_unit_id));
153 m_stop_after_num_samples = m_rtr.GetDataPoint<int64_t>(stop_after_samples_path);
156template <
typename RecInfoType>
157void IpcqRecordingUnit<RecInfoType>::Process() {
158 using namespace std::chrono_literals;
161 std::vector<typename RecInfoType::Topic> buffer;
162 buffer.reserve(MAX_SAMPLES_READ);
164 const std::error_code ok{};
165 std::pair<std::error_code, size_t> result;
167 bool files_open =
false;
168 m_samples_written.Store(0);
169 m_last_observed_sample_id.Store(0);
171 auto reader = ipcq::Reader<typename RecInfoType::Topic>(m_queue_name.c_str());
173 size_t reader_capacity = reader.Capacity();
175 if (not SetState(State::IDLE, State::PREPARING)) {
177 CII_THROW(InvalidStateChange,
178 "IpcqRecordingUnit not in preparing before starting thread");
180 SetFailed(std::current_exception());
185 while (m_stop ==
false) {
186 switch (GetState()) {
189 if (
auto ret = reader.Reset(); ret == ok || ret == ipcq::Error::Closed) {
190 SetState(State::WAITING,
192 "IpcqRecordingUnit not in IDLE before entering WAITING");
195 fmt::format(
"Error resetting ipcq Reader: {}", ret.message()));
199 std::this_thread::sleep_for(1ms);
202 case State::WAITING: {
203 result = reader.Read(ipcq::BackInserter(buffer), 1, 100ms);
204 if (not(result.first == ok or result.first == ipcq::Error::Timeout)) {
205 std::string error =
"Error reading from ipcq: " + result.first.message();
208 for (
const auto& element : buffer) {
209 m_last_observed_sample_id.Store(element.sample_id);
213 if ((m_last_observed_sample_id.Load() >= m_start_sample_id - 1) and
214 (not HasLeaders() or (HasLeaders() and HasFirstLeaderStarted()))) {
215 m_sampling_counter = 0;
216 SetState(State::RUNNING,
218 "Expected to be in WAITING, before going RUNNING");
222 case State::RUNNING: {
223 if (HasLeaders() and HasLastLeaderFinished()) {
224 SetState(State::FINISHED,
226 "Expected to be in RUNNING, before going FINISHED");
231 size_t to_read = reader.NumAvailable();
235 to_read = std::min(to_read, MAX_SAMPLES_READ);
237 if (m_subsample_factor > 1) {
238 m_sampling_counter = m_sampling_counter % m_subsample_factor;
239 if (m_sampling_counter == 0) {
242 to_skip = std::min(to_read, m_subsample_factor - m_sampling_counter);
247 m_buffer_monitor->Tick(reader.NumAvailable(), reader_capacity);
248 result = reader.Read(ipcq::BackInserter(buffer), to_read, 100ms);
249 for (
const auto& element : buffer) {
250 m_last_observed_sample_id.Store(element.sample_id);
251 auto t1 = std::chrono::steady_clock::now();
252 auto sample = RecInfoType::AsTuple(element);
253 if (not files_open) {
255 m_output.SetColumnLength(sample);
256 m_output.Open(*m_file_path);
259 m_output.Write(sample);
260 auto t2 = std::chrono::steady_clock::now();
261 m_dur_monitor->Tick(t2 - t1);
262 m_freq_estimator->Tick();
264 if (m_stop_after_num_samples > 0 and
265 m_samples_written.Load() >= m_stop_after_num_samples) {
266 SetState(State::FINISHED,
268 "Expected to be in RUNNING, before going FINISHED");
274 result = reader.Skip(to_skip, 100ms);
276 m_sampling_counter += result.second;
278 if (not(result.first == ok or result.first == ipcq::Error::Timeout)) {
279 std::string error =
"Error reading from ipcq: " + result.first.message();
285 std::this_thread::sleep_for(1ms);
306 SetFailed(std::current_exception());
311template <
typename RecInfoType>
312typename RecInfoType::Recorder::DisabledFields
314 typename RecInfoType::Recorder::DisabledFields result{};
319 auto fields = rtr.
GetDataPoint<std::vector<std::string>>(path);
321 if (fields.empty()) {
325 if (fields.size() > std::tuple_size<typename RecInfoType::Recorder::DisabledFields>::value) {
326 CII_THROW(
InvalidSetting,
"Invalid disabled fields setting. Too many fields");
330 for (
size_t i = 0; i < std::tuple_size<typename RecInfoType::Recorder::TupleType>::value; i++) {
334 for (
const auto& name : fields) {
336 for (
size_t i = 0; i < std::tuple_size<typename RecInfoType::Recorder::TupleType>::value;
338 if (name == RecInfoType::COLUMNS[i].name) {
346 std::string{
"Invalid disabled fields setting: Could not find field '" + name +
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
Definition fitsDataRecorder.hpp:28
Helper class for passing tags in Telegraf.
Definition influxTagMap.hpp:27
This Exception is raised when a invalid setting was used in the runtime repo.
Definition exceptions.hpp:340
This Exception is raised when the state change requested is invalid.
Definition exceptions.hpp:326
This Exception is raised when the ipc queue returns an error that cannot be handled by the Telemetry ...
Definition exceptions.hpp:384
std::vector< std::filesystem::path > Stop() override
Stop the recording thread and wait for it's termination.
Definition ipcqRecordingUnit.ipp:113
void Update() override
Update settings from RuntimeRepo.
Definition ipcqRecordingUnit.ipp:128
void Prepare(const std::filesystem::path &file_path) override
Prepare the recording thread and start recording.
Definition ipcqRecordingUnit.ipp:86
static RecInfoType::Recorder::DisabledFields GetDisabled(RepositoryIf &rtr, const DataPointPath &sub_path)
get disabled fields from a DataPoint in the runtime repo.
Definition ipcqRecordingUnit.ipp:313
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:33
void Start() override
Start the recording.
Definition ipcqRecordingUnit.ipp:108
~IpcqRecordingUnit() override
Destructor.
Definition ipcqRecordingUnit.ipp:78
OldbIf & m_oldb
Definition recordingUnit.hpp:178
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:19
virtual void Update()
Update dynamic settings.
Definition recordingUnit.cpp:178
std::string GetId()
Get the unit_it of this RecordingUnit.
Definition recordingUnit.cpp:128
std::string m_unit_id
Definition recordingUnit.hpp:176
ComponentMetricsIf & m_metrics
Definition recordingUnit.hpp:179
RuntimeRepoIf & m_rtr
Definition recordingUnit.hpp:177
void SetStopped()
Set the Unit state to STOPPED independent of the current State.
Definition recordingUnit.cpp:157
@ STOPPED
Definition recordingUnit.hpp:53
@ RUNNING
Definition recordingUnit.hpp:53
@ PREPARING
Definition recordingUnit.hpp:53
State GetState()
Get the current state of the Recording Unit.
Definition recordingUnit.cpp:162
bool SetState(State state, State precondition)
Sets the new state, only goes to new state, if expected state matches.
Definition recordingUnit.cpp:132
std::optional< std::filesystem::path > m_file_path
Definition recordingUnit.hpp:180
bool IsEnabled()
Checks whether the Recording Unit is enabled.
Definition recordingUnit.cpp:166
Abstract interface providing basic read and write facilities to a repository.
Definition repositoryIf.hpp:51
T GetDataPoint(const DataPointPath &path) const
Fetches a datapoint from the repository.
Definition repositoryIf.ipp:1843
bool DataPointExists(const DataPointPath &path) const
Checks for the existence of a datapoint in the repository.
Definition repositoryIf.cpp:766
Container class that holds services of any type.
Definition serviceContainer.hpp:39
FitsRecorder allows to write ColumnData to into fits files in a specified directory.
Recording Unit that can record from shared memory queue.
Definition commandReplier.cpp:22
Definition ddsSub.hpp:156