2 * SPDX-License-Identifier: MIT
4 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * Babeltrace CTF file system Reader Component queries
9 #define BT_CLOG_CFG logCfg
10 #define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/QUERY"
15 #include <glib/gstdio.h>
17 #include <sys/types.h>
19 #include "common/assert.h"
20 #include "metadata.hpp"
21 #include "../common/src/metadata/tsdl/metadata-stream-decoder.hpp"
22 #include "../common/src/metadata/metadata-stream-parser-utils.hpp"
23 #include "common/common.h"
24 #include "common/macros.h"
25 #include "plugins/common/param-validation/param-validation.h"
26 #include <babeltrace2/babeltrace.h>
28 #include "cpp-common/cfg-logging-error-reporting.hpp"
29 #include "cpp-common/cfg-logging-error-reporting-throw.hpp"
30 #include "cpp-common/libc-up.hpp"
31 #include "cpp-common/exc.hpp"
32 #include "cpp-common/file-utils.hpp"
33 #include "cpp-common/make-unique.hpp"
35 #define METADATA_TEXT_SIG "/* CTF 1.8"
44 static struct bt_param_validation_map_value_entry_descr metadataInfoQueryParamsDesc
[] = {
45 {"path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY
,
46 bt_param_validation_value_descr::makeString()},
47 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
};
50 bt2::Value::Shared
metadata_info_query(bt2::ConstMapValue params
, const bt2_common::LogCfg
& logCfg
)
52 gchar
*validateError
= NULL
;
53 auto validationStatus
= bt_param_validation_validate(
54 params
.libObjPtr(), metadataInfoQueryParamsDesc
, &validateError
);
56 if (validationStatus
== BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR
) {
57 throw bt2_common::MemoryError
{};
58 } else if (validationStatus
== BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR
) {
59 const std::string error
{validateError
};
61 g_free(validateError
);
62 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error
, "%s", error
.data());
65 const auto path
= params
["path"]->asString().value();
69 bt2_common::dataFromFile(std::string
{path
.to_string() + "/metadata"}.c_str());
71 ctf::src::MetadataStreamDecoder decoder
{logCfg
};
74 decoder
.decode(buffer
.data(), bt2_common::DataLen::fromBytes(buffer
.size()));
76 auto result
= bt2::MapValue::create();
78 * If the metadata does not already start with the plaintext metadata
79 * signature, prepend it.
81 if (plainText
.rfind(METADATA_TEXT_SIG
, 0) != 0) {
82 plainText
.insert(0, std::string
{METADATA_TEXT_SIG
} + " */\n\n");
85 result
->insert("text", plainText
.data());
87 result
->insert("is-packetized", decoder
.pktInfo().has_value());
89 } catch (const bt2_common::Error
&) {
90 BT_CLOGE_APPEND_CAUSE_AND_RETHROW("Error getting plaintext metadata section from file");
94 static void add_range(bt2::MapValue info
, struct range
*range
, const char *range_name
)
101 bt2::MapValue rangeMap
= info
.insertEmptyMap(range_name
);
102 rangeMap
.insert("begin", range
->begin_ns
);
103 rangeMap
.insert("end", range
->end_ns
);
106 static void populate_stream_info(struct ctf_fs_ds_file_group
*group
, bt2::MapValue groupInfo
,
107 struct range
*stream_range
, const bt2_common::LogCfg
& logCfg
)
110 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
111 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
112 * the timestamp_begin of the first index entry and the timestamp_end
113 * of the last index entry.
115 BT_ASSERT(!group
->index
.entries
.empty());
118 const ctf_fs_ds_index_entry
& first_ds_index_entry
= group
->index
.entries
.front();
121 const ctf_fs_ds_index_entry
& last_ds_index_entry
= group
->index
.entries
.back();
123 stream_range
->begin_ns
= first_ds_index_entry
.timestamp_begin_ns
;
124 stream_range
->end_ns
= last_ds_index_entry
.timestamp_end_ns
;
127 * If any of the begin and end timestamps is not set it means that
128 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
129 * in their packet context so we can't set the range.
132 stream_range
->begin_ns
!= UINT64_C(-1) && stream_range
->end_ns
!= UINT64_C(-1);
134 add_range(groupInfo
, stream_range
, "range-ns");
136 std::string portName
= ctf_fs_make_port_name(group
);
137 groupInfo
.insert("port-name", portName
.c_str());
140 static void populate_trace_info(const struct ctf_fs_trace
*trace
, bt2::MapValue traceInfo
,
141 const bt2_common::LogCfg
& logCfg
)
143 /* Add trace range info only if it contains streams. */
144 if (trace
->ds_file_groups
.empty()) {
145 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error
, "Trace has no streams: trace-path=%s",
146 trace
->path
.c_str());
149 bt2::ArrayValue fileGroups
= traceInfo
.insertEmptyArray("stream-infos");
151 /* Find range of all stream groups, and of the trace. */
152 for (const ctf_fs_ds_file_group::UP
& group
: trace
->ds_file_groups
) {
154 bt2::MapValue groupInfo
= fileGroups
.appendEmptyMap();
155 populate_stream_info(group
.get(), groupInfo
, &group_range
, logCfg
);
160 bt2::Value::Shared
trace_infos_query(bt2::ConstMapValue params
, const bt2_common::LogCfg
& logCfg
)
162 ctf::src::fs::Parameters parameters
= read_src_fs_parameters(params
, logCfg
);
163 ctf_fs_component::UP ctf_fs
=
164 bt2_common::makeUnique
<ctf_fs_component
>(parameters
.clkClsCfg
, logCfg
);
166 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs
.get(), parameters
.inputs
, parameters
.traceName
,
168 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error
, "Failed to create trace");
171 bt2::ArrayValue::Shared result
= bt2::ArrayValue::create();
172 bt2::MapValue traceInfo
= result
->appendEmptyMap();
173 populate_trace_info(ctf_fs
->trace
.get(), traceInfo
, logCfg
);
178 static struct bt_param_validation_map_value_entry_descr supportInfoQueryParamsDesc
[] = {
179 {"type", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY
,
180 bt_param_validation_value_descr::makeString()},
181 {"input", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY
,
182 bt_param_validation_value_descr::makeString()},
183 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
};
186 bt2::Value::Shared
support_info_query(bt2::ConstMapValue params
, const bt2_common::LogCfg
& logCfg
)
188 gchar
*validateError
= NULL
;
189 auto validationStatus
= bt_param_validation_validate(
190 params
.libObjPtr(), supportInfoQueryParamsDesc
, &validateError
);
192 if (validationStatus
== BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR
) {
193 throw bt2_common::MemoryError
{};
194 } else if (validationStatus
== BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR
) {
195 const std::string error
{validateError
};
197 g_free(validateError
);
198 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error
, "%s", error
.data());
201 bpstd::string_view type
= params
["type"]->asString().value();
203 if (type
!= "directory") {
205 * The input type is not a directory so we are 100% sure it's not a CTF
206 * 1.8 trace as it would need a directory with at least 1 metadata file
207 * and 1 data stream file.
209 bt2::MapValue::Shared result
= bt2::MapValue::create();
210 result
->insert("weight", 0.0f
);
214 bpstd::string_view input
= params
["input"]->asString().value();
216 auto result
= bt2::MapValue::create();
219 bt2_common::dataFromFile(std::string
{input
.to_string() + "/metadata"}.c_str());
220 ctf::src::MetadataStreamParser::ParseRet parseRet
= ctf::src::parseMetadataStream(
221 {}, nullptr, buffer
.data(), buffer
.data() + buffer
.size(), logCfg
);
222 ctf::src::TraceCls
*ctfTraceCls
= parseRet
.first
.get();
223 BT_ASSERT(ctfTraceCls
);
226 * We were able to parse the metadata file, so we are confident it's a
229 result
->insert("weight", 0.75);
230 if (ctfTraceCls
->uuid()) {
231 result
->insert("group", ctfTraceCls
->uuid()->str());
233 } catch (const bt2_common::NoSuchFileOrDirectoryError
&) {
235 * Failing to find the metadata file is not an error, it simply
236 * indicates that the directory is not a trace. Report appropriate
239 bt_current_thread_clear_error();
240 result
->insert("weight", 0.0);