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
29 #include <babeltrace/assert-internal.h>
31 #include "../common/metadata/decoder.h"
32 #include <babeltrace/common-internal.h>
33 #include <babeltrace/babeltrace-internal.h>
34 #include <babeltrace/babeltrace.h>
37 #define BT_LOG_TAG "PLUGIN-CTF-FS-QUERY-SRC"
40 #define METADATA_TEXT_SIG "/* CTF 1.8"
49 struct bt_component_class_query_method_return
metadata_info_query(
50 struct bt_component_class
*comp_class
,
51 struct bt_value
*params
)
53 struct bt_component_class_query_method_return query_ret
= {
55 .status
= BT_QUERY_STATUS_OK
,
58 struct bt_private_value
*result
= NULL
;
59 struct bt_value
*path_value
= NULL
;
60 char *metadata_text
= NULL
;
61 FILE *metadata_fp
= NULL
;
62 GString
*g_metadata_text
= NULL
;
68 result
= bt_private_value_map_create();
70 query_ret
.status
= BT_QUERY_STATUS_NOMEM
;
74 query_ret
.result
= bt_value_borrow_from_private(result
);
77 if (!bt_value_is_map(params
)) {
78 BT_LOGE_STR("Query parameters is not a map value object.");
79 query_ret
.status
= BT_QUERY_STATUS_INVALID_PARAMS
;
83 path_value
= bt_value_map_borrow_entry_value(params
, "path");
84 path
= bt_value_string_get(path_value
);
87 metadata_fp
= ctf_fs_metadata_open_file(path
);
89 BT_LOGE("Cannot open trace metadata: path=\"%s\".", path
);
93 is_packetized
= ctf_metadata_decoder_is_packetized(metadata_fp
,
97 ret
= ctf_metadata_decoder_packetized_file_stream_to_buf(
98 metadata_fp
, &metadata_text
, bo
);
100 BT_LOGE("Cannot decode packetized metadata file: path=\"%s\"",
107 ret
= fseek(metadata_fp
, 0, SEEK_END
);
109 BT_LOGE_ERRNO("Failed to seek to the end of the metadata file",
110 ": path=\"%s\"", path
);
113 filesize
= ftell(metadata_fp
);
115 BT_LOGE_ERRNO("Failed to get the current position in the metadata file",
116 ": path=\"%s\"", path
);
120 metadata_text
= malloc(filesize
+ 1);
121 if (!metadata_text
) {
122 BT_LOGE_STR("Cannot allocate buffer for metadata text.");
126 if (fread(metadata_text
, filesize
, 1, metadata_fp
) != 1) {
127 BT_LOGE_ERRNO("Cannot read metadata file", ": path=\"%s\"",
132 metadata_text
[filesize
] = '\0';
135 g_metadata_text
= g_string_new(NULL
);
136 if (!g_metadata_text
) {
140 if (strncmp(metadata_text
, METADATA_TEXT_SIG
,
141 sizeof(METADATA_TEXT_SIG
) - 1) != 0) {
142 g_string_assign(g_metadata_text
, METADATA_TEXT_SIG
);
143 g_string_append(g_metadata_text
, " */\n\n");
146 g_string_append(g_metadata_text
, metadata_text
);
148 ret
= bt_private_value_map_insert_string_entry(result
, "text",
149 g_metadata_text
->str
);
151 BT_LOGE_STR("Cannot insert metadata text into query result.");
155 ret
= bt_private_value_map_insert_bool_entry(result
, "is-packetized",
158 BT_LOGE_STR("Cannot insert \"is-packetized\" attribute into query result.");
165 BT_OBJECT_PUT_REF_AND_RESET(result
);
166 query_ret
.result
= NULL
;
168 if (query_ret
.status
>= 0) {
169 query_ret
.status
= BT_QUERY_STATUS_ERROR
;
175 if (g_metadata_text
) {
176 g_string_free(g_metadata_text
, TRUE
);
187 int add_range(struct bt_private_value
*info
, struct range
*range
,
188 const char *range_name
)
191 enum bt_value_status status
;
192 struct bt_private_value
*range_map
= NULL
;
199 range_map
= bt_private_value_map_create();
205 status
= bt_private_value_map_insert_integer_entry(range_map
, "begin",
207 if (status
!= BT_VALUE_STATUS_OK
) {
212 status
= bt_private_value_map_insert_integer_entry(range_map
, "end",
214 if (status
!= BT_VALUE_STATUS_OK
) {
219 status
= bt_private_value_map_insert_entry(info
, range_name
,
220 bt_value_borrow_from_private(range_map
));
221 if (status
!= BT_VALUE_STATUS_OK
) {
227 bt_object_put_ref(range_map
);
232 int add_stream_ids(struct bt_private_value
*info
,
233 struct bt_stream
*stream
)
236 int64_t stream_class_id
, stream_instance_id
;
237 enum bt_value_status status
;
238 struct bt_stream_class
*stream_class
= NULL
;
240 stream_instance_id
= bt_stream_get_id(stream
);
241 if (stream_instance_id
!= -1) {
242 status
= bt_private_value_map_insert_integer_entry(info
, "id",
244 if (status
!= BT_VALUE_STATUS_OK
) {
250 stream_class
= bt_stream_borrow_class(stream
);
256 stream_class_id
= bt_stream_class_get_id(stream_class
);
257 if (stream_class_id
== -1) {
262 status
= bt_private_value_map_insert_integer_entry(info
, "class-id", stream_class_id
);
263 if (status
!= BT_VALUE_STATUS_OK
) {
273 int populate_stream_info(struct ctf_fs_ds_file_group
*group
,
274 struct bt_private_value
*group_info
,
275 struct range
*stream_range
)
279 enum bt_value_status status
;
280 struct bt_private_value
*file_paths
;
282 stream_range
->begin_ns
= INT64_MAX
;
283 stream_range
->end_ns
= 0;
285 file_paths
= bt_private_value_array_create();
291 for (file_idx
= 0; file_idx
< group
->ds_file_infos
->len
; file_idx
++) {
292 int64_t file_begin_epoch
, file_end_epoch
;
293 struct ctf_fs_ds_file_info
*info
=
294 g_ptr_array_index(group
->ds_file_infos
,
297 if (!info
->index
|| info
->index
->entries
->len
== 0) {
298 BT_LOGW("Cannot determine range of unindexed stream file \'%s\'",
304 status
= bt_private_value_array_append_string_element(file_paths
,
306 if (status
!= BT_VALUE_STATUS_OK
) {
312 * file range is from timestamp_begin of the first entry to the
313 * timestamp_end of the last entry.
315 file_begin_epoch
= ((struct ctf_fs_ds_index_entry
*) &g_array_index(info
->index
->entries
,
316 struct ctf_fs_ds_index_entry
, 0))->timestamp_begin_ns
;
317 file_end_epoch
= ((struct ctf_fs_ds_index_entry
*) &g_array_index(info
->index
->entries
,
318 struct ctf_fs_ds_index_entry
, info
->index
->entries
->len
- 1))->timestamp_end_ns
;
320 stream_range
->begin_ns
= min(stream_range
->begin_ns
, file_begin_epoch
);
321 stream_range
->end_ns
= max(stream_range
->end_ns
, file_end_epoch
);
322 stream_range
->set
= true;
325 if (stream_range
->set
) {
326 ret
= add_range(group_info
, stream_range
, "range-ns");
332 status
= bt_private_value_map_insert_entry(group_info
, "paths",
333 bt_value_borrow_from_private(file_paths
));
334 if (status
!= BT_VALUE_STATUS_OK
) {
339 ret
= add_stream_ids(group_info
,
340 bt_stream_borrow_from_private(group
->stream
));
345 bt_object_put_ref(file_paths
);
350 int populate_trace_info(const char *trace_path
, const char *trace_name
,
351 struct bt_private_value
*trace_info
)
355 struct ctf_fs_trace
*trace
= NULL
;
356 enum bt_value_status status
;
357 struct bt_private_value
*file_groups
;
358 struct range trace_range
= {
359 .begin_ns
= INT64_MAX
,
363 struct range trace_intersection
= {
369 file_groups
= bt_private_value_array_create();
374 status
= bt_private_value_map_insert_string_entry(trace_info
, "name",
376 if (status
!= BT_VALUE_STATUS_OK
) {
380 status
= bt_private_value_map_insert_string_entry(trace_info
, "path",
382 if (status
!= BT_VALUE_STATUS_OK
) {
387 trace
= ctf_fs_trace_create(trace_path
, trace_name
, NULL
);
389 BT_LOGE("Failed to create fs trace at \'%s\'", trace_path
);
394 BT_ASSERT(trace
->ds_file_groups
);
395 /* Add trace range info only if it contains streams. */
396 if (trace
->ds_file_groups
->len
== 0) {
401 /* Find range of all stream groups, and of the trace. */
402 for (group_idx
= 0; group_idx
< trace
->ds_file_groups
->len
;
404 struct bt_private_value
*group_info
;
405 struct range group_range
= { .set
= false };
406 struct ctf_fs_ds_file_group
*group
= g_ptr_array_index(
407 trace
->ds_file_groups
, group_idx
);
409 group_info
= bt_private_value_map_create();
415 ret
= populate_stream_info(group
, group_info
, &group_range
);
417 bt_object_put_ref(group_info
);
421 if (group_range
.set
) {
422 trace_range
.begin_ns
= min(trace_range
.begin_ns
,
423 group_range
.begin_ns
);
424 trace_range
.end_ns
= max(trace_range
.end_ns
,
426 trace_range
.set
= true;
428 trace_intersection
.begin_ns
= max(trace_intersection
.begin_ns
,
429 group_range
.begin_ns
);
430 trace_intersection
.end_ns
= min(trace_intersection
.end_ns
,
432 trace_intersection
.set
= true;
433 status
= bt_private_value_array_append_element(
435 bt_value_borrow_from_private(group_info
));
436 bt_object_put_ref(group_info
);
437 if (status
!= BT_VALUE_STATUS_OK
) {
443 ret
= add_range(trace_info
, &trace_range
, "range-ns");
448 if (trace_intersection
.begin_ns
< trace_intersection
.end_ns
) {
449 ret
= add_range(trace_info
, &trace_intersection
,
450 "intersection-range-ns");
456 status
= bt_private_value_map_insert_entry(trace_info
, "streams",
457 bt_value_borrow_from_private(file_groups
));
458 BT_OBJECT_PUT_REF_AND_RESET(file_groups
);
459 if (status
!= BT_VALUE_STATUS_OK
) {
465 bt_object_put_ref(file_groups
);
466 ctf_fs_trace_destroy(trace
);
471 struct bt_component_class_query_method_return
trace_info_query(
472 struct bt_component_class
*comp_class
,
473 struct bt_value
*params
)
475 struct bt_component_class_query_method_return query_ret
= {
477 .status
= BT_QUERY_STATUS_OK
,
480 struct bt_private_value
*result
= NULL
;
481 struct bt_value
*path_value
= NULL
;
483 const char *path
= NULL
;
484 GList
*trace_paths
= NULL
;
485 GList
*trace_names
= NULL
;
486 GList
*tp_node
= NULL
;
487 GList
*tn_node
= NULL
;
488 GString
*normalized_path
= NULL
;
492 if (!bt_value_is_map(params
)) {
493 BT_LOGE("Query parameters is not a map value object.");
494 query_ret
.status
= BT_QUERY_STATUS_INVALID_PARAMS
;
498 path_value
= bt_value_map_borrow_entry_value(params
, "path");
499 path
= bt_value_string_get(path_value
);
501 normalized_path
= bt_common_normalize_path(path
, NULL
);
502 if (!normalized_path
) {
503 BT_LOGE("Failed to normalize path: `%s`.", path
);
508 ret
= ctf_fs_find_traces(&trace_paths
, normalized_path
->str
);
513 trace_names
= ctf_fs_create_trace_names(trace_paths
,
514 normalized_path
->str
);
516 BT_LOGE("Cannot create trace names from trace paths.");
520 result
= bt_private_value_array_create();
522 query_ret
.status
= BT_QUERY_STATUS_NOMEM
;
526 query_ret
.result
= bt_value_borrow_from_private(result
);
528 /* Iterates over both trace paths and names simultaneously. */
529 for (tp_node
= trace_paths
, tn_node
= trace_names
; tp_node
;
530 tp_node
= g_list_next(tp_node
),
531 tn_node
= g_list_next(tn_node
)) {
532 GString
*trace_path
= tp_node
->data
;
533 GString
*trace_name
= tn_node
->data
;
534 enum bt_value_status status
;
535 struct bt_private_value
*trace_info
;
537 trace_info
= bt_private_value_map_create();
539 BT_LOGE("Failed to create trace info map.");
543 ret
= populate_trace_info(trace_path
->str
, trace_name
->str
,
546 bt_object_put_ref(trace_info
);
550 status
= bt_private_value_array_append_element(result
,
551 bt_value_borrow_from_private(trace_info
));
552 bt_object_put_ref(trace_info
);
553 if (status
!= BT_VALUE_STATUS_OK
) {
561 BT_OBJECT_PUT_REF_AND_RESET(result
);
562 query_ret
.result
= NULL
;
564 if (query_ret
.status
>= 0) {
565 query_ret
.status
= BT_QUERY_STATUS_ERROR
;
569 if (normalized_path
) {
570 g_string_free(normalized_path
, TRUE
);
573 for (tp_node
= trace_paths
; tp_node
; tp_node
= g_list_next(tp_node
)) {
575 g_string_free(tp_node
->data
, TRUE
);
578 g_list_free(trace_paths
);
581 for (tn_node
= trace_names
; tn_node
; tn_node
= g_list_next(tn_node
)) {
583 g_string_free(tn_node
->data
, TRUE
);
586 g_list_free(trace_names
);
588 /* "path" becomes invalid with the release of path_value. */