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_LOG_OUTPUT_LEVEL log_level
10 #define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/QUERY"
11 #include "logging/log.h"
16 #include <glib/gstdio.h>
18 #include <sys/types.h>
20 #include "common/assert.h"
22 #include "../common/metadata/decoder.h"
23 #include "common/common.h"
24 #include "common/macros.h"
25 #include <babeltrace2/babeltrace.h>
27 #include "logging/comp-logging.h"
29 #define METADATA_TEXT_SIG "/* CTF 1.8"
38 bt_component_class_query_method_status
metadata_info_query(
39 bt_self_component_class_source
*self_comp_class_src
,
40 const bt_value
*params
, bt_logging_level log_level
,
41 const bt_value
**user_result
)
43 bt_component_class_query_method_status status
=
44 BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
45 bt_self_component_class
*self_comp_class
=
46 bt_self_component_class_source_as_self_component_class(self_comp_class_src
);
47 bt_value
*result
= NULL
;
48 const bt_value
*path_value
= NULL
;
49 FILE *metadata_fp
= NULL
;
54 struct ctf_metadata_decoder
*decoder
= NULL
;
55 struct ctf_metadata_decoder_config decoder_cfg
= { 0 };
56 enum ctf_metadata_decoder_status decoder_status
;
58 result
= bt_value_map_create();
60 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
66 if (!bt_value_is_map(params
)) {
67 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
68 "Query parameters is not a map value object.");
69 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
73 path_value
= bt_value_map_borrow_entry_value_const(params
, "path");
75 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
76 "Mandatory `path` parameter missing");
77 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
81 if (!bt_value_is_string(path_value
)) {
82 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
83 "`path` parameter is required to be a string value");
84 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
88 path
= bt_value_string_get(path_value
);
91 metadata_fp
= ctf_fs_metadata_open_file(path
);
93 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
94 "Cannot open trace metadata: path=\"%s\".", path
);
98 ret
= ctf_metadata_decoder_is_packetized(metadata_fp
, &is_packetized
,
99 &bo
, log_level
, NULL
);
101 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
102 "Cannot check whether or not the metadata stream is packetized: path=\"%s\".",
107 decoder_cfg
.log_level
= log_level
;
108 decoder_cfg
.self_comp_class
= self_comp_class
;
109 decoder_cfg
.keep_plain_text
= true;
110 decoder
= ctf_metadata_decoder_create(&decoder_cfg
);
112 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
113 "Cannot create metadata decoder: path=\"%s\".", path
);
118 decoder_status
= ctf_metadata_decoder_append_content(decoder
,
120 if (decoder_status
) {
121 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
122 "Cannot update metadata decoder's content: path=\"%s\".",
127 ret
= bt_value_map_insert_string_entry(result
, "text",
128 ctf_metadata_decoder_get_text(decoder
));
130 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
131 "Cannot insert metadata text into query result.");
135 ret
= bt_value_map_insert_bool_entry(result
, "is-packetized",
138 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
139 "Cannot insert \"is-packetized\" attribute into query result.");
146 BT_VALUE_PUT_REF_AND_RESET(result
);
150 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
154 ctf_metadata_decoder_destroy(decoder
);
157 ret
= fclose(metadata_fp
);
159 BT_LOGE_ERRNO("Cannot close metatada file stream",
160 ": path=\"%s\"", path
);
164 *user_result
= result
;
169 int add_range(bt_value
*info
, struct range
*range
,
170 const char *range_name
)
173 bt_value_map_insert_entry_status status
;
181 status
= bt_value_map_insert_empty_map_entry(info
, range_name
,
183 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
188 status
= bt_value_map_insert_signed_integer_entry(range_map
, "begin",
190 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
195 status
= bt_value_map_insert_signed_integer_entry(range_map
, "end",
197 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
207 int populate_stream_info(struct ctf_fs_ds_file_group
*group
,
208 bt_value
*group_info
, struct range
*stream_range
)
211 bt_value_map_insert_entry_status insert_status
;
212 struct ctf_fs_ds_index_entry
*first_ds_index_entry
, *last_ds_index_entry
;
213 gchar
*port_name
= NULL
;
216 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
217 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
218 * the timestamp_begin of the first index entry and the timestamp_end
219 * of the last index entry.
221 BT_ASSERT(group
->index
);
222 BT_ASSERT(group
->index
->entries
);
223 BT_ASSERT(group
->index
->entries
->len
> 0);
226 first_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
227 group
->index
->entries
, 0);
230 last_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
231 group
->index
->entries
, group
->index
->entries
->len
- 1);
233 stream_range
->begin_ns
= first_ds_index_entry
->timestamp_begin_ns
;
234 stream_range
->end_ns
= last_ds_index_entry
->timestamp_end_ns
;
237 * If any of the begin and end timestamps is not set it means that
238 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
239 * in their packet context so we can't set the range.
241 stream_range
->set
= stream_range
->begin_ns
!= UINT64_C(-1) &&
242 stream_range
->end_ns
!= UINT64_C(-1);
244 ret
= add_range(group_info
, stream_range
, "range-ns");
249 port_name
= ctf_fs_make_port_name(group
);
255 insert_status
= bt_value_map_insert_string_entry(group_info
,
256 "port-name", port_name
);
257 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
268 int populate_trace_info(const struct ctf_fs_trace
*trace
, bt_value
*trace_info
,
269 bt_logging_level log_level
,
270 bt_self_component_class
*self_comp_class
)
274 bt_value_map_insert_entry_status insert_status
;
275 bt_value_array_append_element_status append_status
;
276 bt_value
*file_groups
= NULL
;
278 BT_ASSERT(trace
->ds_file_groups
);
279 /* Add trace range info only if it contains streams. */
280 if (trace
->ds_file_groups
->len
== 0) {
282 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
283 "Trace has no streams: trace-path=%s", trace
->path
->str
);
287 insert_status
= bt_value_map_insert_empty_array_entry(trace_info
,
288 "stream-infos", &file_groups
);
289 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
294 /* Find range of all stream groups, and of the trace. */
295 for (group_idx
= 0; group_idx
< trace
->ds_file_groups
->len
;
297 bt_value
*group_info
;
298 struct range group_range
= { .set
= false };
299 struct ctf_fs_ds_file_group
*group
= g_ptr_array_index(
300 trace
->ds_file_groups
, group_idx
);
302 append_status
= bt_value_array_append_empty_map_element(
303 file_groups
, &group_info
);
304 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
309 ret
= populate_stream_info(group
, group_info
, &group_range
);
320 bt_component_class_query_method_status
trace_infos_query(
321 bt_self_component_class_source
*self_comp_class_src
,
322 const bt_value
*params
, bt_logging_level log_level
,
323 const bt_value
**user_result
)
325 struct ctf_fs_component
*ctf_fs
= NULL
;
326 bt_component_class_query_method_status status
=
327 BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
328 bt_self_component_class
*self_comp_class
=
329 bt_self_component_class_source_as_self_component_class(
330 self_comp_class_src
);
331 bt_value
*result
= NULL
;
332 const bt_value
*inputs_value
= NULL
;
333 const bt_value
*trace_name_value
;
335 bt_value
*trace_info
= NULL
;
336 bt_value_array_append_element_status append_status
;
340 if (!bt_value_is_map(params
)) {
341 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
342 "Query parameters is not a map value object.");
343 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
347 ctf_fs
= ctf_fs_component_create(log_level
, NULL
);
352 if (!read_src_fs_parameters(params
, &inputs_value
, &trace_name_value
,
353 ctf_fs
, NULL
, self_comp_class
)) {
354 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
358 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs
, inputs_value
,
359 trace_name_value
, NULL
, self_comp_class
)) {
363 result
= bt_value_array_create();
365 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
369 append_status
= bt_value_array_append_empty_map_element(result
,
371 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
372 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
373 "Failed to create trace info map.");
377 ret
= populate_trace_info(ctf_fs
->trace
, trace_info
, log_level
,
386 BT_VALUE_PUT_REF_AND_RESET(result
);
389 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
394 ctf_fs_destroy(ctf_fs
);
398 *user_result
= result
;
403 bt_component_class_query_method_status
support_info_query(
404 bt_self_component_class_source
*comp_class
,
405 const bt_value
*params
, bt_logging_level log_level
,
406 const bt_value
**user_result
)
408 const bt_value
*input_type_value
;
409 const char *input_type
;
410 bt_component_class_query_method_status status
;
411 bt_value_map_insert_entry_status insert_entry_status
;
413 gchar
*metadata_path
= NULL
;
414 bt_value
*result
= NULL
;
415 struct ctf_metadata_decoder
*metadata_decoder
= NULL
;
416 FILE *metadata_file
= NULL
;
417 char uuid_str
[BT_UUID_STR_LEN
+ 1];
418 bool has_uuid
= false;
419 const bt_value
*input_value
;
422 input_type_value
= bt_value_map_borrow_entry_value_const(params
, "type");
423 BT_ASSERT(input_type_value
);
424 BT_ASSERT(bt_value_get_type(input_type_value
) == BT_VALUE_TYPE_STRING
);
425 input_type
= bt_value_string_get(input_type_value
);
427 if (strcmp(input_type
, "directory") != 0) {
431 input_value
= bt_value_map_borrow_entry_value_const(params
, "input");
432 BT_ASSERT(input_value
);
433 BT_ASSERT(bt_value_get_type(input_value
) == BT_VALUE_TYPE_STRING
);
434 input
= bt_value_string_get(input_value
);
436 metadata_path
= g_build_filename(input
, CTF_FS_METADATA_FILENAME
, NULL
);
437 if (!metadata_path
) {
438 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
442 metadata_file
= g_fopen(metadata_path
, "rb");
444 struct ctf_metadata_decoder_config metadata_decoder_config
= { 0 };
445 enum ctf_metadata_decoder_status decoder_status
;
448 metadata_decoder_config
.log_level
= log_level
;
449 metadata_decoder_config
.self_comp_class
=
450 bt_self_component_class_source_as_self_component_class(comp_class
);
452 metadata_decoder
= ctf_metadata_decoder_create(
453 &metadata_decoder_config
);
454 if (!metadata_decoder
) {
455 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
459 decoder_status
= ctf_metadata_decoder_append_content(
460 metadata_decoder
, metadata_file
);
461 if (decoder_status
!= CTF_METADATA_DECODER_STATUS_OK
) {
462 BT_LOGW("cannot append metadata content: metadata-decoder-status=%d",
464 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
469 * We were able to parse the metadata file, so we are
470 * confident it's a CTF trace.
474 /* If the trace has a UUID, return the stringified UUID as the group. */
475 if (ctf_metadata_decoder_get_trace_class_uuid(metadata_decoder
, uuid
) == 0) {
476 bt_uuid_to_str(uuid
, uuid_str
);
482 result
= bt_value_map_create();
484 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
488 insert_entry_status
= bt_value_map_insert_real_entry(result
, "weight", weight
);
489 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
490 status
= (int) insert_entry_status
;
494 /* We are not supposed to have weight == 0 and a UUID. */
495 BT_ASSERT(weight
> 0 || !has_uuid
);
497 if (weight
> 0 && has_uuid
) {
498 insert_entry_status
= bt_value_map_insert_string_entry(result
, "group", uuid_str
);
499 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
500 status
= (int) insert_entry_status
;
505 *user_result
= result
;
507 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
510 g_free(metadata_path
);
511 bt_value_put_ref(result
);
512 ctf_metadata_decoder_destroy(metadata_decoder
);