Values API: split into private and public APIs
[babeltrace.git] / plugins / ctf / fs-src / query.c
CommitLineData
04c0ba87
JG
1/*
2 * query.c
3 *
4 * Babeltrace CTF file system Reader Component queries
5 *
6 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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
24 * SOFTWARE.
25 */
26
27#include "query.h"
28#include <stdbool.h>
f6ccaed9 29#include <babeltrace/assert-internal.h>
04c0ba87
JG
30#include "metadata.h"
31#include "../common/metadata/decoder.h"
55314f2a 32#include <babeltrace/common-internal.h>
97ade20b 33#include <babeltrace/babeltrace-internal.h>
9d408fca 34#include <babeltrace/babeltrace.h>
97ade20b 35#include "fs.h"
55314f2a
JG
36
37#define BT_LOG_TAG "PLUGIN-CTF-FS-QUERY-SRC"
38#include "logging.h"
04c0ba87
JG
39
40#define METADATA_TEXT_SIG "/* CTF 1.8"
41
97ade20b
JG
42struct range {
43 int64_t begin_ns;
44 int64_t end_ns;
45 bool set;
46};
47
04c0ba87 48BT_HIDDEN
90157d89 49struct bt_component_class_query_method_return metadata_info_query(
c7eee084 50 struct bt_component_class *comp_class,
04c0ba87
JG
51 struct bt_value *params)
52{
90157d89 53 struct bt_component_class_query_method_return query_ret = {
c7eee084
PP
54 .result = NULL,
55 .status = BT_QUERY_STATUS_OK,
56 };
57
da91b29a 58 struct bt_private_value *result = NULL;
04c0ba87
JG
59 struct bt_value *path_value = NULL;
60 char *metadata_text = NULL;
61 FILE *metadata_fp = NULL;
62 GString *g_metadata_text = NULL;
63 int ret;
64 int bo;
65 const char *path;
66 bool is_packetized;
67
da91b29a
PP
68 result = bt_private_value_map_create();
69 if (!result) {
c7eee084 70 query_ret.status = BT_QUERY_STATUS_NOMEM;
04c0ba87
JG
71 goto error;
72 }
73
da91b29a 74 query_ret.result = bt_value_borrow_from_private(result);
f6ccaed9
PP
75 BT_ASSERT(params);
76
04c0ba87 77 if (!bt_value_is_map(params)) {
f7d0e29c 78 BT_LOGE_STR("Query parameters is not a map value object.");
c7eee084 79 query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
04c0ba87
JG
80 goto error;
81 }
82
07208d85 83 path_value = bt_value_map_borrow_entry_value(params, "path");
04c0ba87
JG
84 ret = bt_value_string_get(path_value, &path);
85 if (ret) {
f7d0e29c 86 BT_LOGE_STR("Cannot get `path` string parameter.");
c7eee084 87 query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
04c0ba87
JG
88 goto error;
89 }
90
f6ccaed9 91 BT_ASSERT(path);
04c0ba87
JG
92 metadata_fp = ctf_fs_metadata_open_file(path);
93 if (!metadata_fp) {
f7d0e29c 94 BT_LOGE("Cannot open trace metadata: path=\"%s\".", path);
04c0ba87
JG
95 goto error;
96 }
97
98 is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp,
99 &bo);
100
101 if (is_packetized) {
102 ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
103 metadata_fp, &metadata_text, bo);
104 if (ret) {
f7d0e29c
JG
105 BT_LOGE("Cannot decode packetized metadata file: path=\"%s\"",
106 path);
04c0ba87
JG
107 goto error;
108 }
109 } else {
110 long filesize;
111
677e1a21
MD
112 ret = fseek(metadata_fp, 0, SEEK_END);
113 if (ret) {
f7d0e29c
JG
114 BT_LOGE_ERRNO("Failed to seek to the end of the metadata file",
115 ": path=\"%s\"", path);
677e1a21
MD
116 goto error;
117 }
04c0ba87 118 filesize = ftell(metadata_fp);
677e1a21 119 if (filesize < 0) {
f7d0e29c
JG
120 BT_LOGE_ERRNO("Failed to get the current position in the metadata file",
121 ": path=\"%s\"", path);
677e1a21
MD
122 goto error;
123 }
04c0ba87
JG
124 rewind(metadata_fp);
125 metadata_text = malloc(filesize + 1);
126 if (!metadata_text) {
f7d0e29c 127 BT_LOGE_STR("Cannot allocate buffer for metadata text.");
04c0ba87
JG
128 goto error;
129 }
130
131 if (fread(metadata_text, filesize, 1, metadata_fp) != 1) {
f7d0e29c
JG
132 BT_LOGE_ERRNO("Cannot read metadata file", ": path=\"%s\"",
133 path);
04c0ba87
JG
134 goto error;
135 }
136
137 metadata_text[filesize] = '\0';
138 }
139
140 g_metadata_text = g_string_new(NULL);
141 if (!g_metadata_text) {
142 goto error;
143 }
144
145 if (strncmp(metadata_text, METADATA_TEXT_SIG,
146 sizeof(METADATA_TEXT_SIG) - 1) != 0) {
147 g_string_assign(g_metadata_text, METADATA_TEXT_SIG);
148 g_string_append(g_metadata_text, " */\n\n");
149 }
150
151 g_string_append(g_metadata_text, metadata_text);
152
da91b29a 153 ret = bt_private_value_map_insert_string_entry(result, "text",
04c0ba87
JG
154 g_metadata_text->str);
155 if (ret) {
f7d0e29c 156 BT_LOGE_STR("Cannot insert metadata text into query result.");
04c0ba87
JG
157 goto error;
158 }
159
da91b29a 160 ret = bt_private_value_map_insert_bool_entry(result, "is-packetized",
04c0ba87
JG
161 is_packetized);
162 if (ret) {
f7d0e29c 163 BT_LOGE_STR("Cannot insert \"is-packetized\" attribute into query result.");
04c0ba87
JG
164 goto error;
165 }
166
167 goto end;
168
169error:
da91b29a
PP
170 BT_OBJECT_PUT_REF_AND_RESET(result);
171 query_ret.result = NULL;
c7eee084
PP
172
173 if (query_ret.status >= 0) {
174 query_ret.status = BT_QUERY_STATUS_ERROR;
175 }
04c0ba87
JG
176
177end:
04c0ba87
JG
178 free(metadata_text);
179
180 if (g_metadata_text) {
181 g_string_free(g_metadata_text, TRUE);
182 }
183
184 if (metadata_fp) {
185 fclose(metadata_fp);
186 }
c7eee084
PP
187
188 return query_ret;
97ade20b 189}
9ec238a8 190
97ade20b 191static
da91b29a 192int add_range(struct bt_private_value *info, struct range *range,
97ade20b
JG
193 const char *range_name)
194{
195 int ret = 0;
196 enum bt_value_status status;
da91b29a 197 struct bt_private_value *range_map = NULL;
97ade20b
JG
198
199 if (!range->set) {
200 /* Not an error. */
201 goto end;
202 }
203
da91b29a 204 range_map = bt_private_value_map_create();
97ade20b
JG
205 if (!range_map) {
206 ret = -1;
207 goto end;
208 }
209
da91b29a 210 status = bt_private_value_map_insert_integer_entry(range_map, "begin",
97ade20b
JG
211 range->begin_ns);
212 if (status != BT_VALUE_STATUS_OK) {
213 ret = -1;
214 goto end;
215 }
216
da91b29a 217 status = bt_private_value_map_insert_integer_entry(range_map, "end",
97ade20b
JG
218 range->end_ns);
219 if (status != BT_VALUE_STATUS_OK) {
220 ret = -1;
221 goto end;
222 }
223
da91b29a
PP
224 status = bt_private_value_map_insert_entry(info, range_name,
225 bt_value_borrow_from_private(range_map));
97ade20b
JG
226 if (status != BT_VALUE_STATUS_OK) {
227 ret = -1;
228 goto end;
229 }
da91b29a 230
97ade20b 231end:
65300d60 232 bt_object_put_ref(range_map);
97ade20b
JG
233 return ret;
234}
235
236static
da91b29a 237int add_stream_ids(struct bt_private_value *info, struct bt_stream *stream)
97ade20b
JG
238{
239 int ret = 0;
240 int64_t stream_class_id, stream_instance_id;
241 enum bt_value_status status;
50842bdc 242 struct bt_stream_class *stream_class = NULL;
97ade20b 243
50842bdc 244 stream_instance_id = bt_stream_get_id(stream);
97ade20b 245 if (stream_instance_id != -1) {
da91b29a 246 status = bt_private_value_map_insert_integer_entry(info, "id",
97ade20b
JG
247 stream_instance_id);
248 if (status != BT_VALUE_STATUS_OK) {
249 ret = -1;
250 goto end;
251 }
252 }
253
0b29603d 254 stream_class = bt_stream_borrow_class(stream);
97ade20b
JG
255 if (!stream_class) {
256 ret = -1;
257 goto end;
258 }
259
50842bdc 260 stream_class_id = bt_stream_class_get_id(stream_class);
97ade20b
JG
261 if (stream_class_id == -1) {
262 ret = -1;
263 goto end;
264 }
265
da91b29a 266 status = bt_private_value_map_insert_integer_entry(info, "class-id", stream_class_id);
97ade20b
JG
267 if (status != BT_VALUE_STATUS_OK) {
268 ret = -1;
269 goto end;
270 }
0b29603d 271
97ade20b 272end:
97ade20b
JG
273 return ret;
274}
275
276static
277int populate_stream_info(struct ctf_fs_ds_file_group *group,
da91b29a 278 struct bt_private_value *group_info,
97ade20b
JG
279 struct range *stream_range)
280{
281 int ret = 0;
282 size_t file_idx;
283 enum bt_value_status status;
da91b29a 284 struct bt_private_value *file_paths;
97ade20b
JG
285
286 stream_range->begin_ns = INT64_MAX;
287 stream_range->end_ns = 0;
288
da91b29a 289 file_paths = bt_private_value_array_create();
97ade20b
JG
290 if (!file_paths) {
291 ret = -1;
292 goto end;
293 }
294
295 for (file_idx = 0; file_idx < group->ds_file_infos->len; file_idx++) {
296 int64_t file_begin_epoch, file_end_epoch;
297 struct ctf_fs_ds_file_info *info =
298 g_ptr_array_index(group->ds_file_infos,
299 file_idx);
300
301 if (!info->index || info->index->entries->len == 0) {
302 BT_LOGW("Cannot determine range of unindexed stream file \'%s\'",
303 info->path->str);
304 ret = -1;
305 goto end;
306 }
307
da91b29a 308 status = bt_private_value_array_append_string_element(file_paths,
97ade20b
JG
309 info->path->str);
310 if (status != BT_VALUE_STATUS_OK) {
311 ret = -1;
312 goto end;
313 }
314
315 /*
316 * file range is from timestamp_begin of the first entry to the
317 * timestamp_end of the last entry.
318 */
319 file_begin_epoch = ((struct ctf_fs_ds_index_entry *) &g_array_index(info->index->entries,
320 struct ctf_fs_ds_index_entry, 0))->timestamp_begin_ns;
321 file_end_epoch = ((struct ctf_fs_ds_index_entry *) &g_array_index(info->index->entries,
322 struct ctf_fs_ds_index_entry, info->index->entries->len - 1))->timestamp_end_ns;
323
324 stream_range->begin_ns = min(stream_range->begin_ns, file_begin_epoch);
325 stream_range->end_ns = max(stream_range->end_ns, file_end_epoch);
326 stream_range->set = true;
327 }
328
329 if (stream_range->set) {
330 ret = add_range(group_info, stream_range, "range-ns");
331 if (ret) {
332 goto end;
333 }
334 }
335
da91b29a
PP
336 status = bt_private_value_map_insert_entry(group_info, "paths",
337 bt_value_borrow_from_private(file_paths));
97ade20b
JG
338 if (status != BT_VALUE_STATUS_OK) {
339 ret = -1;
340 goto end;
341 }
342
343 ret = add_stream_ids(group_info, group->stream);
344 if (ret) {
345 goto end;
346 }
347end:
65300d60 348 bt_object_put_ref(file_paths);
97ade20b
JG
349 return ret;
350}
351
352static
353int populate_trace_info(const char *trace_path, const char *trace_name,
da91b29a 354 struct bt_private_value *trace_info)
97ade20b
JG
355{
356 int ret = 0;
357 size_t group_idx;
358 struct ctf_fs_trace *trace = NULL;
359 enum bt_value_status status;
da91b29a 360 struct bt_private_value *file_groups;
97ade20b
JG
361 struct range trace_range = {
362 .begin_ns = INT64_MAX,
363 .end_ns = 0,
364 .set = false,
365 };
366 struct range trace_intersection = {
367 .begin_ns = 0,
368 .end_ns = INT64_MAX,
369 .set = false,
370 };
371
da91b29a 372 file_groups = bt_private_value_array_create();
97ade20b
JG
373 if (!file_groups) {
374 goto end;
375 }
376
da91b29a
PP
377 status = bt_private_value_map_insert_string_entry(trace_info, "name",
378 trace_name);
97ade20b
JG
379 if (status != BT_VALUE_STATUS_OK) {
380 ret = -1;
381 goto end;
382 }
da91b29a 383 status = bt_private_value_map_insert_string_entry(trace_info, "path",
97ade20b
JG
384 trace_path);
385 if (status != BT_VALUE_STATUS_OK) {
386 ret = -1;
387 goto end;
388 }
389
5c563278 390 trace = ctf_fs_trace_create(trace_path, trace_name, NULL, NULL);
97ade20b
JG
391 if (!trace) {
392 BT_LOGE("Failed to create fs trace at \'%s\'", trace_path);
393 ret = -1;
394 goto end;
395 }
396
f6ccaed9 397 BT_ASSERT(trace->ds_file_groups);
97ade20b
JG
398 /* Add trace range info only if it contains streams. */
399 if (trace->ds_file_groups->len == 0) {
400 ret = -1;
401 goto end;
402 }
403
404 /* Find range of all stream groups, and of the trace. */
405 for (group_idx = 0; group_idx < trace->ds_file_groups->len;
406 group_idx++) {
da91b29a 407 struct bt_private_value *group_info;
97ade20b
JG
408 struct range group_range = { .set = false };
409 struct ctf_fs_ds_file_group *group = g_ptr_array_index(
410 trace->ds_file_groups, group_idx);
411
da91b29a 412 group_info = bt_private_value_map_create();
97ade20b
JG
413 if (!group_info) {
414 ret = -1;
415 goto end;
416 }
417
418 ret = populate_stream_info(group, group_info, &group_range);
419 if (ret) {
65300d60 420 bt_object_put_ref(group_info);
97ade20b
JG
421 goto end;
422 }
423
424 if (group_range.set) {
425 trace_range.begin_ns = min(trace_range.begin_ns,
426 group_range.begin_ns);
427 trace_range.end_ns = max(trace_range.end_ns,
428 group_range.end_ns);
429 trace_range.set = true;
430
431 trace_intersection.begin_ns = max(trace_intersection.begin_ns,
432 group_range.begin_ns);
433 trace_intersection.end_ns = min(trace_intersection.end_ns,
434 group_range.end_ns);
435 trace_intersection.set = true;
da91b29a
PP
436 status = bt_private_value_array_append_element(
437 file_groups,
438 bt_value_borrow_from_private(group_info));
65300d60 439 bt_object_put_ref(group_info);
97ade20b
JG
440 if (status != BT_VALUE_STATUS_OK) {
441 goto end;
442 }
443 }
444 }
445
446 ret = add_range(trace_info, &trace_range, "range-ns");
447 if (ret) {
448 goto end;
449 }
c6daf8b2
PP
450
451 if (trace_intersection.begin_ns < trace_intersection.end_ns) {
452 ret = add_range(trace_info, &trace_intersection,
453 "intersection-range-ns");
454 if (ret) {
455 goto end;
456 }
97ade20b
JG
457 }
458
da91b29a
PP
459 status = bt_private_value_map_insert_entry(trace_info, "streams",
460 bt_value_borrow_from_private(file_groups));
65300d60 461 BT_OBJECT_PUT_REF_AND_RESET(file_groups);
97ade20b
JG
462 if (status != BT_VALUE_STATUS_OK) {
463 ret = -1;
464 goto end;
465 }
466
467end:
65300d60 468 bt_object_put_ref(file_groups);
97ade20b
JG
469 ctf_fs_trace_destroy(trace);
470 return ret;
471}
472
473BT_HIDDEN
90157d89 474struct bt_component_class_query_method_return trace_info_query(
c7eee084 475 struct bt_component_class *comp_class,
97ade20b
JG
476 struct bt_value *params)
477{
90157d89 478 struct bt_component_class_query_method_return query_ret = {
c7eee084
PP
479 .result = NULL,
480 .status = BT_QUERY_STATUS_OK,
481 };
482
da91b29a 483 struct bt_private_value *result = NULL;
97ade20b
JG
484 struct bt_value *path_value = NULL;
485 int ret = 0;
486 const char *path = NULL;
487 GList *trace_paths = NULL;
488 GList *trace_names = NULL;
489 GList *tp_node = NULL;
490 GList *tn_node = NULL;
491 GString *normalized_path = NULL;
492
f6ccaed9
PP
493 BT_ASSERT(params);
494
97ade20b
JG
495 if (!bt_value_is_map(params)) {
496 BT_LOGE("Query parameters is not a map value object.");
c7eee084 497 query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
97ade20b
JG
498 goto error;
499 }
500
07208d85 501 path_value = bt_value_map_borrow_entry_value(params, "path");
97ade20b
JG
502 ret = bt_value_string_get(path_value, &path);
503 if (ret) {
504 BT_LOGE("Cannot get `path` string parameter.");
c7eee084 505 query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
97ade20b
JG
506 goto error;
507 }
508
509 normalized_path = bt_common_normalize_path(path, NULL);
510 if (!normalized_path) {
511 BT_LOGE("Failed to normalize path: `%s`.", path);
512 goto error;
513 }
f6ccaed9 514 BT_ASSERT(path);
97ade20b
JG
515
516 ret = ctf_fs_find_traces(&trace_paths, normalized_path->str);
517 if (ret) {
518 goto error;
519 }
520
521 trace_names = ctf_fs_create_trace_names(trace_paths,
522 normalized_path->str);
523 if (!trace_names) {
524 BT_LOGE("Cannot create trace names from trace paths.");
525 goto error;
526 }
527
da91b29a
PP
528 result = bt_private_value_array_create();
529 if (!result) {
c7eee084 530 query_ret.status = BT_QUERY_STATUS_NOMEM;
97ade20b
JG
531 goto error;
532 }
533
da91b29a
PP
534 query_ret.result = bt_value_borrow_from_private(result);
535
97ade20b
JG
536 /* Iterates over both trace paths and names simultaneously. */
537 for (tp_node = trace_paths, tn_node = trace_names; tp_node;
538 tp_node = g_list_next(tp_node),
539 tn_node = g_list_next(tn_node)) {
540 GString *trace_path = tp_node->data;
541 GString *trace_name = tn_node->data;
542 enum bt_value_status status;
da91b29a 543 struct bt_private_value *trace_info;
97ade20b 544
da91b29a 545 trace_info = bt_private_value_map_create();
97ade20b
JG
546 if (!trace_info) {
547 BT_LOGE("Failed to create trace info map.");
548 goto error;
549 }
550
551 ret = populate_trace_info(trace_path->str, trace_name->str,
552 trace_info);
553 if (ret) {
65300d60 554 bt_object_put_ref(trace_info);
97ade20b
JG
555 goto error;
556 }
557
da91b29a
PP
558 status = bt_private_value_array_append_element(result,
559 bt_value_borrow_from_private(trace_info));
65300d60 560 bt_object_put_ref(trace_info);
97ade20b
JG
561 if (status != BT_VALUE_STATUS_OK) {
562 goto error;
563 }
564 }
565
566 goto end;
567
568error:
da91b29a
PP
569 BT_OBJECT_PUT_REF_AND_RESET(result);
570 query_ret.result = NULL;
c7eee084
PP
571
572 if (query_ret.status >= 0) {
573 query_ret.status = BT_QUERY_STATUS_ERROR;
574 }
575
97ade20b
JG
576end:
577 if (normalized_path) {
578 g_string_free(normalized_path, TRUE);
579 }
580 if (trace_paths) {
581 for (tp_node = trace_paths; tp_node; tp_node = g_list_next(tp_node)) {
582 if (tp_node->data) {
583 g_string_free(tp_node->data, TRUE);
584 }
585 }
586 g_list_free(trace_paths);
587 }
588 if (trace_names) {
589 for (tn_node = trace_names; tn_node; tn_node = g_list_next(tn_node)) {
590 if (tn_node->data) {
591 g_string_free(tn_node->data, TRUE);
592 }
593 }
594 g_list_free(trace_names);
595 }
596 /* "path" becomes invalid with the release of path_value. */
c7eee084 597 return query_ret;
04c0ba87 598}
This page took 0.055181 seconds and 4 git commands to generate.