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"
33 #include "common/assert.h"
35 #include "../common/metadata/decoder.h"
36 #include "common/common.h"
37 #include "common/macros.h"
38 #include <babeltrace2/babeltrace.h>
40 #include "logging/comp-logging.h"
42 #define METADATA_TEXT_SIG "/* CTF 1.8"
51 bt_component_class_query_method_status
metadata_info_query(
52 bt_self_component_class_source
*self_comp_class_src
,
53 const bt_value
*params
, bt_logging_level log_level
,
54 const bt_value
**user_result
)
56 bt_component_class_query_method_status status
=
57 BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
58 bt_self_component_class
*self_comp_class
=
59 bt_self_component_class_source_as_self_component_class(self_comp_class_src
);
60 bt_value
*result
= NULL
;
61 const bt_value
*path_value
= NULL
;
62 char *metadata_text
= NULL
;
63 FILE *metadata_fp
= NULL
;
64 GString
*g_metadata_text
= NULL
;
70 result
= bt_value_map_create();
72 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
78 if (!bt_value_is_map(params
)) {
79 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
80 "Query parameters is not a map value object.");
81 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
85 path_value
= bt_value_map_borrow_entry_value_const(params
, "path");
87 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
88 "Mandatory `path` parameter missing");
89 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
93 if (!bt_value_is_string(path_value
)) {
94 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
95 "`path` parameter is required to be a string value");
96 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
100 path
= bt_value_string_get(path_value
);
103 metadata_fp
= ctf_fs_metadata_open_file(path
);
105 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
106 "Cannot open trace metadata: path=\"%s\".", path
);
110 is_packetized
= ctf_metadata_decoder_is_packetized(metadata_fp
,
111 &bo
, log_level
, NULL
);
114 ret
= ctf_metadata_decoder_packetized_file_stream_to_buf(
115 metadata_fp
, &metadata_text
, bo
, NULL
, NULL
,
118 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
119 "Cannot decode packetized metadata file: path=\"%s\"",
126 ret
= fseek(metadata_fp
, 0, SEEK_END
);
128 BT_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(self_comp_class
,
129 "Failed to seek to the end of the metadata file",
130 ": path=\"%s\"", path
);
133 filesize
= ftell(metadata_fp
);
135 BT_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(self_comp_class
,
136 "Failed to get the current position in the metadata file",
137 ": path=\"%s\"", path
);
141 metadata_text
= malloc(filesize
+ 1);
142 if (!metadata_text
) {
143 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
144 "Cannot allocate buffer for metadata text.");
148 if (fread(metadata_text
, filesize
, 1, metadata_fp
) != 1) {
149 BT_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(self_comp_class
,
150 "Cannot read metadata file", ": path=\"%s\"",
155 metadata_text
[filesize
] = '\0';
158 g_metadata_text
= g_string_new(NULL
);
159 if (!g_metadata_text
) {
163 if (strncmp(metadata_text
, METADATA_TEXT_SIG
,
164 sizeof(METADATA_TEXT_SIG
) - 1) != 0) {
165 g_string_assign(g_metadata_text
, METADATA_TEXT_SIG
);
166 g_string_append(g_metadata_text
, " */\n\n");
169 g_string_append(g_metadata_text
, metadata_text
);
171 ret
= bt_value_map_insert_string_entry(result
, "text",
172 g_metadata_text
->str
);
174 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
175 "Cannot insert metadata text into query result.");
179 ret
= bt_value_map_insert_bool_entry(result
, "is-packetized",
182 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
183 "Cannot insert \"is-packetized\" attribute into query result.");
190 BT_VALUE_PUT_REF_AND_RESET(result
);
194 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
200 if (g_metadata_text
) {
201 g_string_free(g_metadata_text
, TRUE
);
208 *user_result
= result
;
213 int add_range(bt_value
*info
, struct range
*range
,
214 const char *range_name
)
217 bt_value_map_insert_entry_status status
;
218 bt_value
*range_map
= NULL
;
225 range_map
= bt_value_map_create();
231 status
= bt_value_map_insert_signed_integer_entry(range_map
, "begin",
233 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
238 status
= bt_value_map_insert_signed_integer_entry(range_map
, "end",
240 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
245 status
= bt_value_map_insert_entry(info
, range_name
,
247 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
253 bt_value_put_ref(range_map
);
258 int add_stream_ids(bt_value
*info
, struct ctf_fs_ds_file_group
*ds_file_group
)
261 bt_value_map_insert_entry_status status
;
263 if (ds_file_group
->stream_id
!= UINT64_C(-1)) {
264 status
= bt_value_map_insert_unsigned_integer_entry(info
, "id",
265 ds_file_group
->stream_id
);
266 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
272 status
= bt_value_map_insert_unsigned_integer_entry(info
, "class-id",
273 ds_file_group
->sc
->id
);
274 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
284 int populate_stream_info(struct ctf_fs_ds_file_group
*group
,
285 bt_value
*group_info
, struct range
*stream_range
)
289 bt_value_map_insert_entry_status insert_status
;
290 bt_value_array_append_element_status append_status
;
291 bt_value
*file_paths
;
292 struct ctf_fs_ds_index_entry
*first_ds_index_entry
, *last_ds_index_entry
;
293 gchar
*port_name
= NULL
;
295 file_paths
= bt_value_array_create();
301 for (file_idx
= 0; file_idx
< group
->ds_file_infos
->len
; file_idx
++) {
302 struct ctf_fs_ds_file_info
*info
=
303 g_ptr_array_index(group
->ds_file_infos
,
306 append_status
= bt_value_array_append_string_element(file_paths
,
308 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
315 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
316 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
317 * the timestamp_begin of the first index entry and the timestamp_end
318 * of the last index entry.
320 BT_ASSERT(group
->index
);
321 BT_ASSERT(group
->index
->entries
);
322 BT_ASSERT(group
->index
->entries
->len
> 0);
325 first_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
326 group
->index
->entries
, 0);
329 last_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
330 group
->index
->entries
, group
->index
->entries
->len
- 1);
332 stream_range
->begin_ns
= first_ds_index_entry
->timestamp_begin_ns
;
333 stream_range
->end_ns
= last_ds_index_entry
->timestamp_end_ns
;
336 * If any of the begin and end timestamps is not set it means that
337 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
338 * in their packet context so we can't set the range.
340 stream_range
->set
= stream_range
->begin_ns
!= UINT64_C(-1) &&
341 stream_range
->end_ns
!= UINT64_C(-1);
343 ret
= add_range(group_info
, stream_range
, "range-ns");
348 insert_status
= bt_value_map_insert_entry(group_info
, "paths",
350 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
355 ret
= add_stream_ids(group_info
, group
);
360 port_name
= ctf_fs_make_port_name(group
);
366 insert_status
= bt_value_map_insert_string_entry(group_info
,
367 "port-name", port_name
);
368 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
375 bt_value_put_ref(file_paths
);
380 int populate_trace_info(const struct ctf_fs_trace
*trace
, bt_value
*trace_info
)
384 bt_value_map_insert_entry_status insert_status
;
385 bt_value_array_append_element_status append_status
;
386 bt_value
*file_groups
= NULL
;
387 struct range trace_range
= {
388 .begin_ns
= INT64_MAX
,
392 struct range trace_intersection
= {
398 BT_ASSERT(trace
->ds_file_groups
);
399 /* Add trace range info only if it contains streams. */
400 if (trace
->ds_file_groups
->len
== 0) {
405 file_groups
= bt_value_array_create();
410 insert_status
= bt_value_map_insert_string_entry(trace_info
, "name",
412 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
416 insert_status
= bt_value_map_insert_string_entry(trace_info
, "path",
418 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
423 /* Find range of all stream groups, and of the trace. */
424 for (group_idx
= 0; group_idx
< trace
->ds_file_groups
->len
;
426 bt_value
*group_info
;
427 struct range group_range
= { .set
= false };
428 struct ctf_fs_ds_file_group
*group
= g_ptr_array_index(
429 trace
->ds_file_groups
, group_idx
);
431 group_info
= bt_value_map_create();
437 ret
= populate_stream_info(group
, group_info
, &group_range
);
439 bt_value_put_ref(group_info
);
443 append_status
= bt_value_array_append_element(file_groups
,
445 bt_value_put_ref(group_info
);
446 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
450 if (group_range
.set
) {
451 trace_range
.begin_ns
= MIN(trace_range
.begin_ns
,
452 group_range
.begin_ns
);
453 trace_range
.end_ns
= MAX(trace_range
.end_ns
,
455 trace_range
.set
= true;
457 trace_intersection
.begin_ns
= MAX(trace_intersection
.begin_ns
,
458 group_range
.begin_ns
);
459 trace_intersection
.end_ns
= MIN(trace_intersection
.end_ns
,
461 trace_intersection
.set
= true;
465 ret
= add_range(trace_info
, &trace_range
, "range-ns");
470 if (trace_intersection
.begin_ns
< trace_intersection
.end_ns
) {
471 ret
= add_range(trace_info
, &trace_intersection
,
472 "intersection-range-ns");
478 insert_status
= bt_value_map_insert_entry(trace_info
, "streams",
480 BT_VALUE_PUT_REF_AND_RESET(file_groups
);
481 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
487 bt_value_put_ref(file_groups
);
492 bt_component_class_query_method_status
trace_info_query(
493 bt_self_component_class_source
*self_comp_class_src
,
494 const bt_value
*params
, bt_logging_level log_level
,
495 const bt_value
**user_result
)
497 struct ctf_fs_component
*ctf_fs
= NULL
;
498 bt_component_class_query_method_status status
=
499 BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
500 bt_self_component_class
*self_comp_class
=
501 bt_self_component_class_source_as_self_component_class(
502 self_comp_class_src
);
503 bt_value
*result
= NULL
;
504 const bt_value
*inputs_value
= NULL
;
510 if (!bt_value_is_map(params
)) {
511 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
512 "Query parameters is not a map value object.");
513 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
517 ctf_fs
= ctf_fs_component_create(log_level
, NULL
);
522 if (!read_src_fs_parameters(params
, &inputs_value
, ctf_fs
, NULL
,
524 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
528 if (ctf_fs_component_create_ctf_fs_traces(ctf_fs
, inputs_value
, NULL
,
533 result
= bt_value_array_create();
535 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
539 for (i
= 0; i
< ctf_fs
->traces
->len
; i
++) {
540 struct ctf_fs_trace
*trace
;
541 bt_value
*trace_info
;
542 bt_value_array_append_element_status append_status
;
544 trace
= g_ptr_array_index(ctf_fs
->traces
, i
);
547 trace_info
= bt_value_map_create();
549 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
550 "Failed to create trace info map.");
554 ret
= populate_trace_info(trace
, trace_info
);
556 bt_value_put_ref(trace_info
);
560 append_status
= bt_value_array_append_element(result
,
562 bt_value_put_ref(trace_info
);
563 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
571 BT_VALUE_PUT_REF_AND_RESET(result
);
575 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
580 ctf_fs_destroy(ctf_fs
);
584 *user_result
= result
;
589 bt_component_class_query_method_status
support_info_query(
590 bt_self_component_class_source
*comp_class
,
591 const bt_value
*params
, bt_logging_level log_level
,
592 const bt_value
**user_result
)
594 const bt_value
*input_type_value
;
595 const char *input_type
;
596 bt_component_class_query_method_status status
;
598 gchar
*metadata_path
= NULL
;
599 bt_value
*result
= NULL
;
601 input_type_value
= bt_value_map_borrow_entry_value_const(params
, "type");
602 BT_ASSERT(input_type_value
);
603 BT_ASSERT(bt_value_get_type(input_type_value
) == BT_VALUE_TYPE_STRING
);
604 input_type
= bt_value_string_get(input_type_value
);
606 result
= bt_value_map_create();
608 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
612 if (strcmp(input_type
, "directory") == 0) {
613 const bt_value
*input_value
;
616 input_value
= bt_value_map_borrow_entry_value_const(params
, "input");
617 BT_ASSERT(input_value
);
618 BT_ASSERT(bt_value_get_type(input_value
) == BT_VALUE_TYPE_STRING
);
619 path
= bt_value_string_get(input_value
);
621 metadata_path
= g_build_filename(path
, CTF_FS_METADATA_FILENAME
, NULL
);
622 if (!metadata_path
) {
623 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
628 * If the metadata file exists in this directory, consider it to
631 if (g_file_test(metadata_path
, G_FILE_TEST_EXISTS
)) {
636 if (bt_value_map_insert_real_entry(result
, "weight", weight
) != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
637 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
642 * Use the arbitrary constant string "ctf" as the group, such that all
643 * found ctf traces are passed to the same instance of src.ctf.fs.
645 if (bt_value_map_insert_string_entry(result
, "group", "ctf") != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
646 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
650 *user_result
= result
;
652 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
655 g_free(metadata_path
);
656 bt_value_put_ref(result
);