RTC Toolkit 6.0.0
Loading...
Searching...
No Matches
dataPointRecordingUnit.hpp
Go to the documentation of this file.
1
11#ifndef RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
12#define RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
13
14#include <memory>
22#include <taiclock/taiClock.hpp>
23
24#include <fmt/format.h>
25#include <numapp/numapolicies.hpp>
26#include <numapp/thread.hpp>
27
28#include <cstdint>
29#include <exception>
30#include <string>
31#include <string_view>
32#include <thread>
33#include <typeinfo>
34#include <vector>
35
37
38using namespace std::string_view_literals;
39
40enum class DataPointRecordingSource : uint8_t { OLDB, RUNTIMEREPO };
41
47template <typename DpType>
48class [[deprecated("Use RepositoryRecordingUnit instead.")]] DataPointRecordingUnit
49 : public RecordingUnit {
50public:
51 // we are using a bit-mask to configure when to capture data
52 using CaptureMask = uint32_t;
53 static constexpr uint32_t CAPTURE_ON_START = 1;
54 static constexpr uint32_t CAPTURE_ON_STOP = 2;
55 static constexpr uint32_t CAPTURE_ON_CHANGE = 4;
56
57 using TimepointType = taiclock::TaiClock::time_point::rep;
58
59 using OutputDpType = std::conditional_t<IS_SPAN_CONVERTIBLE<DpType>, AsSpan<DpType>, DpType>;
61
72 DataPointRecordingUnit(const std::string& comp_id,
73 const std::string& unit_id,
74 ServiceContainer& services,
75 const DataPointPath& dp_path,
77 std::unique_ptr<OutputStageType>&& output_stage = {},
78 std::optional<size_t> fixed_recording_length = std::nullopt)
79 : RecordingUnit(comp_id, unit_id, "DataPoint", services)
80 , m_dp_path{dp_path}
81 , m_recording_source{source}
82 , m_dp_buffer()
83 , m_output{std::move(output_stage)}
84 , m_recording_length{fixed_recording_length} {
85 if (m_output == nullptr) {
86 m_output = std::make_unique<FitsRecorder<TimepointType, OutputDpType>>(COLUMNS);
87 }
88
89 if (m_recording_source == DataPointRecordingSource::OLDB) {
90 m_repository = static_cast<RepositoryIf*>(&m_oldb);
91 m_repository_subscriber = static_cast<RepositorySubscriberIf*>(&m_oldb);
92 } else if (m_recording_source == DataPointRecordingSource::RUNTIMEREPO) {
93 m_repository = static_cast<RepositoryIf*>(&m_rtr);
94 m_repository_subscriber = static_cast<RepositorySubscriberIf*>(&m_rtr);
95 } else {
96 CII_THROW(InvalidSetting, "Invalid recording source");
97 }
98 if (not m_repository or not m_repository_subscriber) {
99 CII_THROW(InvalidSetting, "Invalid recording source");
100 }
101
102 auto input_dp_path = DataPointPath(fmt::format(OLDB_PATH_DP_NAME, comp_id, unit_id));
103 if (not m_oldb.DataPointExists(input_dp_path)) {
104 m_oldb.CreateDataPoint<std::string>(input_dp_path);
105 }
106 m_oldb.SetDataPoint<std::string>(input_dp_path, dp_path);
107
108 auto capture_mask_path =
109 DataPointPath(fmt::format(RTR_PATH_CAPTURE_MASK, comp_id, unit_id));
110 if (m_rtr.DataPointExists(capture_mask_path)) {
111 m_capture_mask = m_rtr.GetDataPoint<int32_t>(capture_mask_path);
112 } else {
113 m_capture_mask = CAPTURE_ON_START + CAPTURE_ON_CHANGE + CAPTURE_ON_STOP;
114 }
115
116 const InfluxTagMap base_tags = {{"unit_id", unit_id}};
117
118 m_samples_written_reg = m_metrics.AddCounter(
119 &m_samples_written,
120 CounterMetricInfo(
121 unit_id + "/samples_written", "Samples written", base_tags, "samples_written"));
122 }
123
125 m_stop = true;
126 if (m_process_thread.joinable()) {
127 m_process_thread.join();
128 }
129 SetStopped();
130 }
131
135 void Prepare(const std::filesystem::path& file_path) override {
136 if (not IsEnabled()) {
137 return;
138 }
139
142 "Error in transition to PREPARING, DataPointRecordingUnit not in STOPPED State");
143
144 m_file_path = file_path / (GetId() + m_output->DefaultFileExtension());
145
146 if (not m_repository->DataPointExists(m_dp_path)) {
147 SetFailed(nullptr);
148 CII_THROW(InvalidSetting, "DataPoint does not exist");
149 }
150
151 if (m_capture_mask == 0) {
152 SetFailed(nullptr);
153 CII_THROW(InvalidSetting, "Invalid capture mask 0");
154 }
155
156 using FitsRecorderType = FitsRecorder<TimepointType, OutputDpType>;
157 FitsRecorderType* fits_output = dynamic_cast<FitsRecorderType*>(m_output.get());
158 if (fits_output != nullptr) {
159 auto rec_length =
160 m_recording_length.value_or(m_repository->GetDataPointSize(m_dp_path));
161 fits_output->SetColumnLength(1, rec_length);
162 }
163
164 auto policies = numapp::NumaPolicies();
165 m_process_thread =
166 numapp::MakeThread(m_unit_id.substr(0, 15), policies, [&]() { return Process(); });
167 }
168
171 void Start() override {
172 m_start = true;
173 }
174
178 std::vector<std::filesystem::path> Stop() override {
179 m_stop = true;
180 if (m_process_thread.joinable()) {
181 m_process_thread.join();
182 }
183 std::vector<std::filesystem::path> files;
184 if (m_file_path) {
185 files.push_back(*m_file_path);
186 }
187 m_file_path.reset();
188 SetStopped();
189 return files;
190 }
191
192 static constexpr typename OutputStageType::ColumnDescription COLUMNS =
193 typename OutputStageType::ColumnDescription{{{"timestamp"sv, ""sv}, {"payload"sv, ""sv}}};
194
195private:
196 void Process() {
197 using namespace std::chrono_literals;
198
199 try {
200 m_output->Open(*m_file_path);
201 m_samples_written.Store(0);
203
204 if (m_capture_mask & CAPTURE_ON_CHANGE) {
205 subscription = std::move(m_repository_subscriber->Subscribe<DpType>(
206 m_dp_path,
207 // cppcheck-suppress constParameterReference
208 [this](auto& path, auto& value, auto& metadata) {
209 if (GetState() == State::RUNNING) {
210 try {
211 m_output->Write(AsTuple(value));
212 m_samples_written++;
213 } catch (...) {
214 SetFailed(std::current_exception());
215 return;
216 }
217 }
218 },
219 // NOLINTNEXTLINE(performance-unnecessary-value-param)
220 [this](std::exception_ptr error) {
221 if (error) {
222 std::rethrow_exception(error);
223 }
224 }));
225 }
226
227 SetState(State::IDLE,
228 State::PREPARING,
229 "Error in transition to IDLE, DataPointRecordingUnit not in PREPARING State");
230
231 while (m_stop == false) {
232 switch (GetState()) {
233 case State::IDLE:
234 if (m_start) {
235 SetState(State::WAITING,
236 State::IDLE,
237 "Error in transition to WAITING, DataPointRecordingUnit not in "
238 "IDLE State");
239 break;
240 }
241 std::this_thread::sleep_for(1ms);
242 break;
243 case State::WAITING:
244 if (not HasLeaders() or (HasLeaders() and HasFirstLeaderStarted())) {
245 if (m_capture_mask & CAPTURE_ON_START) {
246 m_repository->ReadDataPoint(m_dp_path, m_dp_buffer);
247 m_output->Write(AsTuple(m_dp_buffer));
248 m_samples_written++;
249 }
250
251 SetState(State::RUNNING,
252 State::WAITING,
253 "Error in transition to RUNNING, DataPointRecordingUnit not in "
254 "WAITING State");
255 break;
256 }
257 std::this_thread::sleep_for(1ms);
258 break;
259 case State::RUNNING:
260 if (HasLeaders() and HasLastLeaderFinished()) {
261 SetState(State::FINISHED,
262 State::RUNNING,
263 "Error in transition to FINISHED, DataPointRecordingUnit not in "
264 "RUNNING State");
265 break;
266 }
267 std::this_thread::sleep_for(1ms);
268 break;
269 default:
270 std::this_thread::sleep_for(1ms);
271 }
272 }
273
274 if (m_capture_mask & CAPTURE_ON_CHANGE) {
275 subscription.Unsubscribe();
276 }
277
278 if (m_capture_mask & CAPTURE_ON_STOP) {
279 m_repository->ReadDataPoint(m_dp_path, m_dp_buffer);
280 m_output->Write(AsTuple(m_dp_buffer));
281 m_samples_written++;
282 }
283
284 m_output->Close();
285 // State is set to stopped after join in Stop function
286 m_start = false;
287 m_stop = false;
288 ResetLeaderStates();
289
290 } catch (...) {
291 m_output->Close();
292 m_start = false;
293 m_stop = false;
294 SetFailed(std::current_exception());
295 ResetLeaderStates();
296 }
297 }
298
299 static std::tuple<TimepointType, OutputDpType> AsTuple(const DpType& data) {
300 auto ts = taiclock::TaiClock::now().time_since_epoch().count();
301 if constexpr (IS_SPAN_CONVERTIBLE<DpType>) {
302 return std::make_tuple(ts, ToSpan(data));
303 } else {
304 return std::make_tuple(ts, data);
305 }
306 }
307
308 // This class is deprecated. Therefore just suppressing this error.
309 // cppcheck-suppress duplInheritedMember
310 std::optional<std::filesystem::path> m_file_path;
311
312 DataPointPath m_dp_path;
313
314 DataPointRecordingSource m_recording_source;
315
316 RepositoryIf* m_repository;
317 RepositorySubscriberIf* m_repository_subscriber;
318
319 DpType m_dp_buffer;
320
321 CaptureMask m_capture_mask;
322
323 std::unique_ptr<OutputStageType> m_output;
324
325 std::optional<size_t> m_recording_length;
326
327 std::atomic<bool> m_start = false;
328 std::atomic<bool> m_stop = false;
329 std::thread m_process_thread;
330
331 perfc::CounterI64 m_samples_written;
332 perfc::ScopedRegistration m_samples_written_reg;
333
337 inline static constexpr std::string_view RTR_PATH_CAPTURE_MASK =
338 "/{}/static/rec_units/{}/capture_mask";
342 inline static constexpr std::string_view OLDB_PATH_DP_NAME = "/{}/rec_units/{}/dp_name";
343};
344
345} // namespace rtctk::componentFramework
346
347#endif // RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:76
static constexpr uint32_t CAPTURE_ON_START
Definition dataPointRecordingUnit.hpp:53
static constexpr OutputStageType::ColumnDescription COLUMNS
Definition dataPointRecordingUnit.hpp:192
std::vector< std::filesystem::path > Stop() override
Stop the recording and wait for it's termination.
Definition dataPointRecordingUnit.hpp:178
DataRecorder< TimepointType, OutputDpType > OutputStageType
Definition dataPointRecordingUnit.hpp:60
std::conditional_t< IS_SPAN_CONVERTIBLE< DpType >, AsSpan< DpType >, DpType > OutputDpType
Definition dataPointRecordingUnit.hpp:59
void Prepare(const std::filesystem::path &file_path) override
Prepare the recording.
Definition dataPointRecordingUnit.hpp:135
taiclock::TaiClock::time_point::rep TimepointType
Definition dataPointRecordingUnit.hpp:57
~DataPointRecordingUnit() override
Definition dataPointRecordingUnit.hpp:124
uint32_t CaptureMask
Definition dataPointRecordingUnit.hpp:52
static constexpr uint32_t CAPTURE_ON_CHANGE
Definition dataPointRecordingUnit.hpp:55
DataPointRecordingUnit(const std::string &comp_id, const std::string &unit_id, ServiceContainer &services, const DataPointPath &dp_path, DataPointRecordingSource source=DataPointRecordingSource::RUNTIMEREPO, std::unique_ptr< OutputStageType > &&output_stage={}, std::optional< size_t > fixed_recording_length=std::nullopt)
Create a new recording unit.
Definition dataPointRecordingUnit.hpp:72
void Start() override
Start the recording.
Definition dataPointRecordingUnit.hpp:171
static constexpr uint32_t CAPTURE_ON_STOP
Definition dataPointRecordingUnit.hpp:54
This is an abstract class that can be used to implement an OutputStage for a Recording Unit.
Definition dataRecorder.hpp:28
const std::array< ColumnMetaData, sizeof...(T)> ColumnDescription
Definition dataRecorder.hpp:48
Definition fitsDataRecorder.hpp:70
This Exception is raised when a invalid setting was used in the runtime repo.
Definition exceptions.hpp:347
Abstract base class for all sources that can be recorded by the MetadataCollector and TelemetryRecord...
Definition recordingUnit.hpp:50
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
void SetFailed(const std::exception_ptr &exception)
Set the unit into failed state, with the given exception.
Definition recordingUnit.cpp:151
bool IsEnabled() const
Checks whether the Recording Unit is enabled.
Definition recordingUnit.cpp:167
std::string m_unit_id
Definition recordingUnit.hpp:175
const std::string & GetId() const
Get the unit_it of this RecordingUnit.
Definition recordingUnit.cpp:129
void SetStopped()
Set the Unit state to STOPPED independent of the current State.
Definition recordingUnit.cpp:158
@ STOPPED
Definition recordingUnit.hpp:52
@ PREPARING
Definition recordingUnit.hpp:52
bool SetState(State state, State precondition)
Sets the new state, only goes to new state, if expected state matches.
Definition recordingUnit.cpp:133
Abstract interface providing basic read and write facilities to a repository.
Definition repositoryIf.hpp:50
RAII wrapper class used to manage the life-time of individual subscriptions.
Definition repositorySubscriberIf.hpp:63
Abstract interface providing I/O and additional subscription facilities for a repository.
Definition repositorySubscriberIf.hpp:26
Container class that holds services of any type.
Definition serviceContainer.hpp:38
Header file for ComponentMetricsIf.
Provides an abstract DataRecorder class as the output stage for a recording unit.
Provides macros and utilities for exception handling.
FitsRecorder allows to write ColumnData to into fits files in a specified directory.
Definition commandReplier.cpp:21
DataPointRecordingSource
Definition dataPointRecordingUnit.hpp:40
@ RUNTIMEREPO
Definition dataPointRecordingUnit.hpp:40
@ OLDB
Definition dataPointRecordingUnit.hpp:40
AsSpanT< T > ToSpan(T &data)
Simple function that converts types that are convertible to spans to a span.
Definition recordingUtils.hpp:24
constexpr bool IS_SPAN_CONVERTIBLE
Small helper alias for IsSpanConvertible.
Definition recordingTypeTraits.hpp:65
Definition ddsSub.hpp:155
FitsRecorder allows to write ColumnData to into fits files in a specified directory.
Abstract base class defining functionality common to all recording units.
A container that can hold any type of service.
Gets the span type for converting type T to a span.
Definition recordingTypeTraits.hpp:27