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 bt_query_status
metadata_info_query(
50 bt_self_component_class_source
*comp_class
,
51 const bt_value
*params
,
52 const bt_value
**user_result
)
54 bt_query_status status
= BT_QUERY_STATUS_OK
;
55 bt_value
*result
= NULL
;
56 const bt_value
*path_value
= NULL
;
57 char *metadata_text
= NULL
;
58 FILE *metadata_fp
= NULL
;
59 GString
*g_metadata_text
= NULL
;
65 result
= bt_value_map_create();
67 status
= BT_QUERY_STATUS_NOMEM
;
73 if (!bt_value_is_map(params
)) {
74 BT_LOGE_STR("Query parameters is not a map value object.");
75 status
= BT_QUERY_STATUS_INVALID_PARAMS
;
79 path_value
= bt_value_map_borrow_entry_value_const(params
, "path");
81 BT_LOGE_STR("Mandatory `path` parameter missing");
82 status
= BT_QUERY_STATUS_INVALID_PARAMS
;
86 if (!bt_value_is_string(path_value
)) {
87 BT_LOGE_STR("`path` parameter is required to be a string value");
88 status
= BT_QUERY_STATUS_INVALID_PARAMS
;
92 path
= bt_value_string_get(path_value
);
95 metadata_fp
= ctf_fs_metadata_open_file(path
);
97 BT_LOGE("Cannot open trace metadata: path=\"%s\".", path
);
101 is_packetized
= ctf_metadata_decoder_is_packetized(metadata_fp
,
105 ret
= ctf_metadata_decoder_packetized_file_stream_to_buf(
106 metadata_fp
, &metadata_text
, bo
);
108 BT_LOGE("Cannot decode packetized metadata file: path=\"%s\"",
115 ret
= fseek(metadata_fp
, 0, SEEK_END
);
117 BT_LOGE_ERRNO("Failed to seek to the end of the metadata file",
118 ": path=\"%s\"", path
);
121 filesize
= ftell(metadata_fp
);
123 BT_LOGE_ERRNO("Failed to get the current position in the metadata file",
124 ": path=\"%s\"", path
);
128 metadata_text
= malloc(filesize
+ 1);
129 if (!metadata_text
) {
130 BT_LOGE_STR("Cannot allocate buffer for metadata text.");
134 if (fread(metadata_text
, filesize
, 1, metadata_fp
) != 1) {
135 BT_LOGE_ERRNO("Cannot read metadata file", ": path=\"%s\"",
140 metadata_text
[filesize
] = '\0';
143 g_metadata_text
= g_string_new(NULL
);
144 if (!g_metadata_text
) {
148 if (strncmp(metadata_text
, METADATA_TEXT_SIG
,
149 sizeof(METADATA_TEXT_SIG
) - 1) != 0) {
150 g_string_assign(g_metadata_text
, METADATA_TEXT_SIG
);
151 g_string_append(g_metadata_text
, " */\n\n");
154 g_string_append(g_metadata_text
, metadata_text
);
156 ret
= bt_value_map_insert_string_entry(result
, "text",
157 g_metadata_text
->str
);
159 BT_LOGE_STR("Cannot insert metadata text into query result.");
163 ret
= bt_value_map_insert_bool_entry(result
, "is-packetized",
166 BT_LOGE_STR("Cannot insert \"is-packetized\" attribute into query result.");
173 BT_VALUE_PUT_REF_AND_RESET(result
);
177 status
= BT_QUERY_STATUS_ERROR
;
183 if (g_metadata_text
) {
184 g_string_free(g_metadata_text
, TRUE
);
191 *user_result
= result
;
196 int add_range(bt_value
*info
, struct range
*range
,
197 const char *range_name
)
200 bt_value_status status
;
201 bt_value
*range_map
= NULL
;
208 range_map
= bt_value_map_create();
214 status
= bt_value_map_insert_integer_entry(range_map
, "begin",
216 if (status
!= BT_VALUE_STATUS_OK
) {
221 status
= bt_value_map_insert_integer_entry(range_map
, "end",
223 if (status
!= BT_VALUE_STATUS_OK
) {
228 status
= bt_value_map_insert_entry(info
, range_name
,
230 if (status
!= BT_VALUE_STATUS_OK
) {
236 bt_value_put_ref(range_map
);
241 int add_stream_ids(bt_value
*info
, struct ctf_fs_ds_file_group
*ds_file_group
)
244 bt_value_status status
;
246 if (ds_file_group
->stream_id
!= UINT64_C(-1)) {
247 status
= bt_value_map_insert_integer_entry(info
, "id",
248 (int64_t) ds_file_group
->stream_id
);
249 if (status
!= BT_VALUE_STATUS_OK
) {
255 status
= bt_value_map_insert_integer_entry(info
, "class-id",
256 (int64_t) ds_file_group
->sc
->id
);
257 if (status
!= BT_VALUE_STATUS_OK
) {
267 int populate_stream_info(struct ctf_fs_ds_file_group
*group
,
268 bt_value
*group_info
, struct range
*stream_range
)
272 bt_value_status status
;
273 bt_value
*file_paths
;
274 struct ctf_fs_ds_file_info
*first_file_info
, *last_file_info
;
275 struct ctf_fs_ds_index_entry
*first_ds_index_entry
, *last_ds_index_entry
;
277 file_paths
= bt_value_array_create();
283 for (file_idx
= 0; file_idx
< group
->ds_file_infos
->len
; file_idx
++) {
284 struct ctf_fs_ds_file_info
*info
=
285 g_ptr_array_index(group
->ds_file_infos
,
288 if (!info
->index
|| info
->index
->entries
->len
== 0) {
289 BT_LOGW("Cannot determine range of unindexed stream file \'%s\'",
295 status
= bt_value_array_append_string_element(file_paths
,
297 if (status
!= BT_VALUE_STATUS_OK
) {
304 * Since `struct ctf_fs_ds_file_info` elements are sorted by value of
305 * `begin_ns` within the `ds_file_groups` array and `struct
306 * ctf_fs_ds_index_entry` elements are sorted by time within their
307 * respective `struct ctf_fs_ds_file_info`, we can compute the stream
308 * range from timestamp_begin of the first index entry of the first
309 * file to the timestamp_end of the last index entry of the last file.
311 BT_ASSERT(group
->ds_file_infos
->len
> 0);
313 first_file_info
= g_ptr_array_index(group
->ds_file_infos
, 0);
314 last_file_info
= g_ptr_array_index(group
->ds_file_infos
,
315 group
->ds_file_infos
->len
- 1);
317 BT_ASSERT(first_file_info
->index
->entries
->len
> 0);
319 first_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) &g_array_index(
320 first_file_info
->index
->entries
, struct ctf_fs_ds_index_entry
, 0);
322 BT_ASSERT(last_file_info
->index
->entries
->len
> 0);
324 last_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) &g_array_index(
325 last_file_info
->index
->entries
, struct ctf_fs_ds_index_entry
,
326 last_file_info
->index
->entries
->len
- 1);
328 stream_range
->begin_ns
= first_ds_index_entry
->timestamp_begin_ns
;
329 stream_range
->end_ns
= last_ds_index_entry
->timestamp_end_ns
;
330 stream_range
->set
= true;
332 if (stream_range
->set
) {
333 ret
= add_range(group_info
, stream_range
, "range-ns");
339 status
= bt_value_map_insert_entry(group_info
, "paths",
341 if (status
!= BT_VALUE_STATUS_OK
) {
346 ret
= add_stream_ids(group_info
, group
);
351 bt_value_put_ref(file_paths
);
356 int populate_trace_info(const struct ctf_fs_trace
*trace
, bt_value
*trace_info
)
360 bt_value_status status
;
361 bt_value
*file_groups
= NULL
;
362 struct range trace_range
= {
363 .begin_ns
= INT64_MAX
,
367 struct range trace_intersection
= {
373 BT_ASSERT(trace
->ds_file_groups
);
374 /* Add trace range info only if it contains streams. */
375 if (trace
->ds_file_groups
->len
== 0) {
380 file_groups
= bt_value_array_create();
385 status
= bt_value_map_insert_string_entry(trace_info
, "name",
387 if (status
!= BT_VALUE_STATUS_OK
) {
391 status
= bt_value_map_insert_string_entry(trace_info
, "path",
393 if (status
!= BT_VALUE_STATUS_OK
) {
398 /* Find range of all stream groups, and of the trace. */
399 for (group_idx
= 0; group_idx
< trace
->ds_file_groups
->len
;
401 bt_value
*group_info
;
402 struct range group_range
= { .set
= false };
403 struct ctf_fs_ds_file_group
*group
= g_ptr_array_index(
404 trace
->ds_file_groups
, group_idx
);
406 group_info
= bt_value_map_create();
412 ret
= populate_stream_info(group
, group_info
, &group_range
);
414 bt_value_put_ref(group_info
);
418 if (group_range
.set
) {
419 trace_range
.begin_ns
= min(trace_range
.begin_ns
,
420 group_range
.begin_ns
);
421 trace_range
.end_ns
= max(trace_range
.end_ns
,
423 trace_range
.set
= true;
425 trace_intersection
.begin_ns
= max(trace_intersection
.begin_ns
,
426 group_range
.begin_ns
);
427 trace_intersection
.end_ns
= min(trace_intersection
.end_ns
,
429 trace_intersection
.set
= true;
430 status
= bt_value_array_append_element(
433 bt_value_put_ref(group_info
);
434 if (status
!= BT_VALUE_STATUS_OK
) {
440 ret
= add_range(trace_info
, &trace_range
, "range-ns");
445 if (trace_intersection
.begin_ns
< trace_intersection
.end_ns
) {
446 ret
= add_range(trace_info
, &trace_intersection
,
447 "intersection-range-ns");
453 status
= bt_value_map_insert_entry(trace_info
, "streams",
455 BT_VALUE_PUT_REF_AND_RESET(file_groups
);
456 if (status
!= BT_VALUE_STATUS_OK
) {
462 bt_value_put_ref(file_groups
);
467 bt_query_status
trace_info_query(
468 bt_self_component_class_source
*comp_class
,
469 const bt_value
*params
,
470 const bt_value
**user_result
)
472 struct ctf_fs_component
*ctf_fs
= NULL
;
473 bt_query_status status
= BT_QUERY_STATUS_OK
;
474 bt_value
*result
= NULL
;
475 const bt_value
*paths_value
= NULL
;
481 if (!bt_value_is_map(params
)) {
482 BT_LOGE("Query parameters is not a map value object.");
483 status
= BT_QUERY_STATUS_INVALID_PARAMS
;
487 paths_value
= bt_value_map_borrow_entry_value_const(params
, "paths");
488 if (!validate_paths_parameter(paths_value
)) {
492 ctf_fs
= ctf_fs_component_create();
497 if (ctf_fs_component_create_ctf_fs_traces(NULL
, ctf_fs
, paths_value
)) {
501 result
= bt_value_array_create();
503 status
= BT_QUERY_STATUS_NOMEM
;
507 for (i
= 0; i
< ctf_fs
->traces
->len
; i
++) {
508 struct ctf_fs_trace
*trace
;
509 bt_value
*trace_info
;
510 bt_value_status status
;
512 trace
= g_ptr_array_index(ctf_fs
->traces
, i
);
515 trace_info
= bt_value_map_create();
517 BT_LOGE("Failed to create trace info map.");
521 ret
= populate_trace_info(trace
, trace_info
);
523 bt_value_put_ref(trace_info
);
527 status
= bt_value_array_append_element(result
, trace_info
);
528 bt_value_put_ref(trace_info
);
529 if (status
!= BT_VALUE_STATUS_OK
) {
537 BT_VALUE_PUT_REF_AND_RESET(result
);
541 status
= BT_QUERY_STATUS_ERROR
;
546 ctf_fs_destroy(ctf_fs
);
550 *user_result
= result
;