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