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