ce4619ef9a10a7bd538d943b478afa405691b789
[babeltrace.git] / src / plugins / ctf / fs-src / query.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 *
6 * Babeltrace CTF file system Reader Component queries
7 */
8
9 #include <glib.h>
10 #include <glib/gstdio.h>
11 #include <sys/types.h>
12
13 #include <babeltrace2/babeltrace.h>
14
15 #include "cpp-common/bt2/exc.hpp"
16 #include "cpp-common/bt2c/libc-up.hpp"
17
18 #include "../common/src/metadata/tsdl/decoder.hpp"
19 #include "fs.hpp"
20 #include "query.hpp"
21
22 #define METADATA_TEXT_SIG "/* CTF 1.8"
23
24 struct range
25 {
26 int64_t begin_ns = 0;
27 int64_t end_ns = 0;
28 bool set = false;
29 };
30
31 bt2::Value::Shared metadata_info_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
32 {
33 const auto pathValue = params["path"];
34 if (!pathValue) {
35 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
36 "Mandatory `path` parameter missing");
37 }
38
39 if (!pathValue->isString()) {
40 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
41 "`path` parameter is required to be a string value");
42 }
43
44 const auto path = pathValue->asString().value();
45 bt2c::FileUP metadataFp {ctf_fs_metadata_open_file(path, logger)};
46 if (!metadataFp) {
47 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
48 "Cannot open trace metadata: path=\"{}\".", path);
49 }
50
51 bool is_packetized;
52 int bo;
53 int ret = ctf_metadata_decoder_is_packetized(metadataFp.get(), &is_packetized, &bo, logger);
54
55 if (ret) {
56 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
57 logger, bt2::Error,
58 "Cannot check whether or not the metadata stream is packetized: path=\"{}\".", path);
59 }
60
61 ctf_metadata_decoder_config decoder_cfg {logger};
62 decoder_cfg.keep_plain_text = true;
63 ctf_metadata_decoder_up decoder = ctf_metadata_decoder_create(&decoder_cfg);
64 if (!decoder) {
65 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
66 logger, bt2::Error, "Cannot create metadata decoder: path=\"{}}\".", path);
67 }
68
69 rewind(metadataFp.get());
70 ctf_metadata_decoder_status decoder_status =
71 ctf_metadata_decoder_append_content(decoder.get(), metadataFp.get());
72 if (decoder_status) {
73 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
74 logger, bt2::Error, "Cannot update metadata decoder's content: path=\"{}\".", path);
75 }
76
77 const char *plain_text = ctf_metadata_decoder_get_text(decoder.get());
78 std::string metadata_text;
79
80 if (strncmp(plain_text, METADATA_TEXT_SIG, sizeof(METADATA_TEXT_SIG) - 1) != 0) {
81 metadata_text = METADATA_TEXT_SIG;
82 metadata_text += " */\n\n";
83 }
84
85 metadata_text += plain_text;
86
87 const auto result = bt2::MapValue::create();
88 result->insert("text", metadata_text);
89 result->insert("is-packetized", is_packetized);
90
91 return result;
92 }
93
94 static void add_range(const bt2::MapValue info, struct range *range, const char *range_name)
95 {
96 if (!range->set) {
97 /* Not an error. */
98 return;
99 }
100
101 const auto rangeMap = info.insertEmptyMap(range_name);
102 rangeMap.insert("begin", range->begin_ns);
103 rangeMap.insert("end", range->end_ns);
104 }
105
106 static void populate_stream_info(struct ctf_fs_ds_file_group *group, const bt2::MapValue groupInfo,
107 struct range *stream_range, const bt2c::Logger& logger)
108 {
109 /*
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.
114 */
115 BT_ASSERT(group->index);
116 BT_ASSERT(group->index->entries);
117 BT_ASSERT(group->index->entries->len > 0);
118
119 /* First entry. */
120 ctf_fs_ds_index_entry *first_ds_index_entry =
121 (struct ctf_fs_ds_index_entry *) g_ptr_array_index(group->index->entries, 0);
122
123 /* Last entry. */
124 ctf_fs_ds_index_entry *last_ds_index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(
125 group->index->entries, group->index->entries->len - 1);
126
127 stream_range->begin_ns = first_ds_index_entry->timestamp_begin_ns;
128 stream_range->end_ns = last_ds_index_entry->timestamp_end_ns;
129
130 /*
131 * If any of the begin and end timestamps is not set it means that
132 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
133 * in their packet context so we can't set the range.
134 */
135 stream_range->set =
136 stream_range->begin_ns != UINT64_C(-1) && stream_range->end_ns != UINT64_C(-1);
137
138 add_range(groupInfo, stream_range, "range-ns");
139
140 bt2c::GCharUP portName = ctf_fs_make_port_name(group);
141 if (!portName) {
142 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "Failed to make port name");
143 }
144
145 groupInfo.insert("port-name", portName.get());
146 }
147
148 static void populate_trace_info(const struct ctf_fs_trace *trace, const bt2::MapValue traceInfo,
149 const bt2c::Logger& logger)
150 {
151 BT_ASSERT(trace->ds_file_groups);
152 /* Add trace range info only if it contains streams. */
153 if (trace->ds_file_groups->len == 0) {
154 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
155 logger, bt2::Error, "Trace has no streams: trace-path={}", trace->path->str);
156 }
157
158 const auto fileGroups = traceInfo.insertEmptyArray("stream-infos");
159
160 /* Find range of all stream groups, and of the trace. */
161 for (size_t group_idx = 0; group_idx < trace->ds_file_groups->len; group_idx++) {
162 range group_range;
163 ctf_fs_ds_file_group *group =
164 (ctf_fs_ds_file_group *) g_ptr_array_index(trace->ds_file_groups, group_idx);
165
166 const auto groupInfo = fileGroups.appendEmptyMap();
167 populate_stream_info(group, groupInfo, &group_range, logger);
168 }
169 }
170
171 bt2::Value::Shared trace_infos_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
172 {
173 ctf_fs_component::UP ctf_fs = ctf_fs_component_create(logger);
174 if (!ctf_fs) {
175 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
176 "Cannot create ctf_fs_component");
177 }
178
179 const bt_value *inputs_value = NULL;
180 const bt_value *trace_name_value;
181
182 if (!read_src_fs_parameters(params.libObjPtr(), &inputs_value, &trace_name_value,
183 ctf_fs.get())) {
184 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "Failed to read parameters");
185 }
186
187 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs.get(), inputs_value, trace_name_value, NULL)) {
188 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "Failed to create trace");
189 }
190
191 const auto result = bt2::ArrayValue::create();
192 const auto traceInfo = result->appendEmptyMap();
193 populate_trace_info(ctf_fs->trace, traceInfo, logger);
194
195 return result;
196 }
197
198 bt2::Value::Shared support_info_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
199 {
200 const auto typeValue = params["type"];
201 BT_ASSERT(typeValue);
202 BT_ASSERT(typeValue->isString());
203 const auto type = typeValue->asString().value();
204
205 if (strcmp(type, "directory") != 0) {
206 const auto result = bt2::MapValue::create();
207 result->insert("weight", 0.0f);
208 return result;
209 }
210
211 const auto inputValue = params["input"];
212 BT_ASSERT(inputValue);
213 BT_ASSERT(inputValue->isString());
214 const auto input = inputValue->asString().value();
215
216 bt2c::GCharUP metadataPath {g_build_filename(input, CTF_FS_METADATA_FILENAME, NULL)};
217 if (!metadataPath) {
218 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "Failed to read parameters");
219 }
220
221 double weight = 0;
222 char uuid_str[BT_UUID_STR_LEN + 1];
223 bool has_uuid = false;
224 bt2c::FileUP metadataFile {g_fopen(metadataPath.get(), "rb")};
225 if (metadataFile) {
226 enum ctf_metadata_decoder_status decoder_status;
227 bt_uuid_t uuid;
228
229 ctf_metadata_decoder_config metadata_decoder_config {logger};
230
231 ctf_metadata_decoder_up metadata_decoder =
232 ctf_metadata_decoder_create(&metadata_decoder_config);
233 if (!metadata_decoder) {
234 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
235 "Failed to create metadata decoder");
236 }
237
238 decoder_status =
239 ctf_metadata_decoder_append_content(metadata_decoder.get(), metadataFile.get());
240 if (decoder_status != CTF_METADATA_DECODER_STATUS_OK) {
241 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
242 logger, bt2::Error, "Failed to append metadata content: metadata-decoder-status={}",
243 decoder_status);
244 }
245
246 /*
247 * We were able to parse the metadata file, so we are
248 * confident it's a CTF trace.
249 */
250 weight = 0.75;
251
252 /* If the trace has a UUID, return the stringified UUID as the group. */
253 if (ctf_metadata_decoder_get_trace_class_uuid(metadata_decoder.get(), uuid) == 0) {
254 bt_uuid_to_str(uuid, uuid_str);
255 has_uuid = true;
256 }
257 }
258
259 const auto result = bt2::MapValue::create();
260 result->insert("weight", weight);
261
262 /* We are not supposed to have weight == 0 and a UUID. */
263 BT_ASSERT(weight > 0 || !has_uuid);
264
265 if (weight > 0 && has_uuid) {
266 result->insert("group", uuid_str);
267 }
268
269 return result;
270 }
This page took 0.043922 seconds and 3 git commands to generate.