src.ctf.fs: remove ctf_fs_file_create
[deliverable/babeltrace.git] / src / plugins / ctf / fs-src / fs.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2015-2017 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 *
7 * Babeltrace CTF file system Reader Component
8 */
9
10 #define BT_CLOG_CFG logCfg
11 #define BT_LOG_TAG "PLUGIN/SRC.CTF.FS"
12
13 #include "common/common.h"
14 #include <babeltrace2/babeltrace.h>
15 #include "common/uuid.h"
16 #include <glib.h>
17 #include "common/assert.h"
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include "fs.hpp"
21 #include "metadata.hpp"
22 #include "data-stream-file.hpp"
23 #include "file.hpp"
24 #include "../common/src/metadata/tsdl/decoder.hpp"
25 #include "../common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp"
26 #include "../common/src/msg-iter/msg-iter.hpp"
27 #include "query.hpp"
28 #include "plugins/common/param-validation/param-validation.h"
29 #include "cpp-common/cfg-logging.hpp"
30 #include "cpp-common/cfg-logging-error-reporting.hpp"
31 #include "cpp-common/exc.hpp"
32 #include "cpp-common/make-unique.hpp"
33 #include <vector>
34 #include <sstream>
35
36 struct tracer_info
37 {
38 const char *name;
39 int64_t major;
40 int64_t minor;
41 int64_t patch;
42 };
43
44 static bt_message_iterator_class_next_method_status
45 ctf_fs_iterator_next_one(struct ctf_fs_msg_iter_data *msg_iter_data, const bt_message **out_msg)
46 {
47 bt_message_iterator_class_next_method_status status;
48 enum ctf_msg_iter_status msg_iter_status;
49 const bt2_common::LogCfg& logCfg = msg_iter_data->logCfg;
50
51 msg_iter_status = ctf_msg_iter_get_next_message(msg_iter_data->msg_iter.get(), out_msg);
52
53 switch (msg_iter_status) {
54 case CTF_MSG_ITER_STATUS_OK:
55 /* Cool, message has been written to *out_msg. */
56 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
57 break;
58
59 case CTF_MSG_ITER_STATUS_EOF:
60 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
61 break;
62
63 case CTF_MSG_ITER_STATUS_AGAIN:
64 /*
65 * Should not make it this far as this is
66 * medium-specific; there is nothing for the user to do
67 * and it should have been handled upstream.
68 */
69 bt_common_abort();
70
71 case CTF_MSG_ITER_STATUS_ERROR:
72 BT_CLOGE_APPEND_CAUSE("Failed to get next message from CTF message iterator.");
73 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
74 break;
75
76 case CTF_MSG_ITER_STATUS_MEMORY_ERROR:
77 BT_CLOGE_APPEND_CAUSE("Failed to get next message from CTF message iterator.");
78 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
79 break;
80
81 default:
82 bt_common_abort();
83 }
84
85 return status;
86 }
87
88 BT_HIDDEN
89 bt_message_iterator_class_next_method_status
90 ctf_fs_iterator_next(bt_self_message_iterator *iterator, bt_message_array_const msgs,
91 uint64_t capacity, uint64_t *count)
92 {
93 struct ctf_fs_msg_iter_data *msg_iter_data =
94 (struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(iterator);
95 const bt2_common::LogCfg& logCfg = msg_iter_data->logCfg;
96
97 try {
98 bt_message_iterator_class_next_method_status status;
99 uint64_t i = 0;
100
101 if (G_UNLIKELY(msg_iter_data->next_saved_error)) {
102 /*
103 * Last time we were called, we hit an error but had some
104 * messages to deliver, so we stashed the error here. Return
105 * it now.
106 */
107 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(msg_iter_data->next_saved_error);
108 status = msg_iter_data->next_saved_status;
109 goto end;
110 }
111
112 do {
113 status = ctf_fs_iterator_next_one(msg_iter_data, &msgs[i]);
114 if (status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK) {
115 i++;
116 }
117 } while (i < capacity && status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK);
118
119 if (i > 0) {
120 /*
121 * Even if ctf_fs_iterator_next_one() returned something
122 * else than BT_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK, we
123 * accumulated message objects in the output
124 * message array, so we need to return
125 * BT_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK so that they are
126 * transfered to downstream. This other status occurs
127 * again the next time muxer_msg_iter_do_next() is
128 * called, possibly without any accumulated
129 * message, in which case we'll return it.
130 */
131 if (status < 0) {
132 /*
133 * Save this error for the next _next call. Assume that
134 * this component always appends error causes when
135 * returning an error status code, which will cause the
136 * current thread error to be non-NULL.
137 */
138 msg_iter_data->next_saved_error = bt_current_thread_take_error();
139 BT_ASSERT(msg_iter_data->next_saved_error);
140 msg_iter_data->next_saved_status = status;
141 }
142
143 *count = i;
144 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
145 }
146
147 end:
148 return status;
149 } catch (const std::bad_alloc&) {
150 return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
151 } catch (const bt2_common::Error&) {
152 BT_CLOGE_APPEND_CAUSE("Failed to fetch next messages");
153 return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
154 }
155 }
156
157 BT_HIDDEN
158 bt_message_iterator_class_seek_beginning_method_status
159 ctf_fs_iterator_seek_beginning(bt_self_message_iterator *it)
160 {
161 struct ctf_fs_msg_iter_data *msg_iter_data =
162 (struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(it);
163
164 BT_ASSERT(msg_iter_data);
165
166 const bt2_common::LogCfg& logCfg = msg_iter_data->logCfg;
167
168 try {
169 ctf_msg_iter_reset(msg_iter_data->msg_iter.get());
170 ctf_fs_ds_group_medops_data_reset(msg_iter_data->msg_iter_medops_data.get());
171
172 return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_OK;
173 } catch (const std::bad_alloc&) {
174 return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_MEMORY_ERROR;
175 } catch (const bt2_common::Error&) {
176 BT_CLOGE_APPEND_CAUSE("Failed to seek beginning");
177 return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_ERROR;
178 }
179 }
180
181 BT_HIDDEN
182 void ctf_fs_iterator_finalize(bt_self_message_iterator *it)
183 {
184 ctf_fs_msg_iter_data::UP {
185 ((struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(it))};
186 }
187
188 static bt_message_iterator_class_initialize_method_status
189 ctf_msg_iter_medium_status_to_msg_iter_initialize_status(enum ctf_msg_iter_medium_status status)
190 {
191 switch (status) {
192 case CTF_MSG_ITER_MEDIUM_STATUS_EOF:
193 case CTF_MSG_ITER_MEDIUM_STATUS_AGAIN:
194 case CTF_MSG_ITER_MEDIUM_STATUS_ERROR:
195 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
196 case CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR:
197 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
198 case CTF_MSG_ITER_MEDIUM_STATUS_OK:
199 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
200 }
201
202 bt_common_abort();
203 }
204
205 BT_HIDDEN
206 bt_message_iterator_class_initialize_method_status
207 ctf_fs_iterator_init(bt_self_message_iterator *self_msg_iter,
208 bt_self_message_iterator_configuration *config,
209 bt_self_component_port_output *self_port)
210 {
211 bt_self_component_port *self_comp_port =
212 bt_self_component_port_output_as_self_component_port(self_port);
213 ctf_fs_port_data *port_data =
214 (ctf_fs_port_data *) bt_self_component_port_get_data(self_comp_port);
215 BT_ASSERT(port_data);
216
217 bt2_common::LogCfg logCfg {port_data->ctf_fs->logCfg.logLevel(), *self_msg_iter};
218
219 try {
220 bt_message_iterator_class_initialize_method_status status;
221 enum ctf_msg_iter_medium_status medium_status;
222
223 ctf_fs_msg_iter_data::UP msg_iter_data =
224 bt2_common::makeUnique<ctf_fs_msg_iter_data>(logCfg);
225
226 msg_iter_data->self_msg_iter = self_msg_iter;
227 msg_iter_data->ds_file_group = port_data->ds_file_group;
228
229 medium_status =
230 ctf_fs_ds_group_medops_data_create(msg_iter_data->ds_file_group, self_msg_iter, logCfg,
231 msg_iter_data->msg_iter_medops_data);
232 BT_ASSERT(medium_status == CTF_MSG_ITER_MEDIUM_STATUS_OK ||
233 medium_status == CTF_MSG_ITER_MEDIUM_STATUS_ERROR ||
234 medium_status == CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR);
235 if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
236 BT_CLOGE_APPEND_CAUSE("Failed to create ctf_fs_ds_group_medops");
237 status = ctf_msg_iter_medium_status_to_msg_iter_initialize_status(medium_status);
238 goto error;
239 }
240
241 msg_iter_data->msg_iter = ctf_msg_iter_create(
242 msg_iter_data->ds_file_group->ctf_fs_trace->metadata->tc,
243 bt_common_get_page_size(logCfg.logLevel()) * 8, ctf_fs_ds_group_medops,
244 msg_iter_data->msg_iter_medops_data.get(), self_msg_iter, logCfg);
245 if (!msg_iter_data->msg_iter) {
246 BT_CLOGE_APPEND_CAUSE("Cannot create a CTF message iterator.");
247 status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
248 goto error;
249 }
250
251 /*
252 * This iterator can seek forward if its stream class has a default
253 * clock class.
254 */
255 if (msg_iter_data->ds_file_group->sc->default_clock_class) {
256 bt_self_message_iterator_configuration_set_can_seek_forward(config, true);
257 }
258
259 bt_self_message_iterator_set_data(self_msg_iter, msg_iter_data.release());
260
261 status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
262 goto end;
263
264 error:
265 bt_self_message_iterator_set_data(self_msg_iter, NULL);
266
267 end:
268 return status;
269 } catch (const std::bad_alloc&) {
270 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
271 } catch (const bt2_common::Error&) {
272 BT_CLOGE_APPEND_CAUSE("Failed to initialize iterator");
273 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
274 }
275 }
276
277 ctf_fs_component::UP ctf_fs_component_create(const bt2_common::LogCfg& logCfg)
278 {
279 return ctf_fs_component::UP {new ctf_fs_component {logCfg}};
280 }
281
282 void ctf_fs_finalize(bt_self_component_source *component)
283 {
284 ctf_fs_component::UP {(ctf_fs_component *) bt_self_component_get_data(
285 bt_self_component_source_as_self_component(component))};
286 }
287
288 std::string ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group)
289 {
290 std::stringstream name;
291
292 /*
293 * The unique port name is generated by concatenating unique identifiers
294 * for:
295 *
296 * - the trace
297 * - the stream class
298 * - the stream
299 */
300
301 /* For the trace, use the uuid if present, else the path. */
302 if (ds_file_group->ctf_fs_trace->metadata->tc->is_uuid_set) {
303 char uuid_str[BT_UUID_STR_LEN + 1];
304
305 bt_uuid_to_str(ds_file_group->ctf_fs_trace->metadata->tc->uuid, uuid_str);
306 name << uuid_str;
307 } else {
308 name << ds_file_group->ctf_fs_trace->path;
309 }
310
311 /*
312 * For the stream class, use the id if present. We can omit this field
313 * otherwise, as there will only be a single stream class.
314 */
315 if (ds_file_group->sc->id != UINT64_C(-1)) {
316 name << " | " << ds_file_group->sc->id;
317 }
318
319 /* For the stream, use the id if present, else, use the path. */
320 if (ds_file_group->stream_id != UINT64_C(-1)) {
321 name << " | " << ds_file_group->stream_id;
322 } else {
323 BT_ASSERT(ds_file_group->ds_file_infos.size() == 1);
324 const ctf_fs_ds_file_info& ds_file_info = *ds_file_group->ds_file_infos[0];
325 name << " | " << ds_file_info.path;
326 }
327
328 return name.str();
329 }
330
331 static int create_one_port_for_trace(struct ctf_fs_component *ctf_fs,
332 struct ctf_fs_trace *ctf_fs_trace,
333 struct ctf_fs_ds_file_group *ds_file_group,
334 bt_self_component_source *self_comp_src)
335 {
336 int ret = 0;
337 ctf_fs_port_data::UP port_data;
338 const bt2_common::LogCfg& logCfg = ctf_fs->logCfg;
339
340 std::string port_name = ctf_fs_make_port_name(ds_file_group);
341 BT_CLOGI("Creating one port named `%s`", port_name.c_str());
342
343 /* Create output port for this file */
344 port_data = bt2_common::makeUnique<ctf_fs_port_data>();
345 port_data->ctf_fs = ctf_fs;
346 port_data->ds_file_group = ds_file_group;
347 ret = bt_self_component_source_add_output_port(self_comp_src, port_name.c_str(),
348 port_data.get(), NULL);
349 if (ret) {
350 goto error;
351 }
352
353 ctf_fs->port_data.emplace_back(std::move(port_data));
354 goto end;
355
356 error:
357 ret = -1;
358
359 end:
360 return ret;
361 }
362
363 static int create_ports_for_trace(struct ctf_fs_component *ctf_fs,
364 struct ctf_fs_trace *ctf_fs_trace,
365 bt_self_component_source *self_comp_src)
366 {
367 int ret = 0;
368 const bt2_common::LogCfg& logCfg = ctf_fs->logCfg;
369
370 /* Create one output port for each stream file group */
371 for (ctf_fs_ds_file_group::UP& ds_file_group : ctf_fs_trace->ds_file_groups) {
372 ret = create_one_port_for_trace(ctf_fs, ctf_fs_trace, ds_file_group.get(), self_comp_src);
373 if (ret) {
374 BT_CLOGE_APPEND_CAUSE("Cannot create output port.");
375 goto end;
376 }
377 }
378
379 end:
380 return ret;
381 }
382
383 /*
384 * Insert ds_file_info in ds_file_group's list of ds_file_infos at the right
385 * place to keep it sorted.
386 */
387
388 static void ds_file_group_insert_ds_file_info_sorted(struct ctf_fs_ds_file_group *ds_file_group,
389 ctf_fs_ds_file_info::UP ds_file_info)
390 {
391 /* Find the spot where to insert this ds_file_info. */
392 auto it = ds_file_group->ds_file_infos.begin();
393
394 for (; it != ds_file_group->ds_file_infos.end(); ++it) {
395 const ctf_fs_ds_file_info& other_ds_file_info = **it;
396
397 if (ds_file_info->begin_ns < other_ds_file_info.begin_ns) {
398 break;
399 }
400 }
401
402 ds_file_group->ds_file_infos.insert(it, std::move(ds_file_info));
403 }
404
405 static bool ds_index_entries_equal(const struct ctf_fs_ds_index_entry *left,
406 const struct ctf_fs_ds_index_entry *right)
407 {
408 if (left->packetSize != right->packetSize) {
409 return false;
410 }
411
412 if (left->timestamp_begin != right->timestamp_begin) {
413 return false;
414 }
415
416 if (left->timestamp_end != right->timestamp_end) {
417 return false;
418 }
419
420 if (left->packet_seq_num != right->packet_seq_num) {
421 return false;
422 }
423
424 return true;
425 }
426
427 /*
428 * Insert `entry` into `index`, without duplication.
429 *
430 * The entry is inserted only if there isn't an identical entry already.
431 *
432 * In any case, the ownership of `entry` is transferred to this function. So if
433 * the entry is not inserted, it is freed.
434 */
435
436 static void ds_index_insert_ds_index_entry_sorted(struct ctf_fs_ds_index *index,
437 ctf_fs_ds_index_entry::UP entry)
438 {
439 /* Find the spot where to insert this index entry. */
440 auto otherEntry = index->entries.begin();
441 for (; otherEntry != index->entries.end(); ++otherEntry) {
442 if (entry->timestamp_begin_ns <= (*otherEntry)->timestamp_begin_ns) {
443 break;
444 }
445 }
446
447 /*
448 * Insert the entry only if a duplicate doesn't already exist.
449 *
450 * There can be duplicate packets if reading multiple overlapping
451 * snapshots of the same trace. We then want the index to contain
452 * a reference to only one copy of that packet.
453 */
454 if (otherEntry == index->entries.end() ||
455 !ds_index_entries_equal(entry.get(), otherEntry->get())) {
456 index->entries.insert(otherEntry, std::move(entry));
457 }
458 }
459
460 static void merge_ctf_fs_ds_indexes(struct ctf_fs_ds_index *dest, ctf_fs_ds_index::UP src)
461 {
462 for (ctf_fs_ds_index_entry::UP& entry : src->entries) {
463 ds_index_insert_ds_index_entry_sorted(dest, std::move(entry));
464 }
465 }
466
467 static int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace, const char *path)
468 {
469 int64_t stream_instance_id = -1;
470 int64_t begin_ns = -1;
471 struct ctf_fs_ds_file_group *ds_file_group = NULL;
472 ctf_fs_ds_file_group::UP new_ds_file_group;
473 int ret;
474 ctf_fs_ds_file_info::UP ds_file_info;
475 ctf_fs_ds_index::UP index;
476 ctf_msg_iter_up msg_iter;
477 struct ctf_stream_class *sc = NULL;
478 struct ctf_msg_iter_packet_properties props;
479 const bt2_common::LogCfg& logCfg = ctf_fs_trace->logCfg;
480
481 /*
482 * Create a temporary ds_file to read some properties about the data
483 * stream file.
484 */
485 ctf_fs_ds_file::UP ds_file = ctf_fs_ds_file_create(ctf_fs_trace, nonstd::nullopt, path, logCfg);
486 if (!ds_file) {
487 goto error;
488 }
489
490 /* Create a temporary iterator to read the ds_file. */
491 msg_iter = ctf_msg_iter_create(ctf_fs_trace->metadata->tc,
492 bt_common_get_page_size(logCfg.logLevel()) * 8,
493 ctf_fs_ds_file_medops, ds_file.get(), nullptr, logCfg);
494 if (!msg_iter) {
495 BT_CLOGE_STR("Cannot create a CTF message iterator.");
496 goto error;
497 }
498
499 ctf_msg_iter_set_dry_run(msg_iter.get(), true);
500
501 ret = ctf_msg_iter_get_packet_properties(msg_iter.get(), &props);
502 if (ret) {
503 BT_CLOGE_APPEND_CAUSE(
504 "Cannot get stream file's first packet's header and context fields (`%s`).", path);
505 goto error;
506 }
507
508 sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props.stream_class_id);
509 BT_ASSERT(sc);
510 stream_instance_id = props.data_stream_id;
511
512 if (props.snapshots.beginning_clock != UINT64_C(-1)) {
513 BT_ASSERT(sc->default_clock_class);
514 ret = bt_util_clock_cycles_to_ns_from_origin(
515 props.snapshots.beginning_clock, sc->default_clock_class->frequency,
516 sc->default_clock_class->offset_seconds, sc->default_clock_class->offset_cycles,
517 &begin_ns);
518 if (ret) {
519 BT_CLOGE_APPEND_CAUSE("Cannot convert clock cycles to nanoseconds from origin (`%s`).",
520 path);
521 goto error;
522 }
523 }
524
525 ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns);
526 if (!ds_file_info) {
527 goto error;
528 }
529
530 index = ctf_fs_ds_file_build_index(ds_file.get(), ds_file_info.get(), msg_iter.get());
531 if (!index) {
532 BT_CLOGE_APPEND_CAUSE("Failed to index CTF stream file \'%s\'",
533 ds_file->file->path.c_str());
534 goto error;
535 }
536
537 if (begin_ns == -1) {
538 /*
539 * No beginning timestamp to sort the stream files
540 * within a stream file group, so consider that this
541 * file must be the only one within its group.
542 */
543 stream_instance_id = -1;
544 }
545
546 if (stream_instance_id == -1) {
547 /*
548 * No stream instance ID or no beginning timestamp:
549 * create a unique stream file group for this stream
550 * file because, even if there's a stream instance ID,
551 * there's no timestamp to order the file within its
552 * group.
553 */
554 new_ds_file_group =
555 ctf_fs_ds_file_group_create(ctf_fs_trace, sc, UINT64_C(-1), std::move(index));
556
557 if (!new_ds_file_group) {
558 goto error;
559 }
560
561 ds_file_group_insert_ds_file_info_sorted(new_ds_file_group.get(), std::move(ds_file_info));
562 ctf_fs_trace->ds_file_groups.emplace_back(std::move(new_ds_file_group));
563 goto end;
564 }
565
566 BT_ASSERT(stream_instance_id != -1);
567 BT_ASSERT(begin_ns != -1);
568
569 /* Find an existing stream file group with this ID */
570 for (ctf_fs_ds_file_group::UP& candidate : ctf_fs_trace->ds_file_groups) {
571 if (candidate->sc == sc && candidate->stream_id == stream_instance_id) {
572 ds_file_group = candidate.get();
573 break;
574 }
575 }
576
577 if (!ds_file_group) {
578 new_ds_file_group =
579 ctf_fs_ds_file_group_create(ctf_fs_trace, sc, stream_instance_id, std::move(index));
580 if (!new_ds_file_group) {
581 goto error;
582 }
583
584 ds_file_group = new_ds_file_group.get();
585 ctf_fs_trace->ds_file_groups.emplace_back(std::move(new_ds_file_group));
586 } else {
587 merge_ctf_fs_ds_indexes(ds_file_group->index.get(), std::move(index));
588 }
589
590 ds_file_group_insert_ds_file_info_sorted(ds_file_group, std::move(ds_file_info));
591
592 goto end;
593
594 error:
595 ret = -1;
596
597 end:
598 return ret;
599 }
600
601 static int create_ds_file_groups(struct ctf_fs_trace *ctf_fs_trace)
602 {
603 int ret = 0;
604 const char *basename;
605 GError *error = NULL;
606 const bt2_common::LogCfg& logCfg = ctf_fs_trace->logCfg;
607
608 /* Check each file in the path directory, except specific ones */
609 bt2_common::GDirUP dir {g_dir_open(ctf_fs_trace->path.c_str(), 0, &error)};
610 if (!dir) {
611 BT_CLOGE_APPEND_CAUSE("Cannot open directory `%s`: %s (code %d)",
612 ctf_fs_trace->path.c_str(), error->message, error->code);
613 goto error;
614 }
615
616 while ((basename = g_dir_read_name(dir.get()))) {
617 if (strcmp(basename, CTF_FS_METADATA_FILENAME) == 0) {
618 /* Ignore the metadata stream. */
619 BT_CLOGI("Ignoring metadata file `%s" G_DIR_SEPARATOR_S "%s`",
620 ctf_fs_trace->path.c_str(), basename);
621 continue;
622 }
623
624 if (basename[0] == '.') {
625 BT_CLOGI("Ignoring hidden file `%s" G_DIR_SEPARATOR_S "%s`", ctf_fs_trace->path.c_str(),
626 basename);
627 continue;
628 }
629
630 /* Create the file. */
631 ctf_fs_file::UP file = bt2_common::makeUnique<ctf_fs_file>(logCfg);
632
633 /* Create full path string. */
634 file->path = ctf_fs_trace->path;
635 file->path += G_DIR_SEPARATOR;
636 file->path += basename;
637
638 if (!g_file_test(file->path.c_str(), G_FILE_TEST_IS_REGULAR)) {
639 BT_CLOGI("Ignoring non-regular file `%s`", file->path.c_str());
640 continue;
641 }
642
643 ret = ctf_fs_file_open(file.get(), "rb");
644 if (ret) {
645 BT_CLOGE_APPEND_CAUSE("Cannot open stream file `%s`", file->path.c_str());
646 goto error;
647 }
648
649 if (file->size == 0) {
650 /* Skip empty stream. */
651 BT_CLOGI("Ignoring empty file `%s`", file->path.c_str());
652 continue;
653 }
654
655 ret = add_ds_file_to_ds_file_group(ctf_fs_trace, file->path.c_str());
656 if (ret) {
657 BT_CLOGE_APPEND_CAUSE("Cannot add stream file `%s` to stream file group",
658 file->path.c_str());
659 goto error;
660 }
661 }
662
663 goto end;
664
665 error:
666 ret = -1;
667
668 end:
669 if (error) {
670 g_error_free(error);
671 }
672
673 return ret;
674 }
675
676 static int set_trace_name(bt_trace *trace, const char *name_suffix,
677 const bt2_common::LogCfg& logCfg)
678 {
679 int ret = 0;
680 const bt_value *val;
681 std::string name;
682
683 /*
684 * Check if we have a trace environment string value named `hostname`.
685 * If so, use it as the trace name's prefix.
686 */
687 val = bt_trace_borrow_environment_entry_value_by_name_const(trace, "hostname");
688 if (val && bt_value_is_string(val)) {
689 name += bt_value_string_get(val);
690
691 if (name_suffix) {
692 name += G_DIR_SEPARATOR;
693 }
694 }
695
696 if (name_suffix) {
697 name += name_suffix;
698 }
699
700 ret = bt_trace_set_name(trace, name.c_str());
701 if (ret) {
702 goto end;
703 }
704
705 goto end;
706
707 end:
708 return ret;
709 }
710
711 static ctf_fs_trace::UP ctf_fs_trace_create(const char *path, const char *name,
712 ctf::src::ClkClsCfg clkClsCfg,
713 bt_self_component *selfComp,
714 const bt2_common::LogCfg& logCfg)
715 {
716 int ret;
717 ctf_fs_trace::UP ctf_fs_trace {new struct ctf_fs_trace(logCfg)};
718
719 ctf_fs_trace->path = path;
720 ctf_fs_trace->metadata = bt2_common::makeUnique<ctf_fs_metadata>();
721
722 ret = ctf_fs_metadata_set_trace_class(ctf_fs_trace.get(), clkClsCfg, selfComp, logCfg);
723 if (ret) {
724 goto error;
725 }
726
727 if (ctf_fs_trace->metadata->trace_class) {
728 bt_trace *trace = bt_trace_create((*ctf_fs_trace->metadata->trace_class)->libObjPtr());
729 if (!trace) {
730 goto error;
731 }
732 ctf_fs_trace->trace = bt2::Trace::Shared::createWithoutRef(trace);
733 }
734
735 if (ctf_fs_trace->trace) {
736 ret = ctf_trace_class_configure_ir_trace(ctf_fs_trace->metadata->tc,
737 (*ctf_fs_trace->trace)->libObjPtr());
738 if (ret) {
739 goto error;
740 }
741
742 ret = set_trace_name((*ctf_fs_trace->trace)->libObjPtr(), name, logCfg);
743 if (ret) {
744 goto error;
745 }
746 }
747
748 ret = create_ds_file_groups(ctf_fs_trace.get());
749 if (ret) {
750 goto error;
751 }
752
753 goto end;
754
755 error:
756 ctf_fs_trace.reset();
757
758 end:
759 return ctf_fs_trace;
760 }
761
762 static int path_is_ctf_trace(const char *path)
763 {
764 int ret = 0;
765
766 std::string metadata_path = path;
767 metadata_path += G_DIR_SEPARATOR;
768 metadata_path += CTF_FS_METADATA_FILENAME;
769
770 if (g_file_test(metadata_path.c_str(), G_FILE_TEST_IS_REGULAR)) {
771 ret = 1;
772 goto end;
773 }
774
775 end:
776 return ret;
777 }
778
779 /* Helper for ctf_fs_component_create_ctf_fs_trace, to handle a single path. */
780
781 static int ctf_fs_component_create_ctf_fs_trace_one_path(struct ctf_fs_component *ctf_fs,
782 const char *path_param,
783 const char *trace_name,
784 std::vector<ctf_fs_trace::UP>& traces,
785 bt_self_component *selfComp)
786 {
787 ctf_fs_trace::UP ctf_fs_trace;
788 int ret;
789 const bt2_common::LogCfg& logCfg = ctf_fs->logCfg;
790
791 bt2_common::GStringUP norm_path {bt_common_normalize_path(path_param, NULL)};
792 if (!norm_path) {
793 BT_CLOGE_APPEND_CAUSE("Failed to normalize path: `%s`.", path_param);
794 goto error;
795 }
796
797 ret = path_is_ctf_trace(norm_path->str);
798 if (ret < 0) {
799 BT_CLOGE_APPEND_CAUSE("Failed to check if path is a CTF trace: path=%s", norm_path->str);
800 goto error;
801 } else if (ret == 0) {
802 BT_CLOGE_APPEND_CAUSE("Path is not a CTF trace (does not contain a metadata file): `%s`.",
803 norm_path->str);
804 goto error;
805 }
806
807 // FIXME: Remove or ifdef for __MINGW32__
808 if (strcmp(norm_path->str, "/") == 0) {
809 BT_CLOGE_APPEND_CAUSE("Opening a trace in `/` is not supported.");
810 ret = -1;
811 goto end;
812 }
813
814 ctf_fs_trace =
815 ctf_fs_trace_create(norm_path->str, trace_name, ctf_fs->clkClsCfg, selfComp, logCfg);
816 if (!ctf_fs_trace) {
817 BT_CLOGE_APPEND_CAUSE("Cannot create trace for `%s`.", norm_path->str);
818 goto error;
819 }
820
821 traces.emplace_back(std::move(ctf_fs_trace));
822
823 ret = 0;
824 goto end;
825
826 error:
827 ret = -1;
828
829 end:
830 return ret;
831 }
832
833 /*
834 * Count the number of stream and event classes defined by this trace's metadata.
835 *
836 * This is used to determine which metadata is the "latest", out of multiple
837 * traces sharing the same UUID. It is assumed that amongst all these metadatas,
838 * a bigger metadata is a superset of a smaller metadata. Therefore, it is
839 * enough to just count the classes.
840 */
841
842 static unsigned int metadata_count_stream_and_event_classes(struct ctf_fs_trace *trace)
843 {
844 unsigned int num = trace->metadata->tc->stream_classes->len;
845 guint i;
846
847 for (i = 0; i < trace->metadata->tc->stream_classes->len; i++) {
848 struct ctf_stream_class *sc =
849 (struct ctf_stream_class *) trace->metadata->tc->stream_classes->pdata[i];
850 num += sc->event_classes->len;
851 }
852
853 return num;
854 }
855
856 /*
857 * Merge the src ds_file_group into dest. This consists of merging their
858 * ds_file_infos, making sure to keep the result sorted.
859 */
860
861 static void merge_ctf_fs_ds_file_groups(struct ctf_fs_ds_file_group *dest,
862 ctf_fs_ds_file_group::UP src)
863 {
864 for (ctf_fs_ds_file_info::UP& ds_file_info : src->ds_file_infos) {
865 ds_file_group_insert_ds_file_info_sorted(dest, std::move(ds_file_info));
866 }
867
868 /* Merge both indexes. */
869 merge_ctf_fs_ds_indexes(dest->index.get(), std::move(src->index));
870 }
871
872 /* Merge src_trace's data stream file groups into dest_trace's. */
873
874 static int merge_matching_ctf_fs_ds_file_groups(struct ctf_fs_trace *dest_trace,
875 ctf_fs_trace::UP src_trace)
876 {
877 std::vector<ctf_fs_ds_file_group::UP>& dest = dest_trace->ds_file_groups;
878 std::vector<ctf_fs_ds_file_group::UP>& src = src_trace->ds_file_groups;
879 int ret = 0;
880
881 /*
882 * Save the initial length of dest: we only want to check against the
883 * original elements in the inner loop.
884 */
885 size_t dest_len = dest.size();
886
887 for (ctf_fs_ds_file_group::UP& src_group : src) {
888 struct ctf_fs_ds_file_group *dest_group = NULL;
889
890 /* A stream instance without ID can't match a stream in the other trace. */
891 if (src_group->stream_id != -1) {
892 /* Let's search for a matching ds_file_group in the destination. */
893 for (size_t d_i = 0; d_i < dest_len; ++d_i) {
894 ctf_fs_ds_file_group *candidate_dest = dest[d_i].get();
895
896 /* Can't match a stream instance without ID. */
897 if (candidate_dest->stream_id == -1) {
898 continue;
899 }
900
901 /*
902 * If the two groups have the same stream instance id
903 * and belong to the same stream class (stream instance
904 * ids are per-stream class), they represent the same
905 * stream instance.
906 */
907 if (candidate_dest->stream_id != src_group->stream_id ||
908 candidate_dest->sc->id != src_group->sc->id) {
909 continue;
910 }
911
912 dest_group = candidate_dest;
913 break;
914 }
915 }
916
917 /*
918 * Didn't find a friend in dest to merge our src_group into?
919 * Create a new empty one. This can happen if a stream was
920 * active in the source trace chunk but not in the destination
921 * trace chunk.
922 */
923 if (!dest_group) {
924 struct ctf_stream_class *sc;
925
926 sc = ctf_trace_class_borrow_stream_class_by_id(dest_trace->metadata->tc,
927 src_group->sc->id);
928 BT_ASSERT(sc);
929
930 ctf_fs_ds_index::UP index = ctf_fs_ds_index_create(dest_trace->logCfg);
931 if (!index) {
932 ret = -1;
933 goto end;
934 }
935
936 ctf_fs_ds_file_group::UP new_dest_group =
937 ctf_fs_ds_file_group_create(dest_trace, sc, src_group->stream_id, std::move(index));
938 /* Ownership of index is transferred. */
939 index = NULL;
940 if (!new_dest_group) {
941 ret = -1;
942 goto end;
943 }
944
945 dest_group = new_dest_group.get();
946 dest_trace->ds_file_groups.emplace_back(std::move(new_dest_group));
947 }
948
949 BT_ASSERT(dest_group);
950 merge_ctf_fs_ds_file_groups(dest_group, std::move(src_group));
951 }
952
953 end:
954 return ret;
955 }
956
957 /*
958 * Collapse the given traces, which must all share the same UUID, in a single
959 * one.
960 *
961 * The trace with the most expansive metadata is chosen and all other traces
962 * are merged into that one. On return, the elements of `traces` are nullptr
963 * and the merged trace is placed in `out_trace`.
964 */
965
966 static int merge_ctf_fs_traces(std::vector<ctf_fs_trace::UP> traces, ctf_fs_trace::UP& out_trace)
967 {
968 unsigned int winner_count;
969 struct ctf_fs_trace *winner;
970 guint i, winner_i;
971 int ret = 0;
972
973 BT_ASSERT(traces.size() >= 2);
974
975 winner_count = metadata_count_stream_and_event_classes(traces[0].get());
976 winner = traces[0].get();
977 winner_i = 0;
978
979 /* Find the trace with the largest metadata. */
980 for (i = 1; i < traces.size(); i++) {
981 ctf_fs_trace *candidate = traces[i].get();
982 unsigned int candidate_count;
983
984 /* A bit of sanity check. */
985 BT_ASSERT(bt_uuid_compare(winner->metadata->tc->uuid, candidate->metadata->tc->uuid) == 0);
986
987 candidate_count = metadata_count_stream_and_event_classes(candidate);
988
989 if (candidate_count > winner_count) {
990 winner_count = candidate_count;
991 winner = candidate;
992 winner_i = i;
993 }
994 }
995
996 /* Merge all the other traces in the winning trace. */
997 for (ctf_fs_trace::UP& trace : traces) {
998 /* Don't merge the winner into itself. */
999 if (trace.get() == winner) {
1000 continue;
1001 }
1002
1003 /* Merge trace's data stream file groups into winner's. */
1004 ret = merge_matching_ctf_fs_ds_file_groups(winner, std::move(trace));
1005 if (ret) {
1006 goto end;
1007 }
1008 }
1009
1010 /*
1011 * Move the winner out of the array, into `*out_trace`.
1012 */
1013 out_trace = std::move(traces[winner_i]);
1014
1015 end:
1016 return ret;
1017 }
1018
1019 enum target_event
1020 {
1021 FIRST_EVENT,
1022 LAST_EVENT,
1023 };
1024
1025 static int decode_clock_snapshot_after_event(struct ctf_fs_trace *ctf_fs_trace,
1026 struct ctf_clock_class *default_cc,
1027 struct ctf_fs_ds_index_entry *index_entry,
1028 enum target_event target_event, uint64_t *cs,
1029 int64_t *ts_ns)
1030 {
1031 enum ctf_msg_iter_status iter_status = CTF_MSG_ITER_STATUS_OK;
1032 ctf_msg_iter_up msg_iter;
1033 const bt2_common::LogCfg& logCfg = ctf_fs_trace->logCfg;
1034 int ret = 0;
1035
1036 BT_ASSERT(ctf_fs_trace);
1037 BT_ASSERT(index_entry);
1038 BT_ASSERT(index_entry->path);
1039
1040 ctf_fs_ds_file::UP ds_file =
1041 ctf_fs_ds_file_create(ctf_fs_trace, nonstd::nullopt, index_entry->path, logCfg);
1042 if (!ds_file) {
1043 BT_CLOGE_APPEND_CAUSE("Failed to create a ctf_fs_ds_file");
1044 ret = -1;
1045 goto end;
1046 }
1047
1048 BT_ASSERT(ctf_fs_trace->metadata);
1049 BT_ASSERT(ctf_fs_trace->metadata->tc);
1050
1051 msg_iter = ctf_msg_iter_create(ctf_fs_trace->metadata->tc,
1052 bt_common_get_page_size(logCfg.logLevel()) * 8,
1053
1054 ctf_fs_ds_file_medops, ds_file.get(), NULL, logCfg);
1055 if (!msg_iter) {
1056 /* ctf_msg_iter_create() logs errors. */
1057 ret = -1;
1058 goto end;
1059 }
1060
1061 /*
1062 * Turn on dry run mode to prevent the creation and usage of Babeltrace
1063 * library objects (bt_field, bt_message_*, etc.).
1064 */
1065 ctf_msg_iter_set_dry_run(msg_iter.get(), true);
1066
1067 /* Seek to the beginning of the target packet. */
1068 iter_status = ctf_msg_iter_seek(msg_iter.get(), index_entry->offset.bytes());
1069 if (iter_status) {
1070 /* ctf_msg_iter_seek() logs errors. */
1071 ret = -1;
1072 goto end;
1073 }
1074
1075 switch (target_event) {
1076 case FIRST_EVENT:
1077 /*
1078 * Start to decode the packet until we reach the end of
1079 * the first event. To extract the first event's clock
1080 * snapshot.
1081 */
1082 iter_status = ctf_msg_iter_curr_packet_first_event_clock_snapshot(msg_iter.get(), cs);
1083 break;
1084 case LAST_EVENT:
1085 /* Decode the packet to extract the last event's clock snapshot. */
1086 iter_status = ctf_msg_iter_curr_packet_last_event_clock_snapshot(msg_iter.get(), cs);
1087 break;
1088 default:
1089 bt_common_abort();
1090 }
1091 if (iter_status) {
1092 ret = -1;
1093 goto end;
1094 }
1095
1096 /* Convert clock snapshot to timestamp. */
1097 ret = bt_util_clock_cycles_to_ns_from_origin(
1098 *cs, default_cc->frequency, default_cc->offset_seconds, default_cc->offset_cycles, ts_ns);
1099 if (ret) {
1100 BT_CLOGE_APPEND_CAUSE("Failed to convert clock snapshot to timestamp");
1101 goto end;
1102 }
1103
1104 end:
1105 return ret;
1106 }
1107
1108 static int decode_packet_first_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
1109 struct ctf_clock_class *default_cc,
1110 struct ctf_fs_ds_index_entry *index_entry,
1111 uint64_t *cs, int64_t *ts_ns)
1112 {
1113 return decode_clock_snapshot_after_event(ctf_fs_trace, default_cc, index_entry, FIRST_EVENT, cs,
1114 ts_ns);
1115 }
1116
1117 static int decode_packet_last_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
1118 struct ctf_clock_class *default_cc,
1119 struct ctf_fs_ds_index_entry *index_entry,
1120 uint64_t *cs, int64_t *ts_ns)
1121 {
1122 return decode_clock_snapshot_after_event(ctf_fs_trace, default_cc, index_entry, LAST_EVENT, cs,
1123 ts_ns);
1124 }
1125
1126 /*
1127 * Fix up packet index entries for lttng's "event-after-packet" bug.
1128 * Some buggy lttng tracer versions may emit events with a timestamp that is
1129 * larger (after) than the timestamp_end of the their packets.
1130 *
1131 * To fix up this erroneous data we do the following:
1132 * 1. If it's not the stream file's last packet: set the packet index entry's
1133 * end time to the next packet's beginning time.
1134 * 2. If it's the stream file's last packet, set the packet index entry's end
1135 * time to the packet's last event's time, if any, or to the packet's
1136 * beginning time otherwise.
1137 *
1138 * Known buggy tracer versions:
1139 * - before lttng-ust 2.11.0
1140 * - before lttng-module 2.11.0
1141 * - before lttng-module 2.10.10
1142 * - before lttng-module 2.9.13
1143 */
1144 static int fix_index_lttng_event_after_packet_bug(struct ctf_fs_trace *trace)
1145 {
1146 int ret = 0;
1147 const bt2_common::LogCfg& logCfg = trace->logCfg;
1148
1149 for (ctf_fs_ds_file_group::UP& ds_file_group : trace->ds_file_groups) {
1150 struct ctf_clock_class *default_cc;
1151 struct ctf_fs_ds_index *index;
1152
1153 BT_ASSERT(ds_file_group);
1154 index = ds_file_group->index.get();
1155
1156 BT_ASSERT(index);
1157 BT_ASSERT(!index->entries.empty());
1158
1159 /*
1160 * Iterate over all entries but the last one. The last one is
1161 * fixed differently after.
1162 */
1163 for (size_t entry_i = 0; entry_i < index->entries.size() - 1; ++entry_i) {
1164 ctf_fs_ds_index_entry *curr_entry = index->entries[entry_i].get();
1165 ctf_fs_ds_index_entry *next_entry = index->entries[entry_i + 1].get();
1166
1167 /*
1168 * 1. Set the current index entry `end` timestamp to
1169 * the next index entry `begin` timestamp.
1170 */
1171 curr_entry->timestamp_end = next_entry->timestamp_begin;
1172 curr_entry->timestamp_end_ns = next_entry->timestamp_begin_ns;
1173 }
1174
1175 /*
1176 * 2. Fix the last entry by decoding the last event of the last
1177 * packet.
1178 */
1179 ctf_fs_ds_index_entry *last_entry = index->entries.back().get();
1180 BT_ASSERT(last_entry);
1181
1182 BT_ASSERT(ds_file_group->sc->default_clock_class);
1183 default_cc = ds_file_group->sc->default_clock_class;
1184
1185 /*
1186 * Decode packet to read the timestamp of the last event of the
1187 * entry.
1188 */
1189 ret = decode_packet_last_event_timestamp(trace, default_cc, last_entry,
1190 &last_entry->timestamp_end,
1191 &last_entry->timestamp_end_ns);
1192 if (ret) {
1193 BT_CLOGE_APPEND_CAUSE(
1194 "Failed to decode stream's last packet to get its last event's clock snapshot.");
1195 goto end;
1196 }
1197 }
1198
1199 end:
1200 return ret;
1201 }
1202
1203 /*
1204 * Fix up packet index entries for barectf's "event-before-packet" bug.
1205 * Some buggy barectf tracer versions may emit events with a timestamp that is
1206 * less than the timestamp_begin of the their packets.
1207 *
1208 * To fix up this erroneous data we do the following:
1209 * 1. Starting at the second index entry, set the timestamp_begin of the
1210 * current entry to the timestamp of the first event of the packet.
1211 * 2. Set the previous entry's timestamp_end to the timestamp_begin of the
1212 * current packet.
1213 *
1214 * Known buggy tracer versions:
1215 * - before barectf 2.3.1
1216 */
1217 static int fix_index_barectf_event_before_packet_bug(struct ctf_fs_trace *trace)
1218 {
1219 int ret = 0;
1220 const bt2_common::LogCfg& logCfg = trace->logCfg;
1221
1222 for (ctf_fs_ds_file_group::UP& ds_file_group : trace->ds_file_groups) {
1223 struct ctf_clock_class *default_cc;
1224 struct ctf_fs_ds_index *index = ds_file_group->index.get();
1225
1226 BT_ASSERT(index);
1227 BT_ASSERT(!index->entries.empty());
1228
1229 BT_ASSERT(ds_file_group->sc->default_clock_class);
1230 default_cc = ds_file_group->sc->default_clock_class;
1231
1232 /*
1233 * 1. Iterate over the index, starting from the second entry
1234 * (index = 1).
1235 */
1236 for (size_t entry_i = 1; entry_i < index->entries.size(); ++entry_i) {
1237 ctf_fs_ds_index_entry *prev_entry = index->entries[entry_i - 1].get();
1238 ctf_fs_ds_index_entry *curr_entry = index->entries[entry_i].get();
1239 /*
1240 * 2. Set the current entry `begin` timestamp to the
1241 * timestamp of the first event of the current packet.
1242 */
1243 ret = decode_packet_first_event_timestamp(trace, default_cc, curr_entry,
1244 &curr_entry->timestamp_begin,
1245 &curr_entry->timestamp_begin_ns);
1246 if (ret) {
1247 BT_CLOGE_APPEND_CAUSE("Failed to decode first event's clock snapshot");
1248 goto end;
1249 }
1250
1251 /*
1252 * 3. Set the previous entry `end` timestamp to the
1253 * timestamp of the first event of the current packet.
1254 */
1255 prev_entry->timestamp_end = curr_entry->timestamp_begin;
1256 prev_entry->timestamp_end_ns = curr_entry->timestamp_begin_ns;
1257 }
1258 }
1259 end:
1260 return ret;
1261 }
1262
1263 /*
1264 * When using the lttng-crash feature it's likely that the last packets of each
1265 * stream have their timestamp_end set to zero. This is caused by the fact that
1266 * the tracer crashed and was not able to properly close the packets.
1267 *
1268 * To fix up this erroneous data we do the following:
1269 * For each index entry, if the entry's timestamp_end is 0 and the
1270 * timestamp_begin is not 0:
1271 * - If it's the stream file's last packet: set the packet index entry's end
1272 * time to the packet's last event's time, if any, or to the packet's
1273 * beginning time otherwise.
1274 * - If it's not the stream file's last packet: set the packet index
1275 * entry's end time to the next packet's beginning time.
1276 *
1277 * Affected versions:
1278 * - All current and future lttng-ust and lttng-modules versions.
1279 */
1280 static int fix_index_lttng_crash_quirk(struct ctf_fs_trace *trace)
1281 {
1282 int ret = 0;
1283 const bt2_common::LogCfg& logCfg = trace->logCfg;
1284
1285 for (ctf_fs_ds_file_group::UP& ds_file_group : trace->ds_file_groups) {
1286 struct ctf_clock_class *default_cc;
1287 struct ctf_fs_ds_index *index;
1288
1289 BT_ASSERT(ds_file_group);
1290 index = ds_file_group->index.get();
1291
1292 BT_ASSERT(ds_file_group->sc->default_clock_class);
1293 default_cc = ds_file_group->sc->default_clock_class;
1294
1295 BT_ASSERT(index);
1296 BT_ASSERT(!index->entries.empty());
1297
1298 ctf_fs_ds_index_entry *last_entry = index->entries.back().get();
1299 BT_ASSERT(last_entry);
1300
1301 /* 1. Fix the last entry first. */
1302 if (last_entry->timestamp_end == 0 && last_entry->timestamp_begin != 0) {
1303 /*
1304 * Decode packet to read the timestamp of the
1305 * last event of the stream file.
1306 */
1307 ret = decode_packet_last_event_timestamp(trace, default_cc, last_entry,
1308 &last_entry->timestamp_end,
1309 &last_entry->timestamp_end_ns);
1310 if (ret) {
1311 BT_CLOGE_APPEND_CAUSE("Failed to decode last event's clock snapshot");
1312 goto end;
1313 }
1314 }
1315
1316 /* Iterate over all entries but the last one. */
1317 for (size_t entry_idx = 0; entry_idx < index->entries.size() - 1; ++entry_idx) {
1318 ctf_fs_ds_index_entry *curr_entry = index->entries[entry_idx].get();
1319 ctf_fs_ds_index_entry *next_entry = index->entries[entry_idx + 1].get();
1320
1321 if (curr_entry->timestamp_end == 0 && curr_entry->timestamp_begin != 0) {
1322 /*
1323 * 2. Set the current index entry `end` timestamp to
1324 * the next index entry `begin` timestamp.
1325 */
1326 curr_entry->timestamp_end = next_entry->timestamp_begin;
1327 curr_entry->timestamp_end_ns = next_entry->timestamp_begin_ns;
1328 }
1329 }
1330 }
1331
1332 end:
1333 return ret;
1334 }
1335
1336 /*
1337 * Extract the tracer information necessary to compare versions.
1338 * Returns 0 on success, and -1 if the extraction is not successful because the
1339 * necessary fields are absents in the trace metadata.
1340 */
1341 static int extract_tracer_info(struct ctf_fs_trace *trace, struct tracer_info *current_tracer_info)
1342 {
1343 int ret = 0;
1344 struct ctf_trace_class_env_entry *entry;
1345
1346 /* Clear the current_tracer_info struct */
1347 memset(current_tracer_info, 0, sizeof(*current_tracer_info));
1348
1349 /*
1350 * To compare 2 tracer versions, at least the tracer name and it's
1351 * major version are needed. If one of these is missing, consider it an
1352 * extraction failure.
1353 */
1354 entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_name");
1355 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR) {
1356 goto missing_bare_minimum;
1357 }
1358
1359 /* Set tracer name. */
1360 current_tracer_info->name = entry->value.str->str;
1361
1362 entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_major");
1363 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
1364 goto missing_bare_minimum;
1365 }
1366
1367 /* Set major version number. */
1368 current_tracer_info->major = entry->value.i;
1369
1370 entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_minor");
1371 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
1372 goto end;
1373 }
1374
1375 /* Set minor version number. */
1376 current_tracer_info->minor = entry->value.i;
1377
1378 entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_patch");
1379 if (!entry) {
1380 /*
1381 * If `tracer_patch` doesn't exist `tracer_patchlevel` might.
1382 * For example, `lttng-modules` uses entry name
1383 * `tracer_patchlevel`.
1384 */
1385 entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_patchlevel");
1386 }
1387
1388 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
1389 goto end;
1390 }
1391
1392 /* Set patch version number. */
1393 current_tracer_info->patch = entry->value.i;
1394
1395 goto end;
1396
1397 missing_bare_minimum:
1398 ret = -1;
1399 end:
1400 return ret;
1401 }
1402
1403 static bool is_tracer_affected_by_lttng_event_after_packet_bug(struct tracer_info *curr_tracer_info)
1404 {
1405 bool is_affected = false;
1406
1407 if (strcmp(curr_tracer_info->name, "lttng-ust") == 0) {
1408 if (curr_tracer_info->major < 2) {
1409 is_affected = true;
1410 } else if (curr_tracer_info->major == 2) {
1411 /* fixed in lttng-ust 2.11.0 */
1412 if (curr_tracer_info->minor < 11) {
1413 is_affected = true;
1414 }
1415 }
1416 } else if (strcmp(curr_tracer_info->name, "lttng-modules") == 0) {
1417 if (curr_tracer_info->major < 2) {
1418 is_affected = true;
1419 } else if (curr_tracer_info->major == 2) {
1420 /* fixed in lttng-modules 2.11.0 */
1421 if (curr_tracer_info->minor == 10) {
1422 /* fixed in lttng-modules 2.10.10 */
1423 if (curr_tracer_info->patch < 10) {
1424 is_affected = true;
1425 }
1426 } else if (curr_tracer_info->minor == 9) {
1427 /* fixed in lttng-modules 2.9.13 */
1428 if (curr_tracer_info->patch < 13) {
1429 is_affected = true;
1430 }
1431 } else if (curr_tracer_info->minor < 9) {
1432 is_affected = true;
1433 }
1434 }
1435 }
1436
1437 return is_affected;
1438 }
1439
1440 static bool
1441 is_tracer_affected_by_barectf_event_before_packet_bug(struct tracer_info *curr_tracer_info)
1442 {
1443 bool is_affected = false;
1444
1445 if (strcmp(curr_tracer_info->name, "barectf") == 0) {
1446 if (curr_tracer_info->major < 2) {
1447 is_affected = true;
1448 } else if (curr_tracer_info->major == 2) {
1449 if (curr_tracer_info->minor < 3) {
1450 is_affected = true;
1451 } else if (curr_tracer_info->minor == 3) {
1452 /* fixed in barectf 2.3.1 */
1453 if (curr_tracer_info->patch < 1) {
1454 is_affected = true;
1455 }
1456 }
1457 }
1458 }
1459
1460 return is_affected;
1461 }
1462
1463 static bool is_tracer_affected_by_lttng_crash_quirk(struct tracer_info *curr_tracer_info)
1464 {
1465 bool is_affected = false;
1466
1467 /* All LTTng tracer may be affected by this lttng crash quirk. */
1468 if (strcmp(curr_tracer_info->name, "lttng-ust") == 0) {
1469 is_affected = true;
1470 } else if (strcmp(curr_tracer_info->name, "lttng-modules") == 0) {
1471 is_affected = true;
1472 }
1473
1474 return is_affected;
1475 }
1476
1477 /*
1478 * Looks for trace produced by known buggy tracers and fix up the index
1479 * produced earlier.
1480 */
1481 static int fix_packet_index_tracer_bugs(struct ctf_fs_component *ctf_fs)
1482 {
1483 int ret = 0;
1484 struct tracer_info current_tracer_info;
1485 const bt2_common::LogCfg& logCfg = ctf_fs->logCfg;
1486
1487 ret = extract_tracer_info(ctf_fs->trace.get(), &current_tracer_info);
1488 if (ret) {
1489 /*
1490 * A trace may not have all the necessary environment
1491 * entries to do the tracer version comparison.
1492 * At least, the tracer name and major version number
1493 * are needed. Failing to extract these entries is not
1494 * an error.
1495 */
1496 ret = 0;
1497 BT_LOGI_STR("Cannot extract tracer information necessary to compare with buggy versions.");
1498 goto end;
1499 ;
1500 }
1501
1502 /* Check if the trace may be affected by old tracer bugs. */
1503 if (is_tracer_affected_by_lttng_event_after_packet_bug(&current_tracer_info)) {
1504 BT_LOGI_STR("Trace may be affected by LTTng tracer packet timestamp bug. Fixing up.");
1505 ret = fix_index_lttng_event_after_packet_bug(ctf_fs->trace.get());
1506 if (ret) {
1507 BT_CLOGE_APPEND_CAUSE("Failed to fix LTTng event-after-packet bug.");
1508 goto end;
1509 }
1510 ctf_fs->trace->metadata->tc->quirks.lttng_event_after_packet = true;
1511 }
1512
1513 if (is_tracer_affected_by_barectf_event_before_packet_bug(&current_tracer_info)) {
1514 BT_LOGI_STR("Trace may be affected by barectf tracer packet timestamp bug. Fixing up.");
1515 ret = fix_index_barectf_event_before_packet_bug(ctf_fs->trace.get());
1516 if (ret) {
1517 BT_CLOGE_APPEND_CAUSE("Failed to fix barectf event-before-packet bug.");
1518 goto end;
1519 }
1520 ctf_fs->trace->metadata->tc->quirks.barectf_event_before_packet = true;
1521 }
1522
1523 if (is_tracer_affected_by_lttng_crash_quirk(&current_tracer_info)) {
1524 ret = fix_index_lttng_crash_quirk(ctf_fs->trace.get());
1525 if (ret) {
1526 BT_CLOGE_APPEND_CAUSE("Failed to fix lttng-crash timestamp quirks.");
1527 goto end;
1528 }
1529 ctf_fs->trace->metadata->tc->quirks.lttng_crash = true;
1530 }
1531
1532 end:
1533 return ret;
1534 }
1535
1536 static bool compare_ds_file_groups_by_first_path(const ctf_fs_ds_file_group::UP& ds_file_group_a,
1537 const ctf_fs_ds_file_group::UP& ds_file_group_b)
1538 {
1539 BT_ASSERT(!ds_file_group_a->ds_file_infos.empty());
1540 BT_ASSERT(!ds_file_group_b->ds_file_infos.empty());
1541
1542 const ctf_fs_ds_file_info& first_ds_file_info_a = *ds_file_group_a->ds_file_infos[0];
1543 const ctf_fs_ds_file_info& first_ds_file_info_b = *ds_file_group_b->ds_file_infos[0];
1544
1545 return first_ds_file_info_a.path < first_ds_file_info_b.path;
1546 }
1547
1548 int ctf_fs_component_create_ctf_fs_trace(struct ctf_fs_component *ctf_fs,
1549 const bt_value *paths_value,
1550 const bt_value *trace_name_value,
1551 bt_self_component *selfComp)
1552 {
1553 int ret = 0;
1554 const bt2_common::LogCfg& logCfg = ctf_fs->logCfg;
1555 std::vector<std::string> paths;
1556 std::vector<ctf_fs_trace::UP> traces;
1557 const char *trace_name;
1558
1559 BT_ASSERT(bt_value_get_type(paths_value) == BT_VALUE_TYPE_ARRAY);
1560 BT_ASSERT(!bt_value_array_is_empty(paths_value));
1561
1562 trace_name = trace_name_value ? bt_value_string_get(trace_name_value) : NULL;
1563
1564 /*
1565 * Create a sorted array of the paths, to make the execution of this
1566 * component deterministic.
1567 */
1568 for (std::uint64_t i = 0; i < bt_value_array_get_length(paths_value); i++) {
1569 const bt_value *path_value = bt_value_array_borrow_element_by_index_const(paths_value, i);
1570 const char *input = bt_value_string_get(path_value);
1571 paths.emplace_back(input);
1572 }
1573
1574 std::sort(paths.begin(), paths.end());
1575
1576 /* Create a separate ctf_fs_trace object for each path. */
1577 for (const std::string& path : paths) {
1578 ret = ctf_fs_component_create_ctf_fs_trace_one_path(ctf_fs, path.c_str(), trace_name,
1579 traces, selfComp);
1580 if (ret) {
1581 goto end;
1582 }
1583 }
1584
1585 if (traces.size() > 1) {
1586 ctf_fs_trace *first_trace = traces[0].get();
1587 const uint8_t *first_trace_uuid = first_trace->metadata->tc->uuid;
1588
1589 /*
1590 * We have more than one trace, they must all share the same
1591 * UUID, verify that.
1592 */
1593 for (size_t i = 0; i < traces.size(); i++) {
1594 ctf_fs_trace *this_trace = traces[i].get();
1595 const uint8_t *this_trace_uuid = this_trace->metadata->tc->uuid;
1596
1597 if (!this_trace->metadata->tc->is_uuid_set) {
1598 BT_CLOGE_APPEND_CAUSE(
1599 "Multiple traces given, but a trace does not have a UUID: path=%s",
1600 this_trace->path.c_str());
1601 goto error;
1602 }
1603
1604 if (bt_uuid_compare(first_trace_uuid, this_trace_uuid) != 0) {
1605 char first_trace_uuid_str[BT_UUID_STR_LEN + 1];
1606 char this_trace_uuid_str[BT_UUID_STR_LEN + 1];
1607
1608 bt_uuid_to_str(first_trace_uuid, first_trace_uuid_str);
1609 bt_uuid_to_str(this_trace_uuid, this_trace_uuid_str);
1610
1611 BT_CLOGE_APPEND_CAUSE("Multiple traces given, but UUIDs don't match: "
1612 "first-trace-uuid=%s, first-trace-path=%s, "
1613 "trace-uuid=%s, trace-path=%s",
1614 first_trace_uuid_str, first_trace->path.c_str(),
1615 this_trace_uuid_str, this_trace->path.c_str());
1616 goto error;
1617 }
1618 }
1619
1620 ret = merge_ctf_fs_traces(std::move(traces), ctf_fs->trace);
1621 if (ret) {
1622 BT_CLOGE_APPEND_CAUSE("Failed to merge traces with the same UUID.");
1623 goto error;
1624 }
1625 } else {
1626 /* Just one trace, it may or may not have a UUID, both are fine. */
1627 ctf_fs->trace = std::move(traces[0]);
1628 }
1629
1630 ret = fix_packet_index_tracer_bugs(ctf_fs);
1631 if (ret) {
1632 BT_CLOGE_APPEND_CAUSE("Failed to fix packet index tracer bugs.");
1633 }
1634
1635 /*
1636 * Sort data stream file groups by first data stream file info
1637 * path to get a deterministic order. This order influences the
1638 * order of the output ports. It also influences the order of
1639 * the automatic stream IDs if the trace's packet headers do not
1640 * contain a `stream_instance_id` field, in which case the data
1641 * stream file to stream ID association is always the same,
1642 * whatever the build and the system.
1643 *
1644 * Having a deterministic order here can help debugging and
1645 * testing.
1646 */
1647 std::sort(ctf_fs->trace->ds_file_groups.begin(), ctf_fs->trace->ds_file_groups.end(),
1648 compare_ds_file_groups_by_first_path);
1649 goto end;
1650
1651 error:
1652 ret = -1;
1653
1654 end:
1655 return ret;
1656 }
1657
1658 static const std::string&
1659 get_stream_instance_unique_name(struct ctf_fs_ds_file_group *ds_file_group)
1660 {
1661 /*
1662 * The first (earliest) stream file's path is used as the stream's unique
1663 * name.
1664 */
1665 BT_ASSERT(!ds_file_group->ds_file_infos.empty());
1666 ctf_fs_ds_file_info *ds_file_info = ds_file_group->ds_file_infos[0].get();
1667 return ds_file_info->path;
1668 }
1669
1670 /* Create the IR stream objects for ctf_fs_trace. */
1671
1672 static int create_streams_for_trace(struct ctf_fs_trace *ctf_fs_trace)
1673 {
1674 int ret;
1675 const bt2_common::LogCfg& logCfg = ctf_fs_trace->logCfg;
1676
1677 for (ctf_fs_ds_file_group::UP& ds_file_group : ctf_fs_trace->ds_file_groups) {
1678 const std::string& name = get_stream_instance_unique_name(ds_file_group.get());
1679
1680 BT_ASSERT(ds_file_group->sc->ir_sc);
1681 BT_ASSERT(ctf_fs_trace->trace);
1682
1683 bt_stream *stream;
1684
1685 if (ds_file_group->stream_id == UINT64_C(-1)) {
1686 /* No stream ID: use 0 */
1687 stream = bt_stream_create_with_id(ds_file_group->sc->ir_sc,
1688 (*ctf_fs_trace->trace)->libObjPtr(),
1689 ctf_fs_trace->next_stream_id);
1690 ctf_fs_trace->next_stream_id++;
1691 } else {
1692 /* Specific stream ID */
1693 stream = bt_stream_create_with_id(ds_file_group->sc->ir_sc,
1694 (*ctf_fs_trace->trace)->libObjPtr(),
1695 (uint64_t) ds_file_group->stream_id);
1696 }
1697
1698 if (!stream) {
1699 BT_CLOGE_APPEND_CAUSE("Cannot create stream for DS file group: "
1700 "addr=%p, stream-name=\"%s\"",
1701 ds_file_group.get(), name.c_str());
1702 goto error;
1703 }
1704
1705 ds_file_group->stream = bt2::Stream::Shared::createWithoutRef(stream);
1706
1707 ret = bt_stream_set_name((*ds_file_group->stream)->libObjPtr(), name.c_str());
1708 if (ret) {
1709 BT_CLOGE_APPEND_CAUSE("Cannot set stream's name: "
1710 "addr=%p, stream-name=\"%s\"",
1711 (*ds_file_group->stream)->libObjPtr(), name.c_str());
1712 goto error;
1713 }
1714 }
1715
1716 ret = 0;
1717 goto end;
1718
1719 error:
1720 ret = -1;
1721
1722 end:
1723 return ret;
1724 }
1725
1726 static const bt_param_validation_value_descr inputs_elem_descr =
1727 bt_param_validation_value_descr::makeString();
1728
1729 static bt_param_validation_map_value_entry_descr fs_params_entries_descr[] = {
1730 {"inputs", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
1731 bt_param_validation_value_descr::makeArray(1, BT_PARAM_VALIDATION_INFINITE,
1732 inputs_elem_descr)},
1733 {"trace-name", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
1734 bt_param_validation_value_descr::makeString()},
1735 {"clock-class-offset-s", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
1736 bt_param_validation_value_descr::makeSignedInteger()},
1737 {"clock-class-offset-ns", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
1738 bt_param_validation_value_descr::makeSignedInteger()},
1739 {"force-clock-class-origin-unix-epoch", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
1740 bt_param_validation_value_descr::makeBool()},
1741 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
1742
1743 bool read_src_fs_parameters(const bt_value *params, const bt_value **inputs,
1744 const bt_value **trace_name, struct ctf_fs_component *ctf_fs)
1745 {
1746 bool ret;
1747 const bt_value *value;
1748 enum bt_param_validation_status validate_value_status;
1749 gchar *error = NULL;
1750 const bt2_common::LogCfg& logCfg = ctf_fs->logCfg;
1751
1752 validate_value_status = bt_param_validation_validate(params, fs_params_entries_descr, &error);
1753 if (validate_value_status != BT_PARAM_VALIDATION_STATUS_OK) {
1754 BT_CLOGE_APPEND_CAUSE("%s", error);
1755 ret = false;
1756 goto end;
1757 }
1758
1759 /* inputs parameter */
1760 *inputs = bt_value_map_borrow_entry_value_const(params, "inputs");
1761
1762 /* clock-class-offset-s parameter */
1763 value = bt_value_map_borrow_entry_value_const(params, "clock-class-offset-s");
1764 if (value) {
1765 ctf_fs->clkClsCfg.offsetSec = bt_value_integer_signed_get(value);
1766 }
1767
1768 /* clock-class-offset-ns parameter */
1769 value = bt_value_map_borrow_entry_value_const(params, "clock-class-offset-ns");
1770 if (value) {
1771 ctf_fs->clkClsCfg.offsetNanoSec = bt_value_integer_signed_get(value);
1772 }
1773
1774 /* force-clock-class-origin-unix-epoch parameter */
1775 value = bt_value_map_borrow_entry_value_const(params, "force-clock-class-origin-unix-epoch");
1776 if (value) {
1777 ctf_fs->clkClsCfg.forceOriginIsUnixEpoch = bt_value_bool_get(value);
1778 }
1779
1780 /* trace-name parameter */
1781 *trace_name = bt_value_map_borrow_entry_value_const(params, "trace-name");
1782
1783 ret = true;
1784
1785 end:
1786 g_free(error);
1787 return ret;
1788 }
1789
1790 static ctf_fs_component::UP ctf_fs_create(const bt_value *params,
1791 bt_self_component_source *self_comp_src,
1792 const bt2_common::LogCfg& logCfg)
1793 {
1794 const bt_value *inputs_value;
1795 const bt_value *trace_name_value;
1796 bt_self_component *self_comp = bt_self_component_source_as_self_component(self_comp_src);
1797
1798 ctf_fs_component::UP ctf_fs = ctf_fs_component_create(logCfg);
1799 if (!ctf_fs) {
1800 return nullptr;
1801 }
1802
1803 if (!read_src_fs_parameters(params, &inputs_value, &trace_name_value, ctf_fs.get())) {
1804 return nullptr;
1805 }
1806
1807 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs.get(), inputs_value, trace_name_value,
1808 self_comp)) {
1809 return nullptr;
1810 }
1811
1812 if (create_streams_for_trace(ctf_fs->trace.get())) {
1813 return nullptr;
1814 }
1815
1816 if (create_ports_for_trace(ctf_fs.get(), ctf_fs->trace.get(), self_comp_src)) {
1817 return nullptr;
1818 }
1819
1820 return ctf_fs;
1821 }
1822
1823 BT_HIDDEN
1824 bt_component_class_initialize_method_status
1825 ctf_fs_init(bt_self_component_source *self_comp_src, bt_self_component_source_configuration *config,
1826 const bt_value *params, __attribute__((unused)) void *init_method_data)
1827 {
1828 bt_self_component *selfComp = bt_self_component_source_as_self_component(self_comp_src);
1829 const bt_component *comp = bt_self_component_as_component(selfComp);
1830 bt_logging_level logLevel = bt_component_get_logging_level(comp);
1831 bt2_common::LogCfg logCfg(logLevel, *selfComp);
1832
1833 try {
1834 ctf_fs_component::UP ctf_fs = ctf_fs_create(params, self_comp_src, logCfg);
1835 if (!ctf_fs) {
1836 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
1837 }
1838
1839 bt_self_component_set_data(selfComp, ctf_fs.release());
1840
1841 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
1842 } catch (const std::bad_alloc&) {
1843 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
1844 } catch (const bt2_common::Error&) {
1845 BT_CLOGE_APPEND_CAUSE("Failed to initialize component");
1846 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
1847 }
1848 }
1849
1850 BT_HIDDEN
1851 bt_component_class_query_method_status ctf_fs_query(bt_self_component_class_source *comp_class_src,
1852 bt_private_query_executor *priv_query_exec,
1853 const char *object, const bt_value *params,
1854 __attribute__((unused)) void *method_data,
1855 const bt_value **result)
1856 {
1857 const bt_query_executor *query_exec =
1858 bt_private_query_executor_as_query_executor_const(priv_query_exec);
1859 bt_logging_level log_level = bt_query_executor_get_logging_level(query_exec);
1860 bt_self_component_class *comp_class =
1861 bt_self_component_class_source_as_self_component_class(comp_class_src);
1862 bt2_common::LogCfg logCfg(log_level, *comp_class);
1863
1864 try {
1865 bt2::ConstMapValue paramsObj(params);
1866 nonstd::optional<bt2::Value::Shared> resultObj;
1867
1868 if (strcmp(object, "metadata-info") == 0) {
1869 resultObj = metadata_info_query(paramsObj, logCfg);
1870 } else if (strcmp(object, "babeltrace.trace-infos") == 0) {
1871 resultObj = trace_infos_query(paramsObj, logCfg);
1872 } else if (!strcmp(object, "babeltrace.support-info")) {
1873 resultObj = support_info_query(paramsObj, logCfg);
1874 } else {
1875 BT_LOGE("Unknown query object `%s`", object);
1876 return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_UNKNOWN_OBJECT;
1877 }
1878
1879 *result = resultObj->release().libObjPtr();
1880
1881 return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
1882 } catch (const std::bad_alloc&) {
1883 return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
1884 } catch (const bt2_common::Error&) {
1885 BT_CLOGE_APPEND_CAUSE("Failed to execute query: object=%s", object);
1886 return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
1887 }
1888 }
This page took 0.069016 seconds and 5 git commands to generate.