12#ifndef RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
13#define RTCTK_COMPONENTFRAMEWORK_DATAPOINTRECORDINGUNIT_HPP
23#include <taiclock/taiClock.hpp>
25#include <fmt/format.h>
26#include <numapp/numapolicies.hpp>
27#include <numapp/thread.hpp>
39using namespace std::string_view_literals;
48template <
typename DpType>
73 const std::string& unit_id,
77 std::unique_ptr<OutputStageType>&& output_stage = {},
78 std::optional<size_t> fixed_recording_length = std::nullopt)
81 , m_recording_source{source}
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);
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);
96 CII_THROW(InvalidSetting,
"Invalid recording source");
98 if (not m_repository or not m_repository_subscriber) {
99 CII_THROW(InvalidSetting,
"Invalid recording source");
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);
106 m_oldb.SetDataPoint<std::string>(input_dp_path, dp_path);
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);
113 m_capture_mask = CAPTURE_ON_START + CAPTURE_ON_CHANGE + CAPTURE_ON_STOP;
116 const InfluxTagMap base_tags = {
120 m_samples_written_reg = m_metrics.AddCounter(
121 &m_samples_written, CounterMetricInfo(
122 unit_id +
"/samples_written",
132 if (m_process_thread.joinable()) {
133 m_process_thread.join();
141 void Prepare(
const std::filesystem::path& file_path)
override {
148 "Error in transition to PREPARING, DataPointRecordingUnit not in STOPPED State");
150 m_file_path = file_path / (
GetId() + m_output->DefaultFileExtension());
152 if (not m_repository->DataPointExists(m_dp_path)) {
157 if (m_capture_mask == 0) {
163 FitsRecorderType* fits_output =
dynamic_cast<FitsRecorderType*
>(m_output.get());
164 if (fits_output !=
nullptr) {
166 m_recording_length.value_or(m_repository->GetDataPointSize(m_dp_path));
167 fits_output->SetColumnLength(1, rec_length);
170 auto policies = numapp::NumaPolicies();
172 numapp::MakeThread(
m_unit_id.substr(0, 15), policies, [&]() { return Process(); });
184 std::vector<std::filesystem::path>
Stop()
override {
186 if (m_process_thread.joinable()) {
187 m_process_thread.join();
189 std::vector<std::filesystem::path> files;
191 files.push_back(*m_file_path);
203 using namespace std::chrono_literals;
206 m_output->Open(*m_file_path);
207 m_samples_written.Store(0);
210 if (m_capture_mask & CAPTURE_ON_CHANGE) {
211 subscription = std::move(m_repository_subscriber->Subscribe<DpType>(
213 [
this](
auto& path,
auto& value,
auto& metadata) {
214 if (GetState() == State::RUNNING) {
216 m_output->Write(AsTuple(value));
219 SetFailed(std::current_exception());
225 [
this](std::exception_ptr error) {
227 std::rethrow_exception(error);
232 SetState(State::IDLE,
234 "Error in transition to IDLE, DataPointRecordingUnit not in PREPARING State");
236 while (m_stop ==
false) {
237 switch (GetState()) {
240 SetState(State::WAITING,
242 "Error in transition to WAITING, DataPointRecordingUnit not in "
246 std::this_thread::sleep_for(1ms);
249 if (not HasLeaders() or (HasLeaders() and HasFirstLeaderStarted())) {
250 if (m_capture_mask & CAPTURE_ON_START) {
251 m_repository->ReadDataPoint(m_dp_path, m_dp_buffer);
252 m_output->Write(AsTuple(m_dp_buffer));
256 SetState(State::RUNNING,
258 "Error in transition to RUNNING, DataPointRecordingUnit not in "
262 std::this_thread::sleep_for(1ms);
265 if (HasLeaders() and HasLastLeaderFinished()) {
266 SetState(State::FINISHED,
268 "Error in transition to FINISHED, DataPointRecordingUnit not in "
272 std::this_thread::sleep_for(1ms);
275 std::this_thread::sleep_for(1ms);
279 if (m_capture_mask & CAPTURE_ON_CHANGE) {
280 subscription.Unsubscribe();
283 if (m_capture_mask & CAPTURE_ON_STOP) {
284 m_repository->ReadDataPoint(m_dp_path, m_dp_buffer);
285 m_output->Write(AsTuple(m_dp_buffer));
299 SetFailed(std::current_exception());
304 static std::tuple<TimepointType, OutputDpType> AsTuple(
const DpType& data) {
305 auto ts = taiclock::TaiClock::now().time_since_epoch().count();
307 return std::make_tuple(ts,
ToSpan(data));
309 return std::make_tuple(ts, data);
313 std::optional<std::filesystem::path> m_file_path;
324 CaptureMask m_capture_mask;
326 std::unique_ptr<OutputStageType> m_output;
328 std::optional<size_t> m_recording_length;
330 std::atomic<bool> m_start =
false;
331 std::atomic<bool> m_stop =
false;
332 std::thread m_process_thread;
334 perfc::CounterI64 m_samples_written;
335 perfc::ScopedRegistration m_samples_written_reg;
340 inline static constexpr std::string_view RTR_PATH_CAPTURE_MASK =
341 "/{}/static/rec_units/{}/capture_mask";
345 inline static constexpr std::string_view OLDB_PATH_DP_NAME =
"/{}/rec_units/{}/dp_name";
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:77
static constexpr uint32_t CAPTURE_ON_START
Definition dataPointRecordingUnit.hpp:53
static constexpr OutputStageType::ColumnDescription COLUMNS
Definition dataPointRecordingUnit.hpp:198
std::vector< std::filesystem::path > Stop() override
Stop the recording and wait for it's termination.
Definition dataPointRecordingUnit.hpp:184
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:141
taiclock::TaiClock::time_point::rep TimepointType
Definition dataPointRecordingUnit.hpp:57
~DataPointRecordingUnit() override
Definition dataPointRecordingUnit.hpp:130
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:177
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:340
Abstract base class for all sources that can be recorded by the MetadataCollector and TelemetryRecord...
Definition recordingUnit.hpp:51
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
void SetFailed(const std::exception_ptr &exception)
Set the unit into failed state, with the given exception.
Definition recordingUnit.cpp:150
std::string GetId()
Get the unit_it of this RecordingUnit.
Definition recordingUnit.cpp:128
std::string m_unit_id
Definition recordingUnit.hpp:176
void SetStopped()
Set the Unit state to STOPPED independent of the current State.
Definition recordingUnit.cpp:157
@ STOPPED
Definition recordingUnit.hpp:53
@ PREPARING
Definition recordingUnit.hpp:53
bool SetState(State state, State precondition)
Sets the new state, only goes to new state, if expected state matches.
Definition recordingUnit.cpp:132
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
RAII wrapper class used to manage the life-time of individual subscriptions.
Definition repositorySubscriberIf.hpp:64
Abstract interface providing I/O and additional subscription facilities for a repository.
Definition repositorySubscriberIf.hpp:27
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
@ RUNTIMEREPO
Definition dataPointRecordingUnit.hpp:41
@ OLDB
Definition dataPointRecordingUnit.hpp:41
AsSpanT< T > ToSpan(T &data)
Simple function that converts types that are convertible to spans to a span.
Definition recordingUtils.hpp:25
constexpr bool IS_SPAN_CONVERTIBLE
Small helper alias for IsSpanConvertible.
Definition recordingTypeTraits.hpp:66
Definition ddsSub.hpp:156
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