4 * Babeltrace CTF file system Reader Component queries
6 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 #define BT_LOG_OUTPUT_LEVEL log_level
28 #define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/QUERY"
29 #include "logging/log.h"
34 #include <glib/gstdio.h>
36 #include <sys/types.h>
38 #include "common/assert.h"
40 #include "../common/metadata/decoder.h"
41 #include "common/common.h"
42 #include "common/macros.h"
43 #include <babeltrace2/babeltrace.h>
45 #include "logging/comp-logging.h"
47 #define METADATA_TEXT_SIG "/* CTF 1.8"
56 bt_component_class_query_method_status
metadata_info_query(
57 bt_self_component_class_source
*self_comp_class_src
,
58 const bt_value
*params
, bt_logging_level log_level
,
59 const bt_value
**user_result
)
61 bt_component_class_query_method_status status
=
62 BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
63 bt_self_component_class
*self_comp_class
=
64 bt_self_component_class_source_as_self_component_class(self_comp_class_src
);
65 bt_value
*result
= NULL
;
66 const bt_value
*path_value
= NULL
;
67 FILE *metadata_fp
= NULL
;
72 struct ctf_metadata_decoder
*decoder
= NULL
;
73 struct ctf_metadata_decoder_config decoder_cfg
= { 0 };
74 enum ctf_metadata_decoder_status decoder_status
;
76 result
= bt_value_map_create();
78 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
84 if (!bt_value_is_map(params
)) {
85 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
86 "Query parameters is not a map value object.");
87 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
91 path_value
= bt_value_map_borrow_entry_value_const(params
, "path");
93 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
94 "Mandatory `path` parameter missing");
95 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
99 if (!bt_value_is_string(path_value
)) {
100 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
101 "`path` parameter is required to be a string value");
102 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
106 path
= bt_value_string_get(path_value
);
109 metadata_fp
= ctf_fs_metadata_open_file(path
);
111 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
112 "Cannot open trace metadata: path=\"%s\".", path
);
116 ret
= ctf_metadata_decoder_is_packetized(metadata_fp
, &is_packetized
,
117 &bo
, log_level
, NULL
);
119 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
120 "Cannot check whether or not the metadata stream is packetized: path=\"%s\".",
125 decoder_cfg
.log_level
= log_level
;
126 decoder_cfg
.keep_plain_text
= true;
127 decoder
= ctf_metadata_decoder_create(&decoder_cfg
);
129 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
130 "Cannot create metadata decoder: path=\"%s\".", path
);
135 decoder_status
= ctf_metadata_decoder_append_content(decoder
,
137 if (decoder_status
) {
138 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
139 "Cannot update metadata decoder's content: path=\"%s\".",
144 ret
= bt_value_map_insert_string_entry(result
, "text",
145 ctf_metadata_decoder_get_text(decoder
));
147 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
148 "Cannot insert metadata text into query result.");
152 ret
= bt_value_map_insert_bool_entry(result
, "is-packetized",
155 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
156 "Cannot insert \"is-packetized\" attribute into query result.");
163 BT_VALUE_PUT_REF_AND_RESET(result
);
167 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
171 ctf_metadata_decoder_destroy(decoder
);
177 *user_result
= result
;
182 int add_range(bt_value
*info
, struct range
*range
,
183 const char *range_name
)
186 bt_value_map_insert_entry_status status
;
194 status
= bt_value_map_insert_empty_map_entry(info
, range_name
,
196 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
201 status
= bt_value_map_insert_signed_integer_entry(range_map
, "begin",
203 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
208 status
= bt_value_map_insert_signed_integer_entry(range_map
, "end",
210 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
220 int populate_stream_info(struct ctf_fs_ds_file_group
*group
,
221 bt_value
*group_info
, struct range
*stream_range
)
224 bt_value_map_insert_entry_status insert_status
;
225 struct ctf_fs_ds_index_entry
*first_ds_index_entry
, *last_ds_index_entry
;
226 gchar
*port_name
= NULL
;
229 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
230 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
231 * the timestamp_begin of the first index entry and the timestamp_end
232 * of the last index entry.
234 BT_ASSERT(group
->index
);
235 BT_ASSERT(group
->index
->entries
);
236 BT_ASSERT(group
->index
->entries
->len
> 0);
239 first_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
240 group
->index
->entries
, 0);
243 last_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
244 group
->index
->entries
, group
->index
->entries
->len
- 1);
246 stream_range
->begin_ns
= first_ds_index_entry
->timestamp_begin_ns
;
247 stream_range
->end_ns
= last_ds_index_entry
->timestamp_end_ns
;
250 * If any of the begin and end timestamps is not set it means that
251 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
252 * in their packet context so we can't set the range.
254 stream_range
->set
= stream_range
->begin_ns
!= UINT64_C(-1) &&
255 stream_range
->end_ns
!= UINT64_C(-1);
257 ret
= add_range(group_info
, stream_range
, "range-ns");
262 port_name
= ctf_fs_make_port_name(group
);
268 insert_status
= bt_value_map_insert_string_entry(group_info
,
269 "port-name", port_name
);
270 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
281 int populate_trace_info(const struct ctf_fs_trace
*trace
, bt_value
*trace_info
)
285 bt_value_map_insert_entry_status insert_status
;
286 bt_value_array_append_element_status append_status
;
287 bt_value
*file_groups
= NULL
;
288 struct range trace_intersection
= {
294 BT_ASSERT(trace
->ds_file_groups
);
295 /* Add trace range info only if it contains streams. */
296 if (trace
->ds_file_groups
->len
== 0) {
301 insert_status
= bt_value_map_insert_empty_array_entry(trace_info
,
302 "streams", &file_groups
);
303 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
308 /* Find range of all stream groups, and of the trace. */
309 for (group_idx
= 0; group_idx
< trace
->ds_file_groups
->len
;
311 bt_value
*group_info
;
312 struct range group_range
= { .set
= false };
313 struct ctf_fs_ds_file_group
*group
= g_ptr_array_index(
314 trace
->ds_file_groups
, group_idx
);
316 append_status
= bt_value_array_append_empty_map_element(
317 file_groups
, &group_info
);
318 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
323 ret
= populate_stream_info(group
, group_info
, &group_range
);
328 if (group_range
.set
) {
329 trace_intersection
.begin_ns
= MAX(trace_intersection
.begin_ns
,
330 group_range
.begin_ns
);
331 trace_intersection
.end_ns
= MIN(trace_intersection
.end_ns
,
333 trace_intersection
.set
= true;
337 if (trace_intersection
.begin_ns
< trace_intersection
.end_ns
) {
338 ret
= add_range(trace_info
, &trace_intersection
,
339 "intersection-range-ns");
350 bt_component_class_query_method_status
trace_info_query(
351 bt_self_component_class_source
*self_comp_class_src
,
352 const bt_value
*params
, bt_logging_level log_level
,
353 const bt_value
**user_result
)
355 struct ctf_fs_component
*ctf_fs
= NULL
;
356 bt_component_class_query_method_status status
=
357 BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
358 bt_self_component_class
*self_comp_class
=
359 bt_self_component_class_source_as_self_component_class(
360 self_comp_class_src
);
361 bt_value
*result
= NULL
;
362 const bt_value
*inputs_value
= NULL
;
364 bt_value
*trace_info
= NULL
;
365 bt_value_array_append_element_status append_status
;
369 if (!bt_value_is_map(params
)) {
370 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
371 "Query parameters is not a map value object.");
372 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
376 ctf_fs
= ctf_fs_component_create(log_level
, NULL
);
381 if (!read_src_fs_parameters(params
, &inputs_value
, ctf_fs
, NULL
,
383 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
387 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs
, inputs_value
, NULL
,
392 result
= bt_value_array_create();
394 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
398 append_status
= bt_value_array_append_empty_map_element(result
,
400 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
401 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
402 "Failed to create trace info map.");
406 ret
= populate_trace_info(ctf_fs
->trace
, trace_info
);
414 BT_VALUE_PUT_REF_AND_RESET(result
);
418 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
423 ctf_fs_destroy(ctf_fs
);
427 *user_result
= result
;
432 bt_component_class_query_method_status
support_info_query(
433 bt_self_component_class_source
*comp_class
,
434 const bt_value
*params
, bt_logging_level log_level
,
435 const bt_value
**user_result
)
437 const bt_value
*input_type_value
;
438 const char *input_type
;
439 bt_component_class_query_method_status status
;
440 bt_value_map_insert_entry_status insert_entry_status
;
442 gchar
*metadata_path
= NULL
;
443 bt_value
*result
= NULL
;
444 struct ctf_metadata_decoder
*metadata_decoder
= NULL
;
445 FILE *metadata_file
= NULL
;
446 char uuid_str
[BT_UUID_STR_LEN
+ 1];
447 bool has_uuid
= false;
448 const bt_value
*input_value
;
451 input_type_value
= bt_value_map_borrow_entry_value_const(params
, "type");
452 BT_ASSERT(input_type_value
);
453 BT_ASSERT(bt_value_get_type(input_type_value
) == BT_VALUE_TYPE_STRING
);
454 input_type
= bt_value_string_get(input_type_value
);
456 if (strcmp(input_type
, "directory") != 0) {
460 input_value
= bt_value_map_borrow_entry_value_const(params
, "input");
461 BT_ASSERT(input_value
);
462 BT_ASSERT(bt_value_get_type(input_value
) == BT_VALUE_TYPE_STRING
);
463 input
= bt_value_string_get(input_value
);
465 metadata_path
= g_build_filename(input
, CTF_FS_METADATA_FILENAME
, NULL
);
466 if (!metadata_path
) {
467 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
471 metadata_file
= g_fopen(metadata_path
, "r");
473 struct ctf_metadata_decoder_config metadata_decoder_config
= { 0 };
474 enum ctf_metadata_decoder_status decoder_status
;
477 metadata_decoder_config
.log_level
= log_level
;
479 metadata_decoder
= ctf_metadata_decoder_create(
480 &metadata_decoder_config
);
481 if (!metadata_decoder
) {
482 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
486 decoder_status
= ctf_metadata_decoder_append_content(
487 metadata_decoder
, metadata_file
);
488 if (decoder_status
!= CTF_METADATA_DECODER_STATUS_OK
) {
489 BT_LOGW("cannot append metadata content: metadata-decoder-status=%d",
491 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
496 * We were able to parse the metadata file, so we are
497 * confident it's a CTF trace.
501 /* If the trace has a UUID, return the stringified UUID as the group. */
502 if (ctf_metadata_decoder_get_trace_class_uuid(metadata_decoder
, uuid
) == 0) {
503 bt_uuid_to_str(uuid
, uuid_str
);
509 result
= bt_value_map_create();
511 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
515 insert_entry_status
= bt_value_map_insert_real_entry(result
, "weight", weight
);
516 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
517 status
= (int) insert_entry_status
;
521 /* We are not supposed to have weight == 0 and a UUID. */
522 BT_ASSERT(weight
> 0 || !has_uuid
);
524 if (weight
> 0 && has_uuid
) {
525 insert_entry_status
= bt_value_map_insert_string_entry(result
, "group", uuid_str
);
526 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
527 status
= (int) insert_entry_status
;
532 *user_result
= result
;
534 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
537 g_free(metadata_path
);
538 bt_value_put_ref(result
);
539 ctf_metadata_decoder_destroy(metadata_decoder
);