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