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