RTC Toolkit 5.1.0
Loading...
Searching...
No Matches
dataPointRecordingUnit.hpp
Go to the documentation of this file.
1
12#ifndef RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
13#define RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
14
15#include <memory>
23#include <taiclock/taiClock.hpp>
24
25#include <fmt/format.h>
26#include <numapp/numapolicies.hpp>
27#include <numapp/thread.hpp>
28
29#include <cstdint>
30#include <exception>
31#include <string>
32#include <string_view>
33#include <thread>
34#include <typeinfo>
35#include <vector>
36
38
39using namespace std::string_view_literals;
40
42
48template <typename DpType>
50public:
51 // we are using a bit-mask to configure when to capture data
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,
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));
105 }
107
108 auto capture_mask_path =
109 DataPointPath(fmt::format(RTR_PATH_CAPTURE_MASK, comp_id, unit_id));
111 m_capture_mask = m_rtr.GetDataPoint<int32_t>(capture_mask_path);
112 } else {
114 }
115
116 m_samples_written_reg = m_metrics.AddCounter(
117 &m_samples_written, CounterMetricInfo(unit_id + "/samples_written", "Samples written"));
118 Update();
119 }
120
122 m_stop = true;
123 if (m_process_thread.joinable()) {
124 m_process_thread.join();
125 }
126 SetStopped();
127 }
132 void Prepare(const std::filesystem::path& file_path) override {
135 "Error in transition to PREPARING, DataPointRecordingUnit not in STOPPED State");
136
137 m_file_path = file_path / (GetId() + m_output->DefaultFileExtension());
138
139 if (not m_repository->DataPointExists(m_dp_path)) {
140 SetFailed(nullptr);
141 CII_THROW(InvalidSetting, "DataPoint does not exist");
142 }
143
144 if (m_capture_mask == 0) {
145 SetFailed(nullptr);
146 CII_THROW(InvalidSetting, "Invalid capture mask 0");
147 }
148
150 FitsRecorderType* fits_output = dynamic_cast<FitsRecorderType*>(m_output.get());
151 if (fits_output != nullptr) {
152 auto rec_length =
153 m_recording_length.value_or(m_repository->GetDataPointSize(m_dp_path));
154 fits_output->SetColumnLength(1, rec_length);
155 }
156
157 auto policies = numapp::NumaPolicies();
158 m_process_thread =
159 numapp::MakeThread(m_unit_id.substr(0, 15), policies, [&]() { return Process(); });
160 }
164 void Start() override {
165 m_start = true;
166 }
171 std::vector<std::filesystem::path> Stop() override {
172 m_stop = true;
173 if (m_process_thread.joinable()) {
174 m_process_thread.join();
175 }
176 std::vector<std::filesystem::path> files;
177 if (m_file_path) {
178 files.push_back(*m_file_path);
179 }
180 m_file_path.reset();
181 SetStopped();
182 return files;
183 }
184
185 static constexpr typename OutputStageType::ColumnDescription COLUMNS =
186 typename OutputStageType::ColumnDescription{{{"timestamp"sv, ""sv}, {"payload"sv, ""sv}}};
187
188private:
189 void Process() {
190 using namespace std::chrono_literals;
191
192 try {
193 m_output->Open(*m_file_path);
194 m_samples_written.Store(0);
196
197 if (m_capture_mask & CAPTURE_ON_CHANGE) {
198 subscription = std::move(m_repository_subscriber->Subscribe<DpType>(
199 m_dp_path,
200 [this](auto& path, auto& value, auto& metadata) {
201 if (GetState() == State::RUNNING) {
202 try {
203 m_output->Write(AsTuple(value));
204 m_samples_written++;
205 } catch (...) {
206 SetFailed(std::current_exception());
207 return;
208 }
209 }
210 },
211 // NOLINTNEXTLINE(performance-unnecessary-value-param)
212 [this](std::exception_ptr error) {
213 if (error) {
214 std::rethrow_exception(error);
215 }
216 }));
217 }
218
221 "Error in transition to IDLE, DataPointRecordingUnit not in PREPARING State");
222
223 while (m_stop == false) {
224 switch (GetState()) {
225 case State::IDLE:
226 if (m_start) {
229 "Error in transition to WAITING, DataPointRecordingUnit not in "
230 "IDLE State");
231 break;
232 }
233 std::this_thread::sleep_for(1ms);
234 break;
235 case State::WAITING:
237 if (m_capture_mask & CAPTURE_ON_START) {
238 m_repository->ReadDataPoint(m_dp_path, m_dp_buffer);
239 m_output->Write(AsTuple(m_dp_buffer));
240 m_samples_written++;
241 }
242
245 "Error in transition to RUNNING, DataPointRecordingUnit not in "
246 "WAITING State");
247 break;
248 }
249 std::this_thread::sleep_for(1ms);
250 break;
251 case State::RUNNING:
255 "Error in transition to FINISHED, DataPointRecordingUnit not in "
256 "RUNNING State");
257 break;
258 }
259 std::this_thread::sleep_for(1ms);
260 break;
261 default:
262 std::this_thread::sleep_for(1ms);
263 }
264 }
265
266 if (m_capture_mask & CAPTURE_ON_CHANGE) {
267 subscription.Unsubscribe();
268 }
269
270 if (m_capture_mask & CAPTURE_ON_STOP) {
271 m_repository->ReadDataPoint(m_dp_path, m_dp_buffer);
272 m_output->Write(AsTuple(m_dp_buffer));
273 m_samples_written++;
274 }
275
276 m_output->Close();
277 // State is set to stopped after join in Stop function
278 m_start = false;
279 m_stop = false;
281
282 } catch (...) {
283 m_output->Close();
284 m_start = false;
285 m_stop = false;
286 SetFailed(std::current_exception());
288 }
289 }
290
291 static std::tuple<TimepointType, OutputDpType> AsTuple(const DpType& data) {
292 auto ts = taiclock::TaiClock::now().time_since_epoch().count();
293 if constexpr (IS_SPAN_CONVERTIBLE<DpType>) {
294 return std::make_tuple(ts, ToSpan(data));
295 } else {
296 return std::make_tuple(ts, data);
297 }
298 }
299
300 std::optional<std::filesystem::path> m_file_path;
301
302 DataPointPath m_dp_path;
303
304 DataPointRecordingSource m_recording_source;
305
306 RepositoryIf* m_repository;
307 RepositorySubscriberIf* m_repository_subscriber;
308
309 DpType m_dp_buffer;
310
311 CaptureMask m_capture_mask;
312
313 std::unique_ptr<OutputStageType> m_output;
314
315 std::optional<size_t> m_recording_length;
316
317 std::atomic<bool> m_start = false;
318 std::atomic<bool> m_stop = false;
319 std::thread m_process_thread;
320
321 perfc::CounterI64 m_samples_written;
322 perfc::ScopedRegistration m_samples_written_reg;
323
327 inline static constexpr std::string_view RTR_PATH_CAPTURE_MASK =
328 "/{}/static/rec_units/{}/capture_mask";
332 inline static constexpr std::string_view OLDB_PATH_DP_NAME = "/{}/rec_units/{}/dp_name";
333};
334
335} // namespace rtctk::componentFramework
336
337#endif // RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
virtual perfc::ScopedRegistration AddCounter(CounterVariant counter, CounterMetricInfo info)=0
Add a counter to be included in component metrics, identified by its address, together with info to t...
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:74
Recording Unit that can record datapoints.
Definition dataPointRecordingUnit.hpp:49
static constexpr uint32_t CAPTURE_ON_START
Definition dataPointRecordingUnit.hpp:53
static constexpr OutputStageType::ColumnDescription COLUMNS
Definition dataPointRecordingUnit.hpp:185
std::vector< std::filesystem::path > Stop() override
Stop the recording and wait for it's termination.
Definition dataPointRecordingUnit.hpp:171
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:132
virtual ~DataPointRecordingUnit()
Definition dataPointRecordingUnit.hpp:121
taiclock::TaiClock::time_point::rep TimepointType
Definition dataPointRecordingUnit.hpp:57
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:164
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:29
const std::array< ColumnMetaData, sizeof...(T)> ColumnDescription
Definition dataRecorder.hpp:49
Definition fitsDataRecorder.hpp:71
This Exception is raised when a invalid setting was used in the runtime repo.
Definition exceptions.hpp:338
Abstract base class for all sources that can be recorded by the MetadataCollector and TelemetryRecord...
Definition recordingUnit.hpp:51
bool HasLeaders()
Check if this unit is following any leaders.
Definition recordingUnit.cpp:97
OldbIf & m_oldb
Definition recordingUnit.hpp:173
bool HasLastLeaderFinished()
This function is used to determine if this unit should stop recording when waiting for leaders.
Definition recordingUnit.cpp:106
bool HasFirstLeaderStarted()
This function is used to determine if this unit should start recording when waiting for leaders.
Definition recordingUnit.cpp:101
virtual void Update()
Update dynamic settings.
Definition recordingUnit.cpp:166
void SetFailed(const std::exception_ptr &exception)
Set the unit into failed state, with the given exception.
Definition recordingUnit.cpp:142
std::string GetId()
Get the unit_it of this RecordingUnit.
Definition recordingUnit.cpp:120
std::string m_unit_id
Definition recordingUnit.hpp:171
void ResetLeaderStates()
Definition recordingUnit.cpp:111
ComponentMetricsIf & m_metrics
Definition recordingUnit.hpp:174
RuntimeRepoIf & m_rtr
Definition recordingUnit.hpp:172
void SetStopped()
Set the Unit state to STOPPED independent of the current State.
Definition recordingUnit.cpp:149
State GetState()
Get the current state of the Recording Unit.
Definition recordingUnit.cpp:154
bool SetState(State state, State precondition)
Sets the new state, only goes to new state, if expected state matches.
Definition recordingUnit.cpp:124
T GetDataPoint(const DataPointPath &path) const
Fetches a datapoint from the repository.
Definition repositoryIf.ipp:1711
size_t GetDataPointSize(const DataPointPath &path) const
Fetches the size of the datapoint's data.
Definition repositoryIf.cpp:397
void CreateDataPoint(const DataPointPath &path)
Creates a new datapoint in the repository.
Definition repositoryIf.ipp:1696
void SetDataPoint(const DataPointPath &path, const T &value)
Sets a datapoint in the repository.
Definition repositoryIf.ipp:1720
void ReadDataPoint(const DataPointPath &path, T &buffer) const
Reads a datapoint from the repository.
Definition repositoryIf.ipp:1727
bool DataPointExists(const DataPointPath &path) const
Checks for the existence of a datapoint in the repository.
Definition repositoryIf.cpp:461
RAII wrapper class used to manage the life-time of individual subscriptions.
Definition repositorySubscriberIf.hpp:64
Container class that holds services of any type.
Definition serviceContainer.hpp:39
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:22
DataPointRecordingSource
Definition dataPointRecordingUnit.hpp:41
elt::mal::future< std::string > InjectReqRepEvent(StateMachineEngine &engine)
Definition malEventInjector.hpp:23
AsSpanT< T > ToSpan(T &data)
Simple function that converts types that are convertible to spans to a span.
Definition recordingUtils.hpp:25
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:28