ctf: de-duplicate index entries
[babeltrace.git] / src / plugins / ctf / fs-src / fs.c
CommitLineData
7a278c8e 1/*
ea0b4b9e 2 * fs.c
7a278c8e 3 *
ea0b4b9e 4 * Babeltrace CTF file system Reader Component
7a278c8e 5 *
1a9f7075 6 * Copyright 2015-2017 Philippe Proulx <pproulx@efficios.com>
f3bc2010 7 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7a278c8e 8 *
7a278c8e
JG
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
4c65a157 28#define BT_COMP_LOG_SELF_COMP self_comp
98903a3e
PP
29#define BT_LOG_OUTPUT_LEVEL log_level
30#define BT_LOG_TAG "PLUGIN/SRC.CTF.FS"
d9c39b0a 31#include "logging/comp-logging.h"
98903a3e 32
578e048b 33#include "common/common.h"
3fadfbc0 34#include <babeltrace2/babeltrace.h>
6162e6b7 35#include "common/uuid.h"
ea0b4b9e 36#include <glib.h>
578e048b 37#include "common/assert.h"
94cf822e 38#include <inttypes.h>
c55a9f58 39#include <stdbool.h>
56a1cced 40#include "fs.h"
413bc2c4 41#include "metadata.h"
94cf822e 42#include "data-stream-file.h"
e7a4393b 43#include "file.h"
1e649dff 44#include "../common/metadata/decoder.h"
335a2da5 45#include "../common/metadata/ctf-meta-configure-ir-trace.h"
d6e69534 46#include "../common/msg-iter/msg-iter.h"
04c0ba87 47#include "query.h"
c24f7ab4 48#include "plugins/common/param-validation/param-validation.h"
e7a4393b 49
626cc488
FD
50struct tracer_info {
51 const char *name;
52 int64_t major;
53 int64_t minor;
54 int64_t patch;
55};
56
94cf822e 57static
d6e69534 58int msg_iter_data_set_current_ds_file(struct ctf_fs_msg_iter_data *msg_iter_data)
94cf822e
PP
59{
60 struct ctf_fs_ds_file_info *ds_file_info;
61 int ret = 0;
62
d6e69534
PP
63 BT_ASSERT(msg_iter_data->ds_file_info_index <
64 msg_iter_data->ds_file_group->ds_file_infos->len);
94cf822e 65 ds_file_info = g_ptr_array_index(
d6e69534
PP
66 msg_iter_data->ds_file_group->ds_file_infos,
67 msg_iter_data->ds_file_info_index);
68
69 ctf_fs_ds_file_destroy(msg_iter_data->ds_file);
70 msg_iter_data->ds_file = ctf_fs_ds_file_create(
71 msg_iter_data->ds_file_group->ctf_fs_trace,
f30762e5 72 msg_iter_data->self_msg_iter,
d6e69534
PP
73 msg_iter_data->msg_iter,
74 msg_iter_data->ds_file_group->stream,
98903a3e
PP
75 ds_file_info->path->str,
76 msg_iter_data->log_level);
d6e69534 77 if (!msg_iter_data->ds_file) {
94cf822e
PP
78 ret = -1;
79 }
80
81 return ret;
82}
83
84static
d6e69534
PP
85void ctf_fs_msg_iter_data_destroy(
86 struct ctf_fs_msg_iter_data *msg_iter_data)
94cf822e 87{
d6e69534 88 if (!msg_iter_data) {
94cf822e
PP
89 return;
90 }
91
d6e69534 92 ctf_fs_ds_file_destroy(msg_iter_data->ds_file);
6de92955 93
d6e69534 94 if (msg_iter_data->msg_iter) {
18a1979b 95 ctf_msg_iter_destroy(msg_iter_data->msg_iter);
6de92955
PP
96 }
97
d6e69534 98 g_free(msg_iter_data);
94cf822e
PP
99}
100
fc917f65
PP
101static
102void set_msg_iter_emits_stream_beginning_end_messages(
103 struct ctf_fs_msg_iter_data *msg_iter_data)
104{
18a1979b 105 ctf_msg_iter_set_emit_stream_beginning_message(
fc917f65
PP
106 msg_iter_data->ds_file->msg_iter,
107 msg_iter_data->ds_file_info_index == 0);
18a1979b 108 ctf_msg_iter_set_emit_stream_end_message(
fc917f65
PP
109 msg_iter_data->ds_file->msg_iter,
110 msg_iter_data->ds_file_info_index ==
111 msg_iter_data->ds_file_group->ds_file_infos->len - 1);
112}
113
d4393e08 114static
d24d5663 115bt_component_class_message_iterator_next_method_status ctf_fs_iterator_next_one(
d6e69534 116 struct ctf_fs_msg_iter_data *msg_iter_data,
fc917f65 117 const bt_message **out_msg)
ea0b4b9e 118{
d24d5663 119 bt_component_class_message_iterator_next_method_status status;
94cf822e 120
98b15851 121 BT_ASSERT_DBG(msg_iter_data->ds_file);
f42867e2 122
fc917f65
PP
123 while (true) {
124 bt_message *msg;
125
126 status = ctf_fs_ds_file_next(msg_iter_data->ds_file, &msg);
127 switch (status) {
d24d5663 128 case BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK:
fc917f65
PP
129 *out_msg = msg;
130 msg = NULL;
f42867e2 131 goto end;
d24d5663 132 case BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_END:
fc917f65
PP
133 {
134 int ret;
f42867e2 135
fc917f65
PP
136 if (msg_iter_data->ds_file_info_index ==
137 msg_iter_data->ds_file_group->ds_file_infos->len - 1) {
138 /* End of all group's stream files */
139 goto end;
140 }
141
142 msg_iter_data->ds_file_info_index++;
18a1979b 143 ctf_msg_iter_reset_for_next_stream_file(
495490c5 144 msg_iter_data->msg_iter);
fc917f65
PP
145 set_msg_iter_emits_stream_beginning_end_messages(
146 msg_iter_data);
94cf822e 147
94cf822e 148 /*
fc917f65
PP
149 * Open and start reading the next stream file
150 * within our stream file group.
94cf822e 151 */
fc917f65
PP
152 ret = msg_iter_data_set_current_ds_file(msg_iter_data);
153 if (ret) {
d24d5663 154 status = BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_ERROR;
fc917f65
PP
155 goto end;
156 }
157
158 /* Continue the loop to get the next message */
159 break;
94cf822e 160 }
fc917f65 161 default:
94cf822e
PP
162 goto end;
163 }
94cf822e 164 }
d01e0f33 165
94cf822e 166end:
d4393e08
PP
167 return status;
168}
169
170BT_HIDDEN
d24d5663 171bt_component_class_message_iterator_next_method_status ctf_fs_iterator_next(
d6e69534
PP
172 bt_self_message_iterator *iterator,
173 bt_message_array_const msgs, uint64_t capacity,
d4393e08
PP
174 uint64_t *count)
175{
cbca1c06 176 bt_component_class_message_iterator_next_method_status status;
d6e69534
PP
177 struct ctf_fs_msg_iter_data *msg_iter_data =
178 bt_self_message_iterator_get_data(iterator);
d4393e08
PP
179 uint64_t i = 0;
180
cbca1c06
SM
181 if (G_UNLIKELY(msg_iter_data->next_saved_error)) {
182 /*
183 * Last time we were called, we hit an error but had some
184 * messages to deliver, so we stashed the error here. Return
185 * it now.
186 */
187 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(msg_iter_data->next_saved_error);
188 status = msg_iter_data->next_saved_status;
189 goto end;
190 }
191
192 do {
d6e69534 193 status = ctf_fs_iterator_next_one(msg_iter_data, &msgs[i]);
d24d5663 194 if (status == BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK) {
d4393e08
PP
195 i++;
196 }
cbca1c06
SM
197 } while (i < capacity &&
198 status == BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK);
d4393e08
PP
199
200 if (i > 0) {
201 /*
202 * Even if ctf_fs_iterator_next_one() returned something
d24d5663 203 * else than BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK, we
d6e69534
PP
204 * accumulated message objects in the output
205 * message array, so we need to return
d24d5663 206 * BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK so that they are
d4393e08 207 * transfered to downstream. This other status occurs
d6e69534 208 * again the next time muxer_msg_iter_do_next() is
d4393e08 209 * called, possibly without any accumulated
d6e69534 210 * message, in which case we'll return it.
d4393e08 211 */
cbca1c06
SM
212 if (status < 0) {
213 /*
214 * Save this error for the next _next call. Assume that
215 * this component always appends error causes when
216 * returning an error status code, which will cause the
217 * current thread error to be non-NULL.
218 */
219 msg_iter_data->next_saved_error = bt_current_thread_take_error();
220 BT_ASSERT(msg_iter_data->next_saved_error);
221 msg_iter_data->next_saved_status = status;
222 }
223
d4393e08 224 *count = i;
d24d5663 225 status = BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK;
d4393e08
PP
226 }
227
cbca1c06 228end:
d4393e08 229 return status;
ea0b4b9e 230}
bfd20a42 231
6a9bb5e9
PP
232static
233int ctf_fs_iterator_reset(struct ctf_fs_msg_iter_data *msg_iter_data)
234{
235 int ret;
236
237 msg_iter_data->ds_file_info_index = 0;
238 ret = msg_iter_data_set_current_ds_file(msg_iter_data);
239 if (ret) {
240 goto end;
241 }
242
18a1979b 243 ctf_msg_iter_reset(msg_iter_data->msg_iter);
6a9bb5e9
PP
244 set_msg_iter_emits_stream_beginning_end_messages(msg_iter_data);
245
246end:
247 return ret;
248}
249
250BT_HIDDEN
d24d5663
PP
251bt_component_class_message_iterator_seek_beginning_method_status
252ctf_fs_iterator_seek_beginning(bt_self_message_iterator *it)
6a9bb5e9
PP
253{
254 struct ctf_fs_msg_iter_data *msg_iter_data =
255 bt_self_message_iterator_get_data(it);
d24d5663
PP
256 bt_component_class_message_iterator_seek_beginning_method_status status =
257 BT_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD_STATUS_OK;
6a9bb5e9
PP
258
259 BT_ASSERT(msg_iter_data);
260 if (ctf_fs_iterator_reset(msg_iter_data)) {
d24d5663 261 status = BT_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD_STATUS_ERROR;
6a9bb5e9
PP
262 }
263
264 return status;
265}
266
267BT_HIDDEN
d6e69534 268void ctf_fs_iterator_finalize(bt_self_message_iterator *it)
760051fa 269{
d6e69534
PP
270 ctf_fs_msg_iter_data_destroy(
271 bt_self_message_iterator_get_data(it));
760051fa
JG
272}
273
6a9bb5e9 274BT_HIDDEN
21a9f056 275bt_component_class_message_iterator_initialize_method_status ctf_fs_iterator_init(
d6e69534 276 bt_self_message_iterator *self_msg_iter,
8d8b141d 277 bt_self_message_iterator_configuration *config,
4c65a157 278 bt_self_component_source *self_comp_src,
b19ff26f 279 bt_self_component_port_output *self_port)
4c1456f0 280{
4f1f88a6 281 struct ctf_fs_port_data *port_data;
d6e69534 282 struct ctf_fs_msg_iter_data *msg_iter_data = NULL;
21a9f056
FD
283 bt_component_class_message_iterator_initialize_method_status ret =
284 BT_COMPONENT_CLASS_MESSAGE_ITERATOR_INITIALIZE_METHOD_STATUS_OK;
98903a3e 285 bt_logging_level log_level;
d23b766e
SM
286 bt_self_component *self_comp =
287 bt_self_component_source_as_self_component(self_comp_src);
760051fa 288
d94d92ac 289 port_data = bt_self_component_port_get_data(
707b7d35 290 bt_self_component_port_output_as_self_component_port(
d94d92ac
PP
291 self_port));
292 BT_ASSERT(port_data);
98903a3e 293 log_level = port_data->ctf_fs->log_level;
d6e69534
PP
294 msg_iter_data = g_new0(struct ctf_fs_msg_iter_data, 1);
295 if (!msg_iter_data) {
21a9f056 296 ret = BT_COMPONENT_CLASS_MESSAGE_ITERATOR_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
94cf822e
PP
297 goto error;
298 }
299
98903a3e 300 msg_iter_data->log_level = log_level;
4c65a157 301 msg_iter_data->self_comp = self_comp;
f30762e5 302 msg_iter_data->self_msg_iter = self_msg_iter;
18a1979b 303 msg_iter_data->msg_iter = ctf_msg_iter_create(
44c440bc 304 port_data->ds_file_group->ctf_fs_trace->metadata->tc,
98903a3e 305 bt_common_get_page_size(msg_iter_data->log_level) * 8,
4c65a157 306 ctf_fs_ds_file_medops, NULL, msg_iter_data->log_level,
851de941 307 self_comp, self_msg_iter);
d6e69534 308 if (!msg_iter_data->msg_iter) {
d23b766e 309 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot create a CTF message iterator.");
21a9f056 310 ret = BT_COMPONENT_CLASS_MESSAGE_ITERATOR_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
6de92955
PP
311 goto error;
312 }
313
d6e69534 314 msg_iter_data->ds_file_group = port_data->ds_file_group;
6a9bb5e9 315 if (ctf_fs_iterator_reset(msg_iter_data)) {
21a9f056 316 ret = BT_COMPONENT_CLASS_MESSAGE_ITERATOR_INITIALIZE_METHOD_STATUS_ERROR;
4f1f88a6 317 goto error;
760051fa
JG
318 }
319
c0e46a7c
SM
320 /*
321 * This iterator can seek forward if its stream class has a default
322 * clock class.
323 */
324 if (msg_iter_data->ds_file_group->sc->default_clock_class) {
325 bt_self_message_iterator_configuration_set_can_seek_forward(
326 config, true);
327 }
328
d6e69534
PP
329 bt_self_message_iterator_set_data(self_msg_iter,
330 msg_iter_data);
21a9f056 331 if (ret != BT_COMPONENT_CLASS_MESSAGE_ITERATOR_INITIALIZE_METHOD_STATUS_OK) {
4f1f88a6 332 goto error;
760051fa 333 }
d6e69534 334 msg_iter_data = NULL;
4f1f88a6 335 goto end;
5b29e799 336
4f1f88a6 337error:
d6e69534 338 bt_self_message_iterator_set_data(self_msg_iter, NULL);
4f1f88a6 339
760051fa 340end:
d6e69534 341 ctf_fs_msg_iter_data_destroy(msg_iter_data);
760051fa
JG
342 return ret;
343}
344
a0cd55ad
SM
345static
346void ctf_fs_trace_destroy(struct ctf_fs_trace *ctf_fs_trace)
347{
348 if (!ctf_fs_trace) {
349 return;
350 }
351
352 if (ctf_fs_trace->ds_file_groups) {
353 g_ptr_array_free(ctf_fs_trace->ds_file_groups, TRUE);
354 }
355
356 BT_TRACE_PUT_REF_AND_RESET(ctf_fs_trace->trace);
357
358 if (ctf_fs_trace->path) {
359 g_string_free(ctf_fs_trace->path, TRUE);
360 }
361
362 if (ctf_fs_trace->metadata) {
363 ctf_fs_metadata_fini(ctf_fs_trace->metadata);
364 g_free(ctf_fs_trace->metadata);
365 }
366
367 g_free(ctf_fs_trace);
368}
369
f280892e 370BT_HIDDEN
1a9f7075 371void ctf_fs_destroy(struct ctf_fs_component *ctf_fs)
760051fa 372{
4f1f88a6 373 if (!ctf_fs) {
8fa760ba
JG
374 return;
375 }
4f1f88a6 376
a0cd55ad 377 ctf_fs_trace_destroy(ctf_fs->trace);
4f1f88a6
PP
378
379 if (ctf_fs->port_data) {
380 g_ptr_array_free(ctf_fs->port_data, TRUE);
c14d7e26 381 }
760051fa 382
1a9f7075
PP
383 g_free(ctf_fs);
384}
385
f280892e
SM
386static
387void port_data_destroy(struct ctf_fs_port_data *port_data)
388{
389 if (!port_data) {
390 return;
391 }
392
393 g_free(port_data);
394}
395
396static
397void port_data_destroy_notifier(void *data) {
398 port_data_destroy(data);
399}
400
97ade20b 401static
56a924f4 402void ctf_fs_trace_destroy_notifier(void *data)
97ade20b
JG
403{
404 struct ctf_fs_trace *trace = data;
405 ctf_fs_trace_destroy(trace);
406}
407
4c65a157
PP
408struct ctf_fs_component *ctf_fs_component_create(bt_logging_level log_level,
409 bt_self_component *self_comp)
a4792757 410{
f280892e 411 struct ctf_fs_component *ctf_fs;
a4792757 412
f280892e
SM
413 ctf_fs = g_new0(struct ctf_fs_component, 1);
414 if (!ctf_fs) {
415 goto error;
416 }
4f1f88a6 417
98903a3e 418 ctf_fs->log_level = log_level;
f280892e
SM
419 ctf_fs->port_data =
420 g_ptr_array_new_with_free_func(port_data_destroy_notifier);
421 if (!ctf_fs->port_data) {
422 goto error;
4f1f88a6
PP
423 }
424
f280892e
SM
425 goto end;
426
427error:
bce64edb
SM
428 ctf_fs_destroy(ctf_fs);
429 ctf_fs = NULL;
f280892e
SM
430
431end:
432 return ctf_fs;
433}
434
435void ctf_fs_finalize(bt_self_component_source *component)
436{
437 ctf_fs_destroy(bt_self_component_get_data(
438 bt_self_component_source_as_self_component(component)));
5b29e799
JG
439}
440
a38d7650 441gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group)
547eacf1 442{
a38d7650 443 GString *name = g_string_new(NULL);
547eacf1 444
a38d7650
SM
445 /*
446 * The unique port name is generated by concatenating unique identifiers
447 * for:
448 *
449 * - the trace
450 * - the stream class
451 * - the stream
452 */
453
454 /* For the trace, use the uuid if present, else the path. */
455 if (ds_file_group->ctf_fs_trace->metadata->tc->is_uuid_set) {
6162e6b7 456 char uuid_str[BT_UUID_STR_LEN + 1];
a38d7650 457
6162e6b7 458 bt_uuid_to_str(ds_file_group->ctf_fs_trace->metadata->tc->uuid, uuid_str);
a38d7650
SM
459 g_string_assign(name, uuid_str);
460 } else {
461 g_string_assign(name, ds_file_group->ctf_fs_trace->path->str);
547eacf1
PP
462 }
463
464 /*
a38d7650
SM
465 * For the stream class, use the id if present. We can omit this field
466 * otherwise, as there will only be a single stream class.
547eacf1 467 */
a38d7650
SM
468 if (ds_file_group->sc->id != UINT64_C(-1)) {
469 g_string_append_printf(name, " | %" PRIu64, ds_file_group->sc->id);
470 }
547eacf1 471
a38d7650
SM
472 /* For the stream, use the id if present, else, use the path. */
473 if (ds_file_group->stream_id != UINT64_C(-1)) {
474 g_string_append_printf(name, " | %" PRIu64, ds_file_group->stream_id);
475 } else {
476 BT_ASSERT(ds_file_group->ds_file_infos->len == 1);
477 struct ctf_fs_ds_file_info *ds_file_info =
478 g_ptr_array_index(ds_file_group->ds_file_infos, 0);
479 g_string_append_printf(name, " | %s", ds_file_info->path->str);
480 }
481
482 return g_string_free(name, FALSE);
547eacf1
PP
483}
484
5b29e799 485static
55314f2a
JG
486int create_one_port_for_trace(struct ctf_fs_component *ctf_fs,
487 struct ctf_fs_trace *ctf_fs_trace,
d23b766e
SM
488 struct ctf_fs_ds_file_group *ds_file_group,
489 bt_self_component_source *self_comp_src)
5b29e799 490{
4f1f88a6 491 int ret = 0;
4f1f88a6 492 struct ctf_fs_port_data *port_data = NULL;
a38d7650 493 gchar *port_name;
98903a3e 494 bt_logging_level log_level = ctf_fs->log_level;
d23b766e
SM
495 bt_self_component *self_comp =
496 bt_self_component_source_as_self_component(self_comp_src);
4f1f88a6 497
a38d7650 498 port_name = ctf_fs_make_port_name(ds_file_group);
4f1f88a6
PP
499 if (!port_name) {
500 goto error;
501 }
502
4c65a157 503 BT_COMP_LOGI("Creating one port named `%s`", port_name);
4f1f88a6
PP
504
505 /* Create output port for this file */
4f1f88a6
PP
506 port_data = g_new0(struct ctf_fs_port_data, 1);
507 if (!port_data) {
508 goto error;
509 }
510
5c563278 511 port_data->ctf_fs = ctf_fs;
94cf822e 512 port_data->ds_file_group = ds_file_group;
d94d92ac 513 ret = bt_self_component_source_add_output_port(
d23b766e 514 self_comp_src, port_name, port_data, NULL);
147337a3 515 if (ret) {
4f1f88a6
PP
516 goto error;
517 }
518
519 g_ptr_array_add(ctf_fs->port_data, port_data);
520 port_data = NULL;
521 goto end;
522
523error:
524 ret = -1;
525
526end:
19bbdc9b 527 g_free(port_name);
4f1f88a6 528
4f1f88a6
PP
529 port_data_destroy(port_data);
530 return ret;
5b29e799
JG
531}
532
533static
55314f2a 534int create_ports_for_trace(struct ctf_fs_component *ctf_fs,
d23b766e
SM
535 struct ctf_fs_trace *ctf_fs_trace,
536 bt_self_component_source *self_comp_src)
94cf822e
PP
537{
538 int ret = 0;
94cf822e 539 size_t i;
98903a3e 540 bt_logging_level log_level = ctf_fs_trace->log_level;
d23b766e
SM
541 bt_self_component *self_comp =
542 bt_self_component_source_as_self_component(self_comp_src);
94cf822e
PP
543
544 /* Create one output port for each stream file group */
545 for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
546 struct ctf_fs_ds_file_group *ds_file_group =
547 g_ptr_array_index(ctf_fs_trace->ds_file_groups, i);
548
55314f2a 549 ret = create_one_port_for_trace(ctf_fs, ctf_fs_trace,
d23b766e 550 ds_file_group, self_comp_src);
94cf822e 551 if (ret) {
d23b766e 552 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot create output port.");
94cf822e
PP
553 goto end;
554 }
555 }
556
557end:
558 return ret;
559}
560
94cf822e
PP
561static
562void ctf_fs_ds_file_info_destroy(struct ctf_fs_ds_file_info *ds_file_info)
563{
564 if (!ds_file_info) {
565 return;
566 }
567
568 if (ds_file_info->path) {
569 g_string_free(ds_file_info->path, TRUE);
570 }
571
572 g_free(ds_file_info);
573}
574
575static
576struct ctf_fs_ds_file_info *ctf_fs_ds_file_info_create(const char *path,
7ed5243a 577 int64_t begin_ns)
94cf822e
PP
578{
579 struct ctf_fs_ds_file_info *ds_file_info;
580
581 ds_file_info = g_new0(struct ctf_fs_ds_file_info, 1);
582 if (!ds_file_info) {
583 goto end;
584 }
585
586 ds_file_info->path = g_string_new(path);
587 if (!ds_file_info->path) {
588 ctf_fs_ds_file_info_destroy(ds_file_info);
589 ds_file_info = NULL;
590 goto end;
591 }
592
593 ds_file_info->begin_ns = begin_ns;
594
595end:
596 return ds_file_info;
597}
598
599static
600void ctf_fs_ds_file_group_destroy(struct ctf_fs_ds_file_group *ds_file_group)
601{
602 if (!ds_file_group) {
603 return;
604 }
605
606 if (ds_file_group->ds_file_infos) {
607 g_ptr_array_free(ds_file_group->ds_file_infos, TRUE);
608 }
609
7ed5243a
FD
610 if (ds_file_group->index) {
611 if (ds_file_group->index->entries) {
612 g_ptr_array_free(ds_file_group->index->entries, TRUE);
613 }
614 g_free(ds_file_group->index);
615 }
616
c5b9b441 617 bt_stream_put_ref(ds_file_group->stream);
94cf822e
PP
618 g_free(ds_file_group);
619}
620
621static
622struct ctf_fs_ds_file_group *ctf_fs_ds_file_group_create(
623 struct ctf_fs_trace *ctf_fs_trace,
60363f2f 624 struct ctf_stream_class *sc,
7ed5243a
FD
625 uint64_t stream_instance_id,
626 struct ctf_fs_ds_index *index)
94cf822e
PP
627{
628 struct ctf_fs_ds_file_group *ds_file_group;
629
94cf822e
PP
630 ds_file_group = g_new0(struct ctf_fs_ds_file_group, 1);
631 if (!ds_file_group) {
632 goto error;
633 }
634
635 ds_file_group->ds_file_infos = g_ptr_array_new_with_free_func(
636 (GDestroyNotify) ctf_fs_ds_file_info_destroy);
637 if (!ds_file_group->ds_file_infos) {
638 goto error;
639 }
640
7ed5243a
FD
641 ds_file_group->index = index;
642
547eacf1 643 ds_file_group->stream_id = stream_instance_id;
60363f2f
PP
644 BT_ASSERT(sc);
645 ds_file_group->sc = sc;
94cf822e 646 ds_file_group->ctf_fs_trace = ctf_fs_trace;
94cf822e
PP
647 goto end;
648
649error:
650 ctf_fs_ds_file_group_destroy(ds_file_group);
7ed5243a 651 ctf_fs_ds_index_destroy(index);
94cf822e
PP
652 ds_file_group = NULL;
653
654end:
655 return ds_file_group;
656}
657
8bf7105e
MJ
658/* Replace by g_ptr_array_insert when we depend on glib >= 2.40. */
659static
660void array_insert(GPtrArray *array, gpointer element, size_t pos)
661{
662 size_t original_array_len = array->len;
663
664 /* Allocate an unused element at the end of the array. */
665 g_ptr_array_add(array, NULL);
666
667 /* If we are not inserting at the end, move the elements by one. */
668 if (pos < original_array_len) {
669 memmove(&(array->pdata[pos + 1]),
670 &(array->pdata[pos]),
671 (original_array_len - pos) * sizeof(gpointer));
672 }
673
f897d50c 674 /* Insert the value. */
8bf7105e
MJ
675 array->pdata[pos] = element;
676}
677
41a65f30
SM
678/*
679 * Insert ds_file_info in ds_file_group's list of ds_file_infos at the right
680 * place to keep it sorted.
681 */
682
683static
684void ds_file_group_insert_ds_file_info_sorted(
685 struct ctf_fs_ds_file_group *ds_file_group,
686 struct ctf_fs_ds_file_info *ds_file_info)
687{
688 guint i;
689
690 /* Find the spot where to insert this ds_file_info. */
691 for (i = 0; i < ds_file_group->ds_file_infos->len; i++) {
692 struct ctf_fs_ds_file_info *other_ds_file_info =
693 g_ptr_array_index(ds_file_group->ds_file_infos, i);
694
695 if (ds_file_info->begin_ns < other_ds_file_info->begin_ns) {
696 break;
697 }
698 }
699
700 array_insert(ds_file_group->ds_file_infos, ds_file_info, i);
701}
702
1505f33a
SM
703static
704bool ds_index_entries_equal(
705 const struct ctf_fs_ds_index_entry *left,
706 const struct ctf_fs_ds_index_entry *right)
707{
708 if (left->packet_size != right->packet_size) {
709 return false;
710 }
711
712 if (left->timestamp_begin != right->timestamp_begin) {
713 return false;
714 }
715
716 if (left->timestamp_end != right->timestamp_end) {
717 return false;
718 }
719
720 if (left->packet_seq_num != right->packet_seq_num) {
721 return false;
722 }
723
724 return true;
725}
726
727/*
728 * Insert `entry` into `index`, without duplication.
729 *
730 * The entry is inserted only if there isn't an identical entry already.
731 *
732 * In any case, the ownership of `entry` is transferred to this function. So if
733 * the entry is not inserted, it is freed.
734 */
735
7ed5243a 736static
ce75de14
SM
737void ds_index_insert_ds_index_entry_sorted(
738 struct ctf_fs_ds_index *index,
7ed5243a
FD
739 struct ctf_fs_ds_index_entry *entry)
740{
741 guint i;
1505f33a 742 struct ctf_fs_ds_index_entry *other_entry;
7ed5243a
FD
743
744 /* Find the spot where to insert this index entry. */
ce75de14 745 for (i = 0; i < index->entries->len; i++) {
1505f33a 746 other_entry = g_ptr_array_index(index->entries, i);
7ed5243a 747
1505f33a 748 if (entry->timestamp_begin_ns <= other_entry->timestamp_begin_ns) {
7ed5243a
FD
749 break;
750 }
751 }
752
1505f33a
SM
753 /*
754 * Insert the entry only if a duplicate doesn't already exist.
755 *
756 * There can be duplicate packets if reading multiple overlapping
757 * snapshots of the same trace. We then want the index to contain
758 * a reference to only one copy of that packet.
759 */
760 if (i == index->entries->len ||
761 !ds_index_entries_equal(entry, other_entry)) {
762 array_insert(index->entries, entry, i);
763 } else {
764 g_free(entry);
765 }
ce75de14
SM
766}
767
768static
769void merge_ctf_fs_ds_indexes(struct ctf_fs_ds_index *dest, struct ctf_fs_ds_index *src)
770{
771 guint i;
772
773 for (i = 0; i < src->entries->len; i++) {
774 struct ctf_fs_ds_index_entry *entry =
775 g_ptr_array_index(src->entries, i);
776
777 /*
778 * Ownership of the ctf_fs_ds_index_entry is transferred to
1505f33a 779 * ds_index_insert_ds_index_entry_sorted.
ce75de14
SM
780 */
781 g_ptr_array_index(src->entries, i) = NULL;
ce75de14
SM
782 ds_index_insert_ds_index_entry_sorted(dest, entry);
783 }
7ed5243a
FD
784}
785
94cf822e
PP
786static
787int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
e5be10ef 788 const char *path)
94cf822e 789{
44c440bc
PP
790 int64_t stream_instance_id = -1;
791 int64_t begin_ns = -1;
94cf822e
PP
792 struct ctf_fs_ds_file_group *ds_file_group = NULL;
793 bool add_group = false;
794 int ret;
795 size_t i;
6de92955 796 struct ctf_fs_ds_file *ds_file = NULL;
bf012bde 797 struct ctf_fs_ds_file_info *ds_file_info = NULL;
97ade20b 798 struct ctf_fs_ds_index *index = NULL;
18a1979b 799 struct ctf_msg_iter *msg_iter = NULL;
44c440bc 800 struct ctf_stream_class *sc = NULL;
18a1979b 801 struct ctf_msg_iter_packet_properties props;
98903a3e 802 bt_logging_level log_level = ctf_fs_trace->log_level;
4c65a157 803 bt_self_component *self_comp = ctf_fs_trace->self_comp;
b7d2695a 804 bt_self_component_class *self_comp_class = ctf_fs_trace->self_comp_class;
94cf822e 805
18a1979b 806 msg_iter = ctf_msg_iter_create(ctf_fs_trace->metadata->tc,
98903a3e 807 bt_common_get_page_size(log_level) * 8,
851de941 808 ctf_fs_ds_file_medops, NULL, log_level, self_comp, NULL);
d6e69534 809 if (!msg_iter) {
4c65a157 810 BT_COMP_LOGE_STR("Cannot create a CTF message iterator.");
6de92955
PP
811 goto error;
812 }
813
d6e69534 814 ds_file = ctf_fs_ds_file_create(ctf_fs_trace, NULL, msg_iter,
98903a3e 815 NULL, path, log_level);
97ade20b
JG
816 if (!ds_file) {
817 goto error;
818 }
819
18a1979b 820 ret = ctf_msg_iter_get_packet_properties(ds_file->msg_iter, &props);
94cf822e 821 if (ret) {
b7d2695a 822 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
d23b766e 823 "Cannot get stream file's first packet's header and context fields (`%s`).",
94cf822e
PP
824 path);
825 goto error;
826 }
827
44c440bc
PP
828 sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
829 props.stream_class_id);
830 BT_ASSERT(sc);
44c440bc
PP
831 stream_instance_id = props.data_stream_id;
832
833 if (props.snapshots.beginning_clock != UINT64_C(-1)) {
834 BT_ASSERT(sc->default_clock_class);
0f2d58c9
PP
835 ret = bt_util_clock_cycles_to_ns_from_origin(
836 props.snapshots.beginning_clock,
837 sc->default_clock_class->frequency,
838 sc->default_clock_class->offset_seconds,
839 sc->default_clock_class->offset_cycles, &begin_ns);
44c440bc 840 if (ret) {
b7d2695a 841 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
d23b766e 842 "Cannot convert clock cycles to nanoseconds from origin (`%s`).",
44c440bc
PP
843 path);
844 goto error;
845 }
94cf822e
PP
846 }
847
bf012bde
FD
848 ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns);
849 if (!ds_file_info) {
850 goto error;
851 }
852
853 index = ctf_fs_ds_file_build_index(ds_file, ds_file_info);
97ade20b 854 if (!index) {
29a8227a
SM
855 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
856 self_comp, self_comp_class,
857 "Failed to index CTF stream file \'%s\'",
97ade20b 858 ds_file->file->path->str);
29a8227a 859 goto error;
97ade20b
JG
860 }
861
44c440bc 862 if (begin_ns == -1) {
94cf822e
PP
863 /*
864 * No beggining timestamp to sort the stream files
865 * within a stream file group, so consider that this
866 * file must be the only one within its group.
867 */
44c440bc 868 stream_instance_id = -1;
94cf822e
PP
869 }
870
44c440bc 871 if (stream_instance_id == -1) {
94cf822e
PP
872 /*
873 * No stream instance ID or no beginning timestamp:
874 * create a unique stream file group for this stream
875 * file because, even if there's a stream instance ID,
876 * there's no timestamp to order the file within its
877 * group.
878 */
94cf822e 879 ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace,
7ed5243a
FD
880 sc, UINT64_C(-1), index);
881 /* Ownership of index is transferred. */
882 index = NULL;
883
94cf822e
PP
884 if (!ds_file_group) {
885 goto error;
886 }
887
55b71f05
SM
888 ds_file_group_insert_ds_file_info_sorted(ds_file_group,
889 BT_MOVE_REF(ds_file_info));
94cf822e
PP
890
891 add_group = true;
892 goto end;
893 }
894
44c440bc
PP
895 BT_ASSERT(stream_instance_id != -1);
896 BT_ASSERT(begin_ns != -1);
94cf822e
PP
897
898 /* Find an existing stream file group with this ID */
899 for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
94cf822e
PP
900 ds_file_group = g_ptr_array_index(
901 ctf_fs_trace->ds_file_groups, i);
94cf822e 902
60363f2f 903 if (ds_file_group->sc == sc &&
547eacf1
PP
904 ds_file_group->stream_id ==
905 stream_instance_id) {
94cf822e
PP
906 break;
907 }
908
909 ds_file_group = NULL;
910 }
911
912 if (!ds_file_group) {
913 ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace,
7ed5243a
FD
914 sc, stream_instance_id, index);
915 /* Ownership of index is transferred. */
916 index = NULL;
94cf822e
PP
917 if (!ds_file_group) {
918 goto error;
919 }
920
921 add_group = true;
ce75de14
SM
922 } else {
923 merge_ctf_fs_ds_indexes(ds_file_group->index, index);
94cf822e
PP
924 }
925
55b71f05
SM
926 ds_file_group_insert_ds_file_info_sorted(ds_file_group,
927 BT_MOVE_REF(ds_file_info));
94cf822e
PP
928
929 goto end;
930
931error:
932 ctf_fs_ds_file_group_destroy(ds_file_group);
90e1eb09 933 ds_file_group = NULL;
94cf822e
PP
934 ret = -1;
935
936end:
937 if (add_group && ds_file_group) {
938 g_ptr_array_add(ctf_fs_trace->ds_file_groups, ds_file_group);
939 }
547eacf1 940
97ade20b 941 ctf_fs_ds_file_destroy(ds_file);
55b71f05 942 ctf_fs_ds_file_info_destroy(ds_file_info);
6de92955 943
d6e69534 944 if (msg_iter) {
18a1979b 945 ctf_msg_iter_destroy(msg_iter);
6de92955
PP
946 }
947
97ade20b 948 ctf_fs_ds_index_destroy(index);
94cf822e
PP
949 return ret;
950}
951
952static
e5be10ef 953int create_ds_file_groups(struct ctf_fs_trace *ctf_fs_trace)
e7a4393b
JG
954{
955 int ret = 0;
4f1f88a6 956 const char *basename;
e7a4393b 957 GError *error = NULL;
4f1f88a6 958 GDir *dir = NULL;
98903a3e 959 bt_logging_level log_level = ctf_fs_trace->log_level;
4c65a157 960 bt_self_component *self_comp = ctf_fs_trace->self_comp;
b7d2695a 961 bt_self_component_class *self_comp_class = ctf_fs_trace->self_comp_class;
e7a4393b 962
94cf822e 963 /* Check each file in the path directory, except specific ones */
1a9f7075 964 dir = g_dir_open(ctf_fs_trace->path->str, 0, &error);
e7a4393b 965 if (!dir) {
b7d2695a
SM
966 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
967 "Cannot open directory `%s`: %s (code %d)",
1a9f7075 968 ctf_fs_trace->path->str, error->message,
4f1f88a6 969 error->code);
e7a4393b
JG
970 goto error;
971 }
972
4f1f88a6 973 while ((basename = g_dir_read_name(dir))) {
94cf822e
PP
974 struct ctf_fs_file *file;
975
2242b43d 976 if (strcmp(basename, CTF_FS_METADATA_FILENAME) == 0) {
e7a4393b 977 /* Ignore the metadata stream. */
4c65a157 978 BT_COMP_LOGI("Ignoring metadata file `%s" G_DIR_SEPARATOR_S "%s`",
1a9f7075 979 ctf_fs_trace->path->str, basename);
e7a4393b
JG
980 continue;
981 }
982
4f1f88a6 983 if (basename[0] == '.') {
4c65a157 984 BT_COMP_LOGI("Ignoring hidden file `%s" G_DIR_SEPARATOR_S "%s`",
1a9f7075 985 ctf_fs_trace->path->str, basename);
e7a4393b
JG
986 continue;
987 }
988
989 /* Create the file. */
4c65a157 990 file = ctf_fs_file_create(log_level, self_comp);
e7a4393b 991 if (!file) {
b7d2695a 992 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
d23b766e 993 "Cannot create stream file object for file `%s" G_DIR_SEPARATOR_S "%s`",
1a9f7075 994 ctf_fs_trace->path->str, basename);
e7a4393b
JG
995 goto error;
996 }
997
998 /* Create full path string. */
3743a302 999 g_string_append_printf(file->path, "%s" G_DIR_SEPARATOR_S "%s",
1a9f7075 1000 ctf_fs_trace->path->str, basename);
e7a4393b 1001 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
4c65a157 1002 BT_COMP_LOGI("Ignoring non-regular file `%s`",
1a9f7075 1003 file->path->str);
e7a4393b 1004 ctf_fs_file_destroy(file);
4f1f88a6 1005 file = NULL;
e7a4393b
JG
1006 continue;
1007 }
1008
55314f2a 1009 ret = ctf_fs_file_open(file, "rb");
4f1f88a6 1010 if (ret) {
b7d2695a
SM
1011 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
1012 "Cannot open stream file `%s`",
d23b766e 1013 file->path->str);
e7a4393b
JG
1014 goto error;
1015 }
1016
9fa0891a
JG
1017 if (file->size == 0) {
1018 /* Skip empty stream. */
4c65a157 1019 BT_COMP_LOGI("Ignoring empty file `%s`", file->path->str);
9fa0891a
JG
1020 ctf_fs_file_destroy(file);
1021 continue;
1022 }
1023
e5be10ef 1024 ret = add_ds_file_to_ds_file_group(ctf_fs_trace,
94cf822e 1025 file->path->str);
4f1f88a6 1026 if (ret) {
b7d2695a 1027 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
d23b766e 1028 "Cannot add stream file `%s` to stream file group",
1a9f7075 1029 file->path->str);
94cf822e 1030 ctf_fs_file_destroy(file);
e7a4393b
JG
1031 goto error;
1032 }
1033
4f1f88a6 1034 ctf_fs_file_destroy(file);
e7a4393b
JG
1035 }
1036
1037 goto end;
4f1f88a6 1038
e7a4393b
JG
1039error:
1040 ret = -1;
4f1f88a6 1041
e7a4393b
JG
1042end:
1043 if (dir) {
1044 g_dir_close(dir);
1045 dir = NULL;
1046 }
4f1f88a6 1047
e7a4393b
JG
1048 if (error) {
1049 g_error_free(error);
1050 }
5b29e799 1051
91457551 1052 return ret;
5b29e799
JG
1053}
1054
862ca4ed 1055static
98903a3e 1056int set_trace_name(bt_trace *trace, const char *name_suffix,
4c65a157 1057 bt_logging_level log_level, bt_self_component *self_comp)
862ca4ed
PP
1058{
1059 int ret = 0;
b19ff26f 1060 const bt_value *val;
862ca4ed
PP
1061 GString *name;
1062
1063 name = g_string_new(NULL);
1064 if (!name) {
4c65a157 1065 BT_COMP_LOGE_STR("Failed to allocate a GString.");
862ca4ed
PP
1066 ret = -1;
1067 goto end;
1068 }
1069
1070 /*
1071 * Check if we have a trace environment string value named `hostname`.
1072 * If so, use it as the trace name's prefix.
1073 */
335a2da5
PP
1074 val = bt_trace_borrow_environment_entry_value_by_name_const(
1075 trace, "hostname");
862ca4ed
PP
1076 if (val && bt_value_is_string(val)) {
1077 g_string_append(name, bt_value_string_get(val));
1078
1079 if (name_suffix) {
1080 g_string_append_c(name, G_DIR_SEPARATOR);
1081 }
1082 }
1083
1084 if (name_suffix) {
1085 g_string_append(name, name_suffix);
1086 }
1087
1088 ret = bt_trace_set_name(trace, name->str);
1089 if (ret) {
1090 goto end;
1091 }
1092
1093 goto end;
1094
1095end:
1096 if (name) {
1097 g_string_free(name, TRUE);
1098 }
1099
1100 return ret;
1101}
1102
f280892e 1103static
b7d2695a
SM
1104struct ctf_fs_trace *ctf_fs_trace_create(
1105 bt_self_component *self_comp,
1106 bt_self_component_class *self_comp_class,
41693723 1107 const char *path, const char *name,
98903a3e
PP
1108 struct ctf_fs_metadata_config *metadata_config,
1109 bt_logging_level log_level)
1a9f7075
PP
1110{
1111 struct ctf_fs_trace *ctf_fs_trace;
1112 int ret;
1113
b7d2695a
SM
1114 /* Only one of them must be set. */
1115 BT_ASSERT(!self_comp != !self_comp_class);
1116
1a9f7075
PP
1117 ctf_fs_trace = g_new0(struct ctf_fs_trace, 1);
1118 if (!ctf_fs_trace) {
1119 goto end;
1120 }
1121
98903a3e 1122 ctf_fs_trace->log_level = log_level;
4c65a157 1123 ctf_fs_trace->self_comp = self_comp;
b7d2695a 1124 ctf_fs_trace->self_comp_class = self_comp_class;
1a9f7075
PP
1125 ctf_fs_trace->path = g_string_new(path);
1126 if (!ctf_fs_trace->path) {
1127 goto error;
1128 }
1129
1a9f7075
PP
1130 ctf_fs_trace->metadata = g_new0(struct ctf_fs_metadata, 1);
1131 if (!ctf_fs_trace->metadata) {
1132 goto error;
1133 }
1134
44c440bc 1135 ctf_fs_metadata_init(ctf_fs_trace->metadata);
94cf822e
PP
1136 ctf_fs_trace->ds_file_groups = g_ptr_array_new_with_free_func(
1137 (GDestroyNotify) ctf_fs_ds_file_group_destroy);
1138 if (!ctf_fs_trace->ds_file_groups) {
1139 goto error;
1140 }
1141
4c65a157
PP
1142 ret = ctf_fs_metadata_set_trace_class(self_comp, ctf_fs_trace,
1143 metadata_config);
862ca4ed
PP
1144 if (ret) {
1145 goto error;
1146 }
1147
41693723
PP
1148 if (ctf_fs_trace->metadata->trace_class) {
1149 ctf_fs_trace->trace =
1150 bt_trace_create(ctf_fs_trace->metadata->trace_class);
1151 if (!ctf_fs_trace->trace) {
1152 goto error;
1153 }
862ca4ed
PP
1154 }
1155
41693723 1156 if (ctf_fs_trace->trace) {
335a2da5
PP
1157 ret = ctf_trace_class_configure_ir_trace(
1158 ctf_fs_trace->metadata->tc, ctf_fs_trace->trace);
1159 if (ret) {
1160 goto error;
1161 }
1162
4c65a157
PP
1163 ret = set_trace_name(ctf_fs_trace->trace, name, log_level,
1164 self_comp);
41693723
PP
1165 if (ret) {
1166 goto error;
1167 }
1a9f7075
PP
1168 }
1169
e5be10ef 1170 ret = create_ds_file_groups(ctf_fs_trace);
94cf822e
PP
1171 if (ret) {
1172 goto error;
1173 }
1174
1a9f7075
PP
1175 goto end;
1176
1177error:
1178 ctf_fs_trace_destroy(ctf_fs_trace);
1179 ctf_fs_trace = NULL;
44c440bc 1180
1a9f7075
PP
1181end:
1182 return ctf_fs_trace;
1183}
1184
1185static
1186int path_is_ctf_trace(const char *path)
1187{
1188 GString *metadata_path = g_string_new(NULL);
1189 int ret = 0;
1190
1191 if (!metadata_path) {
1192 ret = -1;
1193 goto end;
1194 }
1195
3743a302 1196 g_string_printf(metadata_path, "%s" G_DIR_SEPARATOR_S "%s", path, CTF_FS_METADATA_FILENAME);
1a9f7075
PP
1197
1198 if (g_file_test(metadata_path->str, G_FILE_TEST_IS_REGULAR)) {
1199 ret = 1;
1200 goto end;
1201 }
1202
1203end:
1204 g_string_free(metadata_path, TRUE);
1205 return ret;
1206}
1207
a0cd55ad 1208/* Helper for ctf_fs_component_create_ctf_fs_trace, to handle a single path. */
f280892e 1209
1a9f7075 1210static
a0cd55ad 1211int ctf_fs_component_create_ctf_fs_trace_one_path(
41693723 1212 struct ctf_fs_component *ctf_fs,
d23b766e 1213 const char *path_param,
005d49d6 1214 const char *trace_name,
a0cd55ad 1215 GPtrArray *traces,
d23b766e
SM
1216 bt_self_component *self_comp,
1217 bt_self_component_class *self_comp_class)
1a9f7075 1218{
48881202
SM
1219 struct ctf_fs_trace *ctf_fs_trace;
1220 int ret;
1221 GString *norm_path;
98903a3e 1222 bt_logging_level log_level = ctf_fs->log_level;
1a9f7075 1223
4bd72b60
PP
1224 norm_path = bt_common_normalize_path(path_param, NULL);
1225 if (!norm_path) {
d23b766e 1226 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
b7d2695a
SM
1227 "Failed to normalize path: `%s`.",
1228 path_param);
4bd72b60
PP
1229 goto error;
1230 }
1231
48881202
SM
1232 ret = path_is_ctf_trace(norm_path->str);
1233 if (ret < 0) {
1234 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
b7d2695a
SM
1235 "Failed to check if path is a CTF trace: path=%s",
1236 norm_path->str);
48881202
SM
1237 goto error;
1238 } else if (ret == 0) {
1239 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
b7d2695a
SM
1240 "Path is not a CTF trace (does not contain a metadata file): `%s`.",
1241 norm_path->str);
1a9f7075
PP
1242 goto error;
1243 }
1244
48881202
SM
1245 // FIXME: Remove or ifdef for __MINGW32__
1246 if (strcmp(norm_path->str, "/") == 0) {
d23b766e 1247 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
48881202
SM
1248 "Opening a trace in `/` is not supported.");
1249 ret = -1;
1250 goto end;
1a9f7075
PP
1251 }
1252
b7d2695a 1253 ctf_fs_trace = ctf_fs_trace_create(self_comp, self_comp_class, norm_path->str,
005d49d6 1254 trace_name, &ctf_fs->metadata_config, log_level);
48881202 1255 if (!ctf_fs_trace) {
b7d2695a
SM
1256 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
1257 "Cannot create trace for `%s`.",
48881202 1258 norm_path->str);
1a9f7075
PP
1259 goto error;
1260 }
1261
a0cd55ad 1262 g_ptr_array_add(traces, ctf_fs_trace);
48881202 1263 ctf_fs_trace = NULL;
1a9f7075 1264
48881202 1265 ret = 0;
1a9f7075
PP
1266 goto end;
1267
1268error:
1269 ret = -1;
1a9f7075
PP
1270
1271end:
4bd72b60
PP
1272 if (norm_path) {
1273 g_string_free(norm_path, TRUE);
1274 }
1275
1a9f7075
PP
1276 return ret;
1277}
1278
41a65f30
SM
1279/*
1280 * Count the number of stream and event classes defined by this trace's metadata.
1281 *
1282 * This is used to determine which metadata is the "latest", out of multiple
1283 * traces sharing the same UUID. It is assumed that amongst all these metadatas,
1284 * a bigger metadata is a superset of a smaller metadata. Therefore, it is
1285 * enough to just count the classes.
1286 */
1287
1288static
1289unsigned int metadata_count_stream_and_event_classes(struct ctf_fs_trace *trace)
1290{
1291 unsigned int num = trace->metadata->tc->stream_classes->len;
1292 guint i;
1293
1294 for (i = 0; i < trace->metadata->tc->stream_classes->len; i++) {
1295 struct ctf_stream_class *sc = trace->metadata->tc->stream_classes->pdata[i];
1296 num += sc->event_classes->len;
1297 }
1298
1299 return num;
1300}
1301
1302/*
1303 * Merge the src ds_file_group into dest. This consists of merging their
1304 * ds_file_infos, making sure to keep the result sorted.
1305 */
1306
1307static
1308void merge_ctf_fs_ds_file_groups(struct ctf_fs_ds_file_group *dest, struct ctf_fs_ds_file_group *src)
1309{
1310 guint i;
1311
1312 for (i = 0; i < src->ds_file_infos->len; i++) {
1313 struct ctf_fs_ds_file_info *ds_file_info =
1314 g_ptr_array_index(src->ds_file_infos, i);
1315
1316 /* Ownership of the ds_file_info is transferred to dest. */
1317 g_ptr_array_index(src->ds_file_infos, i) = NULL;
1318
1319 ds_file_group_insert_ds_file_info_sorted(dest, ds_file_info);
1320 }
41a65f30 1321
7ed5243a 1322 /* Merge both indexes. */
ce75de14 1323 merge_ctf_fs_ds_indexes(dest->index, src->index);
7ed5243a 1324}
41a65f30
SM
1325/* Merge src_trace's data stream file groups into dest_trace's. */
1326
1327static
54ef52bd 1328int merge_matching_ctf_fs_ds_file_groups(
41a65f30
SM
1329 struct ctf_fs_trace *dest_trace,
1330 struct ctf_fs_trace *src_trace)
1331{
1332
1333 GPtrArray *dest = dest_trace->ds_file_groups;
1334 GPtrArray *src = src_trace->ds_file_groups;
1335 guint s_i;
54ef52bd 1336 int ret = 0;
41a65f30
SM
1337
1338 /*
1339 * Save the initial length of dest: we only want to check against the
1340 * original elements in the inner loop.
1341 */
1342 const guint dest_len = dest->len;
1343
1344 for (s_i = 0; s_i < src->len; s_i++) {
1345 struct ctf_fs_ds_file_group *src_group = g_ptr_array_index(src, s_i);
1346 struct ctf_fs_ds_file_group *dest_group = NULL;
1347
1348 /* A stream instance without ID can't match a stream in the other trace. */
1349 if (src_group->stream_id != -1) {
1350 guint d_i;
1351
1352 /* Let's search for a matching ds_file_group in the destination. */
1353 for (d_i = 0; d_i < dest_len; d_i++) {
1354 struct ctf_fs_ds_file_group *candidate_dest = g_ptr_array_index(dest, d_i);
1355
1356 /* Can't match a stream instance without ID. */
1357 if (candidate_dest->stream_id == -1) {
1358 continue;
1359 }
1360
1361 /*
1362 * If the two groups have the same stream instance id
1363 * and belong to the same stream class (stream instance
1364 * ids are per-stream class), they represent the same
1365 * stream instance.
1366 */
1367 if (candidate_dest->stream_id != src_group->stream_id ||
1368 candidate_dest->sc->id != src_group->sc->id) {
1369 continue;
1370 }
1371
1372 dest_group = candidate_dest;
1373 break;
1374 }
1375 }
1376
1377 /*
1378 * Didn't find a friend in dest to merge our src_group into?
7ed5243a
FD
1379 * Create a new empty one. This can happen if a stream was
1380 * active in the source trace chunk but not in the destination
1381 * trace chunk.
41a65f30
SM
1382 */
1383 if (!dest_group) {
1384 struct ctf_stream_class *sc;
7ed5243a 1385 struct ctf_fs_ds_index *index;
41a65f30
SM
1386
1387 sc = ctf_trace_class_borrow_stream_class_by_id(
1388 dest_trace->metadata->tc, src_group->sc->id);
1389 BT_ASSERT(sc);
1390
4c65a157
PP
1391 index = ctf_fs_ds_index_create(dest_trace->log_level,
1392 dest_trace->self_comp);
7ed5243a
FD
1393 if (!index) {
1394 ret = -1;
1395 goto end;
1396 }
1397
41a65f30 1398 dest_group = ctf_fs_ds_file_group_create(dest_trace, sc,
7ed5243a
FD
1399 src_group->stream_id, index);
1400 /* Ownership of index is transferred. */
1401 index = NULL;
54ef52bd
FD
1402 if (!dest_group) {
1403 ret = -1;
1404 goto end;
1405 }
41a65f30
SM
1406
1407 g_ptr_array_add(dest_trace->ds_file_groups, dest_group);
1408 }
1409
1410 BT_ASSERT(dest_group);
1411 merge_ctf_fs_ds_file_groups(dest_group, src_group);
1412 }
54ef52bd
FD
1413
1414end:
1415 return ret;
41a65f30
SM
1416}
1417
1418/*
1419 * Collapse the given traces, which must all share the same UUID, in a single
1420 * one.
1421 *
1422 * The trace with the most expansive metadata is chosen and all other traces
1423 * are merged into that one. The array slots of all the traces that get merged
1424 * in the chosen one are set to NULL, so only the slot of the chosen trace
1425 * remains non-NULL.
1426 */
1427
1428static
a0cd55ad
SM
1429int merge_ctf_fs_traces(struct ctf_fs_trace **traces, unsigned int num_traces,
1430 struct ctf_fs_trace **out_trace)
41a65f30
SM
1431{
1432 unsigned int winner_count;
1433 struct ctf_fs_trace *winner;
a0cd55ad 1434 guint i, winner_i;
54ef52bd 1435 int ret = 0;
41a65f30
SM
1436
1437 BT_ASSERT(num_traces >= 2);
1438
1439 winner_count = metadata_count_stream_and_event_classes(traces[0]);
1440 winner = traces[0];
a0cd55ad 1441 winner_i = 0;
41a65f30
SM
1442
1443 /* Find the trace with the largest metadata. */
1444 for (i = 1; i < num_traces; i++) {
1445 struct ctf_fs_trace *candidate;
1446 unsigned int candidate_count;
1447
1448 candidate = traces[i];
1449
1450 /* A bit of sanity check. */
1451 BT_ASSERT(bt_uuid_compare(winner->metadata->tc->uuid, candidate->metadata->tc->uuid) == 0);
1452
1453 candidate_count = metadata_count_stream_and_event_classes(candidate);
1454
1455 if (candidate_count > winner_count) {
1456 winner_count = candidate_count;
1457 winner = candidate;
a0cd55ad 1458 winner_i = i;
41a65f30
SM
1459 }
1460 }
1461
1462 /* Merge all the other traces in the winning trace. */
1463 for (i = 0; i < num_traces; i++) {
1464 struct ctf_fs_trace *trace = traces[i];
1465
1466 /* Don't merge the winner into itself. */
1467 if (trace == winner) {
1468 continue;
1469 }
1470
1471 /* Merge trace's data stream file groups into winner's. */
54ef52bd
FD
1472 ret = merge_matching_ctf_fs_ds_file_groups(winner, trace);
1473 if (ret) {
1474 goto end;
1475 }
41a65f30
SM
1476 }
1477
a0cd55ad
SM
1478 /*
1479 * Move the winner out of the array, into `*out_trace`.
1480 */
1481 *out_trace = winner;
1482 traces[winner_i] = NULL;
54ef52bd
FD
1483
1484end:
1485 return ret;
41a65f30
SM
1486}
1487
1719bf64
FD
1488enum target_event {
1489 FIRST_EVENT,
1490 LAST_EVENT,
1491};
1492
1493static
1494int decode_clock_snapshot_after_event(struct ctf_fs_trace *ctf_fs_trace,
1495 struct ctf_clock_class *default_cc,
1496 struct ctf_fs_ds_index_entry *index_entry,
1497 enum target_event target_event, uint64_t *cs, int64_t *ts_ns)
1498{
18a1979b 1499 enum ctf_msg_iter_status iter_status = CTF_MSG_ITER_STATUS_OK;
1719bf64 1500 struct ctf_fs_ds_file *ds_file = NULL;
18a1979b 1501 struct ctf_msg_iter *msg_iter = NULL;
1719bf64
FD
1502 bt_logging_level log_level = ctf_fs_trace->log_level;
1503 bt_self_component *self_comp = ctf_fs_trace->self_comp;
1504 int ret = 0;
1505
1506 BT_ASSERT(ctf_fs_trace);
1507 BT_ASSERT(ctf_fs_trace->metadata);
1508 BT_ASSERT(ctf_fs_trace->metadata->tc);
1509
18a1979b 1510 msg_iter = ctf_msg_iter_create(ctf_fs_trace->metadata->tc,
1719bf64 1511 bt_common_get_page_size(log_level) * 8, ctf_fs_ds_file_medops,
851de941 1512 NULL, log_level, self_comp, NULL);
1719bf64 1513 if (!msg_iter) {
18a1979b 1514 /* ctf_msg_iter_create() logs errors. */
1719bf64
FD
1515 ret = -1;
1516 goto end;
1517 }
1518
1519 BT_ASSERT(index_entry);
1520 BT_ASSERT(index_entry->path);
1521
1522 ds_file = ctf_fs_ds_file_create(ctf_fs_trace, NULL, msg_iter,
1523 NULL, index_entry->path, log_level);
1524 if (!ds_file) {
d23b766e 1525 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create a ctf_fs_ds_file");
1719bf64
FD
1526 ret = -1;
1527 goto end;
1528 }
1529
1530 /*
1531 * Turn on dry run mode to prevent the creation and usage of Babeltrace
1532 * library objects (bt_field, bt_message_*, etc.).
1533 */
18a1979b 1534 ctf_msg_iter_set_dry_run(msg_iter, true);
1719bf64
FD
1535
1536 /* Seek to the beginning of the target packet. */
18a1979b 1537 iter_status = ctf_msg_iter_seek(ds_file->msg_iter, index_entry->offset);
1719bf64 1538 if (iter_status) {
18a1979b 1539 /* ctf_msg_iter_seek() logs errors. */
1719bf64
FD
1540 ret = -1;
1541 goto end;
1542 }
1543
1544 switch (target_event) {
1545 case FIRST_EVENT:
1546 /*
1547 * Start to decode the packet until we reach the end of
1548 * the first event. To extract the first event's clock
1549 * snapshot.
1550 */
18a1979b 1551 iter_status = ctf_msg_iter_curr_packet_first_event_clock_snapshot(
1719bf64
FD
1552 ds_file->msg_iter, cs);
1553 break;
1554 case LAST_EVENT:
1555 /* Decode the packet to extract the last event's clock snapshot. */
18a1979b 1556 iter_status = ctf_msg_iter_curr_packet_last_event_clock_snapshot(
1719bf64
FD
1557 ds_file->msg_iter, cs);
1558 break;
1559 default:
498e7994 1560 bt_common_abort();
1719bf64
FD
1561 }
1562 if (iter_status) {
1563 ret = -1;
1564 goto end;
1565 }
1566
1567 /* Convert clock snapshot to timestamp. */
1568 ret = bt_util_clock_cycles_to_ns_from_origin(*cs,
1569 default_cc->frequency, default_cc->offset_seconds,
1570 default_cc->offset_cycles, ts_ns);
1571 if (ret) {
d23b766e
SM
1572 BT_COMP_LOGE_APPEND_CAUSE(self_comp,
1573 "Failed to convert clock snapshot to timestamp");
1719bf64
FD
1574 goto end;
1575 }
1576
1577end:
1578 if (ds_file) {
1579 ctf_fs_ds_file_destroy(ds_file);
1580 }
1581 if (msg_iter) {
18a1979b 1582 ctf_msg_iter_destroy(msg_iter);
1719bf64
FD
1583 }
1584
1585 return ret;
1586}
1587
c43092a5
FD
1588static
1589int decode_packet_first_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
1590 struct ctf_clock_class *default_cc,
1591 struct ctf_fs_ds_index_entry *index_entry, uint64_t *cs, int64_t *ts_ns)
1592{
1593 return decode_clock_snapshot_after_event(ctf_fs_trace, default_cc,
1594 index_entry, FIRST_EVENT, cs, ts_ns);
1595}
1596
1719bf64
FD
1597static
1598int decode_packet_last_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
1599 struct ctf_clock_class *default_cc,
1600 struct ctf_fs_ds_index_entry *index_entry, uint64_t *cs, int64_t *ts_ns)
1601{
1602 return decode_clock_snapshot_after_event(ctf_fs_trace, default_cc,
1603 index_entry, LAST_EVENT, cs, ts_ns);
1604}
1605
1606/*
1607 * Fix up packet index entries for lttng's "event-after-packet" bug.
1608 * Some buggy lttng tracer versions may emit events with a timestamp that is
1609 * larger (after) than the timestamp_end of the their packets.
1610 *
1611 * To fix up this erroneous data we do the following:
1612 * 1. If it's not the stream file's last packet: set the packet index entry's
1613 * end time to the next packet's beginning time.
1614 * 2. If it's the stream file's last packet, set the packet index entry's end
1615 * time to the packet's last event's time, if any, or to the packet's
1616 * beginning time otherwise.
1617 *
1618 * Known buggy tracer versions:
1619 * - before lttng-ust 2.11.0
1620 * - before lttng-module 2.11.0
1621 * - before lttng-module 2.10.10
1622 * - before lttng-module 2.9.13
1623 */
1624static
1625int fix_index_lttng_event_after_packet_bug(struct ctf_fs_trace *trace)
1626{
1627 int ret = 0;
1628 guint ds_file_group_i;
1629 GPtrArray *ds_file_groups = trace->ds_file_groups;
1630 bt_logging_level log_level = trace->log_level;
1631
1632 for (ds_file_group_i = 0; ds_file_group_i < ds_file_groups->len;
1633 ds_file_group_i++) {
1634 guint entry_i;
1635 struct ctf_clock_class *default_cc;
1636 struct ctf_fs_ds_index_entry *last_entry;
1637 struct ctf_fs_ds_index *index;
1638
1639 struct ctf_fs_ds_file_group *ds_file_group =
1640 g_ptr_array_index(ds_file_groups, ds_file_group_i);
1641
1642 BT_ASSERT(ds_file_group);
1643 index = ds_file_group->index;
1644
1645 BT_ASSERT(index);
1646 BT_ASSERT(index->entries);
1647 BT_ASSERT(index->entries->len > 0);
1648
1649 /*
1650 * Iterate over all entries but the last one. The last one is
1651 * fixed differently after.
1652 */
1653 for (entry_i = 0; entry_i < index->entries->len - 1;
1654 entry_i++) {
1655 struct ctf_fs_ds_index_entry *curr_entry, *next_entry;
1656
1657 curr_entry = g_ptr_array_index(index->entries, entry_i);
1658 next_entry = g_ptr_array_index(index->entries, entry_i + 1);
1659
1660 /*
1661 * 1. Set the current index entry `end` timestamp to
1662 * the next index entry `begin` timestamp.
1663 */
1664 curr_entry->timestamp_end = next_entry->timestamp_begin;
1665 curr_entry->timestamp_end_ns = next_entry->timestamp_begin_ns;
1666 }
1667
1668 /*
1669 * 2. Fix the last entry by decoding the last event of the last
1670 * packet.
1671 */
1672 last_entry = g_ptr_array_index(index->entries,
1673 index->entries->len - 1);
1674 BT_ASSERT(last_entry);
1675
1676 BT_ASSERT(ds_file_group->sc->default_clock_class);
1677 default_cc = ds_file_group->sc->default_clock_class;
1678
1679 /*
1680 * Decode packet to read the timestamp of the last event of the
1681 * entry.
1682 */
1683 ret = decode_packet_last_event_timestamp(trace, default_cc,
1684 last_entry, &last_entry->timestamp_end,
1685 &last_entry->timestamp_end_ns);
1686 if (ret) {
d23b766e
SM
1687 BT_COMP_LOGE_APPEND_CAUSE(trace->self_comp,
1688 "Failed to decode stream's last packet to get its last event's clock snapshot.");
1719bf64
FD
1689 goto end;
1690 }
1691 }
1692
1693end:
1694 return ret;
1695}
1696
c43092a5
FD
1697/*
1698 * Fix up packet index entries for barectf's "event-before-packet" bug.
1699 * Some buggy barectf tracer versions may emit events with a timestamp that is
1700 * less than the timestamp_begin of the their packets.
1701 *
1702 * To fix up this erroneous data we do the following:
1703 * 1. Starting at the second index entry, set the timestamp_begin of the
1704 * current entry to the timestamp of the first event of the packet.
1705 * 2. Set the previous entry's timestamp_end to the timestamp_begin of the
1706 * current packet.
1707 *
1708 * Known buggy tracer versions:
1709 * - before barectf 2.3.1
1710 */
1711static
1712int fix_index_barectf_event_before_packet_bug(struct ctf_fs_trace *trace)
1713{
1714 int ret = 0;
1715 guint ds_file_group_i;
1716 GPtrArray *ds_file_groups = trace->ds_file_groups;
1717 bt_logging_level log_level = trace->log_level;
1718
1719 for (ds_file_group_i = 0; ds_file_group_i < ds_file_groups->len;
1720 ds_file_group_i++) {
1721 guint entry_i;
1722 struct ctf_clock_class *default_cc;
1723 struct ctf_fs_ds_file_group *ds_file_group =
1724 g_ptr_array_index(ds_file_groups, ds_file_group_i);
1725
1726 struct ctf_fs_ds_index *index = ds_file_group->index;
1727
1728 BT_ASSERT(index);
1729 BT_ASSERT(index->entries);
1730 BT_ASSERT(index->entries->len > 0);
1731
1732 BT_ASSERT(ds_file_group->sc->default_clock_class);
1733 default_cc = ds_file_group->sc->default_clock_class;
1734
1735 /*
1736 * 1. Iterate over the index, starting from the second entry
1737 * (index = 1).
1738 */
1739 for (entry_i = 1; entry_i < index->entries->len;
1740 entry_i++) {
1741 struct ctf_fs_ds_index_entry *curr_entry, *prev_entry;
1742 prev_entry = g_ptr_array_index(index->entries, entry_i - 1);
1743 curr_entry = g_ptr_array_index(index->entries, entry_i);
1744 /*
1745 * 2. Set the current entry `begin` timestamp to the
1746 * timestamp of the first event of the current packet.
1747 */
1748 ret = decode_packet_first_event_timestamp(trace, default_cc,
1749 curr_entry, &curr_entry->timestamp_begin,
1750 &curr_entry->timestamp_begin_ns);
1751 if (ret) {
d23b766e
SM
1752 BT_COMP_LOGE_APPEND_CAUSE(trace->self_comp,
1753 "Failed to decode first event's clock snapshot");
c43092a5
FD
1754 goto end;
1755 }
1756
1757 /*
1758 * 3. Set the previous entry `end` timestamp to the
1759 * timestamp of the first event of the current packet.
1760 */
1761 prev_entry->timestamp_end = curr_entry->timestamp_begin;
1762 prev_entry->timestamp_end_ns = curr_entry->timestamp_begin_ns;
1763 }
1764 }
1765end:
1766 return ret;
1767}
1768
aada78b5
FD
1769/*
1770 * When using the lttng-crash feature it's likely that the last packets of each
1771 * stream have their timestamp_end set to zero. This is caused by the fact that
1772 * the tracer crashed and was not able to properly close the packets.
1773 *
1774 * To fix up this erroneous data we do the following:
1775 * For each index entry, if the entry's timestamp_end is 0 and the
1776 * timestamp_begin is not 0:
1777 * - If it's the stream file's last packet: set the packet index entry's end
1778 * time to the packet's last event's time, if any, or to the packet's
1779 * beginning time otherwise.
1780 * - If it's not the stream file's last packet: set the packet index
1781 * entry's end time to the next packet's beginning time.
1782 *
1783 * Affected versions:
1784 * - All current and future lttng-ust and lttng-modules versions.
1785 */
1786static
1787int fix_index_lttng_crash_quirk(struct ctf_fs_trace *trace)
1788{
1789 int ret = 0;
1790 guint ds_file_group_idx;
1791 GPtrArray *ds_file_groups = trace->ds_file_groups;
1792 bt_logging_level log_level = trace->log_level;
1793
1794 for (ds_file_group_idx = 0; ds_file_group_idx < ds_file_groups->len;
1795 ds_file_group_idx++) {
1796 guint entry_idx;
1797 struct ctf_clock_class *default_cc;
1798 struct ctf_fs_ds_index_entry *last_entry;
1799 struct ctf_fs_ds_index *index;
1800
1801 struct ctf_fs_ds_file_group *ds_file_group =
1802 g_ptr_array_index(ds_file_groups, ds_file_group_idx);
1803
1804 BT_ASSERT(ds_file_group);
1805 index = ds_file_group->index;
1806
1807 BT_ASSERT(ds_file_group->sc->default_clock_class);
1808 default_cc = ds_file_group->sc->default_clock_class;
1809
1810 BT_ASSERT(index);
1811 BT_ASSERT(index->entries);
1812 BT_ASSERT(index->entries->len > 0);
1813
1814 last_entry = g_ptr_array_index(index->entries,
1815 index->entries->len - 1);
1816 BT_ASSERT(last_entry);
1817
1818
1819 /* 1. Fix the last entry first. */
1820 if (last_entry->timestamp_end == 0 &&
1821 last_entry->timestamp_begin != 0) {
1822 /*
1823 * Decode packet to read the timestamp of the
1824 * last event of the stream file.
1825 */
1826 ret = decode_packet_last_event_timestamp(trace,
1827 default_cc, last_entry,
1828 &last_entry->timestamp_end,
1829 &last_entry->timestamp_end_ns);
1830 if (ret) {
d23b766e
SM
1831 BT_COMP_LOGE_APPEND_CAUSE(trace->self_comp,
1832 "Failed to decode last event's clock snapshot");
aada78b5
FD
1833 goto end;
1834 }
1835 }
1836
1837 /* Iterate over all entries but the last one. */
1838 for (entry_idx = 0; entry_idx < index->entries->len - 1;
1839 entry_idx++) {
1840 struct ctf_fs_ds_index_entry *curr_entry, *next_entry;
1841 curr_entry = g_ptr_array_index(index->entries, entry_idx);
1842 next_entry = g_ptr_array_index(index->entries, entry_idx + 1);
1843
1844 if (curr_entry->timestamp_end == 0 &&
1845 curr_entry->timestamp_begin != 0) {
1846 /*
1847 * 2. Set the current index entry `end` timestamp to
1848 * the next index entry `begin` timestamp.
1849 */
1850 curr_entry->timestamp_end = next_entry->timestamp_begin;
1851 curr_entry->timestamp_end_ns = next_entry->timestamp_begin_ns;
1852 }
1853 }
1854 }
1855
1856end:
1857 return ret;
1858}
1859
626cc488
FD
1860/*
1861 * Extract the tracer information necessary to compare versions.
1862 * Returns 0 on success, and -1 if the extraction is not successful because the
1863 * necessary fields are absents in the trace metadata.
1864 */
1865static
626cc488
FD
1866int extract_tracer_info(struct ctf_fs_trace *trace,
1867 struct tracer_info *current_tracer_info)
1868{
1869 int ret = 0;
1870 struct ctf_trace_class_env_entry *entry;
1871
1872 /* Clear the current_tracer_info struct */
1873 memset(current_tracer_info, 0, sizeof(*current_tracer_info));
1874
1875 /*
1876 * To compare 2 tracer versions, at least the tracer name and it's
1877 * major version are needed. If one of these is missing, consider it an
1878 * extraction failure.
1879 */
1880 entry = ctf_trace_class_borrow_env_entry_by_name(
1881 trace->metadata->tc, "tracer_name");
1882 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR) {
1883 goto missing_bare_minimum;
1884 }
1885
1886 /* Set tracer name. */
1887 current_tracer_info->name = entry->value.str->str;
1888
1889 entry = ctf_trace_class_borrow_env_entry_by_name(
1890 trace->metadata->tc, "tracer_major");
1891 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
1892 goto missing_bare_minimum;
1893 }
1894
1895 /* Set major version number. */
1896 current_tracer_info->major = entry->value.i;
1897
1898 entry = ctf_trace_class_borrow_env_entry_by_name(
1899 trace->metadata->tc, "tracer_minor");
1900 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
1901 goto end;
1902 }
1903
1904 /* Set minor version number. */
1905 current_tracer_info->minor = entry->value.i;
1906
1907 entry = ctf_trace_class_borrow_env_entry_by_name(
1908 trace->metadata->tc, "tracer_patch");
1909 if (!entry) {
1910 /*
1911 * If `tracer_patch` doesn't exist `tracer_patchlevel` might.
1912 * For example, `lttng-modules` uses entry name
1913 * `tracer_patchlevel`.
1914 */
1915 entry = ctf_trace_class_borrow_env_entry_by_name(
1916 trace->metadata->tc, "tracer_patchlevel");
1917 }
1918
1919 if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
1920 goto end;
1921 }
1922
1923 /* Set patch version number. */
1924 current_tracer_info->patch = entry->value.i;
1925
1926 goto end;
1927
1928missing_bare_minimum:
1929 ret = -1;
1930end:
1931 return ret;
1932}
1933
1719bf64
FD
1934static
1935bool is_tracer_affected_by_lttng_event_after_packet_bug(
1936 struct tracer_info *curr_tracer_info)
1937{
1938 bool is_affected = false;
1939
1940 if (strcmp(curr_tracer_info->name, "lttng-ust") == 0) {
1941 if (curr_tracer_info->major < 2) {
1942 is_affected = true;
1943 } else if (curr_tracer_info->major == 2) {
1944 /* fixed in lttng-ust 2.11.0 */
1945 if (curr_tracer_info->minor < 11) {
1946 is_affected = true;
1947 }
1948 }
1949 } else if (strcmp(curr_tracer_info->name, "lttng-modules") == 0) {
1950 if (curr_tracer_info->major < 2) {
1951 is_affected = true;
1952 } else if (curr_tracer_info->major == 2) {
1953 /* fixed in lttng-modules 2.11.0 */
1954 if (curr_tracer_info->minor == 10) {
1955 /* fixed in lttng-modules 2.10.10 */
1956 if (curr_tracer_info->patch < 10) {
1957 is_affected = true;
1958 }
1959 } else if (curr_tracer_info->minor == 9) {
1960 /* fixed in lttng-modules 2.9.13 */
1961 if (curr_tracer_info->patch < 13) {
1962 is_affected = true;
1963 }
1964 } else if (curr_tracer_info->minor < 9) {
1965 is_affected = true;
1966 }
1967 }
1968 }
1969
1970 return is_affected;
1971}
1972
c43092a5
FD
1973static
1974bool is_tracer_affected_by_barectf_event_before_packet_bug(
1975 struct tracer_info *curr_tracer_info)
1976{
1977 bool is_affected = false;
1978
1979 if (strcmp(curr_tracer_info->name, "barectf") == 0) {
1980 if (curr_tracer_info->major < 2) {
1981 is_affected = true;
1982 } else if (curr_tracer_info->major == 2) {
1983 if (curr_tracer_info->minor < 3) {
1984 is_affected = true;
1985 } else if (curr_tracer_info->minor == 3) {
1986 /* fixed in barectf 2.3.1 */
1987 if (curr_tracer_info->patch < 1) {
1988 is_affected = true;
1989 }
1990 }
1991 }
1992 }
1993
1994 return is_affected;
1995}
1996
aada78b5
FD
1997static
1998bool is_tracer_affected_by_lttng_crash_quirk(
1999 struct tracer_info *curr_tracer_info)
2000{
2001 bool is_affected = false;
2002
2003 /* All LTTng tracer may be affected by this lttng crash quirk. */
2004 if (strcmp(curr_tracer_info->name, "lttng-ust") == 0) {
2005 is_affected = true;
2006 } else if (strcmp(curr_tracer_info->name, "lttng-modules") == 0) {
2007 is_affected = true;
2008 }
2009
2010 return is_affected;
2011}
2012
1719bf64
FD
2013/*
2014 * Looks for trace produced by known buggy tracers and fix up the index
2015 * produced earlier.
2016 */
2017static
d23b766e 2018int fix_packet_index_tracer_bugs(struct ctf_fs_component *ctf_fs,
b7d2695a
SM
2019 bt_self_component *self_comp,
2020 bt_self_component_class *self_comp_class)
1719bf64
FD
2021{
2022 int ret = 0;
1719bf64 2023 struct tracer_info current_tracer_info;
1719bf64
FD
2024 bt_logging_level log_level = ctf_fs->log_level;
2025
a0cd55ad
SM
2026 ret = extract_tracer_info(ctf_fs->trace, &current_tracer_info);
2027 if (ret) {
2028 /*
2029 * A trace may not have all the necessary environment
2030 * entries to do the tracer version comparison.
2031 * At least, the tracer name and major version number
2032 * are needed. Failing to extract these entries is not
2033 * an error.
2034 */
2035 ret = 0;
2036 BT_LOGI_STR("Cannot extract tracer information necessary to compare with buggy versions.");
2037 goto end;;
2038 }
1719bf64 2039
a0cd55ad
SM
2040 /* Check if the trace may be affected by old tracer bugs. */
2041 if (is_tracer_affected_by_lttng_event_after_packet_bug(
2042 &current_tracer_info)) {
2043 BT_LOGI_STR("Trace may be affected by LTTng tracer packet timestamp bug. Fixing up.");
2044 ret = fix_index_lttng_event_after_packet_bug(ctf_fs->trace);
1719bf64 2045 if (ret) {
b7d2695a
SM
2046 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
2047 self_comp, self_comp_class,
a0cd55ad
SM
2048 "Failed to fix LTTng event-after-packet bug.");
2049 goto end;
1719bf64 2050 }
a0cd55ad
SM
2051 ctf_fs->trace->metadata->tc->quirks.lttng_event_after_packet = true;
2052 }
c43092a5 2053
a0cd55ad
SM
2054 if (is_tracer_affected_by_barectf_event_before_packet_bug(
2055 &current_tracer_info)) {
2056 BT_LOGI_STR("Trace may be affected by barectf tracer packet timestamp bug. Fixing up.");
2057 ret = fix_index_barectf_event_before_packet_bug(ctf_fs->trace);
2058 if (ret) {
b7d2695a
SM
2059 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
2060 self_comp, self_comp_class,
a0cd55ad
SM
2061 "Failed to fix barectf event-before-packet bug.");
2062 goto end;
c43092a5 2063 }
a0cd55ad
SM
2064 ctf_fs->trace->metadata->tc->quirks.barectf_event_before_packet = true;
2065 }
aada78b5 2066
a0cd55ad
SM
2067 if (is_tracer_affected_by_lttng_crash_quirk(
2068 &current_tracer_info)) {
2069 ret = fix_index_lttng_crash_quirk(ctf_fs->trace);
2070 if (ret) {
b7d2695a
SM
2071 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
2072 self_comp, self_comp_class,
a0cd55ad
SM
2073 "Failed to fix lttng-crash timestamp quirks.");
2074 goto end;
aada78b5 2075 }
a0cd55ad 2076 ctf_fs->trace->metadata->tc->quirks.lttng_crash = true;
1719bf64 2077 }
a0cd55ad 2078
1719bf64
FD
2079end:
2080 return ret;
2081}
2082
e9b3611f
PP
2083static
2084gint compare_ds_file_groups_by_first_path(gconstpointer a, gconstpointer b)
2085{
2086 struct ctf_fs_ds_file_group * const *ds_file_group_a = a;
2087 struct ctf_fs_ds_file_group * const *ds_file_group_b = b;
2088 const struct ctf_fs_ds_file_info *first_ds_file_info_a;
2089 const struct ctf_fs_ds_file_info *first_ds_file_info_b;
2090
2091 BT_ASSERT((*ds_file_group_a)->ds_file_infos->len > 0);
2092 BT_ASSERT((*ds_file_group_b)->ds_file_infos->len > 0);
2093 first_ds_file_info_a = (*ds_file_group_a)->ds_file_infos->pdata[0];
2094 first_ds_file_info_b = (*ds_file_group_b)->ds_file_infos->pdata[0];
2095 return strcmp(first_ds_file_info_a->path->str,
2096 first_ds_file_info_b->path->str);
2097}
2098
a0cd55ad 2099int ctf_fs_component_create_ctf_fs_trace(
f280892e 2100 struct ctf_fs_component *ctf_fs,
d23b766e 2101 const bt_value *paths_value,
005d49d6 2102 const bt_value *trace_name_value,
d23b766e
SM
2103 bt_self_component *self_comp,
2104 bt_self_component_class *self_comp_class)
f280892e
SM
2105{
2106 int ret = 0;
2107 uint64_t i;
1719bf64 2108 bt_logging_level log_level = ctf_fs->log_level;
a0cd55ad 2109 GPtrArray *traces;
005d49d6 2110 const char *trace_name;
f280892e 2111
a0cd55ad
SM
2112 BT_ASSERT(bt_value_get_type(paths_value) == BT_VALUE_TYPE_ARRAY);
2113 BT_ASSERT(!bt_value_array_is_empty(paths_value));
2114
2115 traces = g_ptr_array_new_with_free_func(ctf_fs_trace_destroy_notifier);
2116 if (!traces) {
2117 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
2118 "Failed to allocate a GPtrArray.");
2119 goto error;
2120 }
2121
005d49d6
SM
2122 trace_name = trace_name_value ? bt_value_string_get(trace_name_value) : NULL;
2123
a0cd55ad 2124 /* Start by creating a separate ctf_fs_trace object for each path. */
393729a6 2125 for (i = 0; i < bt_value_array_get_length(paths_value); i++) {
f280892e 2126 const bt_value *path_value = bt_value_array_borrow_element_by_index_const(paths_value, i);
73760435 2127 const char *input = bt_value_string_get(path_value);
f280892e 2128
a0cd55ad 2129 ret = ctf_fs_component_create_ctf_fs_trace_one_path(ctf_fs,
005d49d6 2130 input, trace_name, traces, self_comp, self_comp_class);
f280892e
SM
2131 if (ret) {
2132 goto end;
2133 }
2134 }
2135
a0cd55ad
SM
2136 if (traces->len > 1) {
2137 struct ctf_fs_trace *first_trace = (struct ctf_fs_trace *) traces->pdata[0];
2138 const uint8_t *first_trace_uuid = first_trace->metadata->tc->uuid;
2139 struct ctf_fs_trace *trace;
2140
2141 /*
2142 * We have more than one trace, they must all share the same
2143 * UUID, verify that.
2144 */
2145 for (i = 0; i < traces->len; i++) {
2146 struct ctf_fs_trace *this_trace =
2147 (struct ctf_fs_trace *) traces->pdata[i];
2148 const uint8_t *this_trace_uuid = this_trace->metadata->tc->uuid;
2149
2150 if (!this_trace->metadata->tc->is_uuid_set) {
2151 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
2152 "Multiple traces given, but a trace does not have a UUID: path=%s",
2153 this_trace->path->str);
2154 goto error;
2155 }
2156
2157 if (bt_uuid_compare(first_trace_uuid, this_trace_uuid) != 0) {
2158 char first_trace_uuid_str[BT_UUID_STR_LEN + 1];
2159 char this_trace_uuid_str[BT_UUID_STR_LEN + 1];
2160
2161 bt_uuid_to_str(first_trace_uuid, first_trace_uuid_str);
2162 bt_uuid_to_str(this_trace_uuid, this_trace_uuid_str);
2163
2164 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
2165 "Multiple traces given, but UUIDs don't match: "
2166 "first-trace-uuid=%s, first-trace-path=%s, "
2167 "trace-uuid=%s, trace-path=%s",
2168 first_trace_uuid_str, first_trace->path->str,
2169 this_trace_uuid_str, this_trace->path->str);
2170 goto error;
2171 }
2172 }
2173
2174 ret = merge_ctf_fs_traces((struct ctf_fs_trace **) traces->pdata,
2175 traces->len, &trace);
2176 if (ret) {
2177 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
2178 "Failed to merge traces with the same UUID.");
2179 goto error;
2180 }
2181
2182 ctf_fs->trace = trace;
2183 } else {
2184 /* Just one trace, it may or may not have a UUID, both are fine. */
2185 ctf_fs->trace = traces->pdata[0];
2186 traces->pdata[0] = NULL;
1719bf64 2187 }
41a65f30 2188
b7d2695a 2189 ret = fix_packet_index_tracer_bugs(ctf_fs, self_comp, self_comp_class);
1719bf64 2190 if (ret) {
d23b766e
SM
2191 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
2192 "Failed to fix packet index tracer bugs.");
1719bf64 2193 }
a0cd55ad 2194
e9b3611f
PP
2195 /*
2196 * Sort data stream file groups by first data stream file info
2197 * path to get a deterministic order. This order influences the
2198 * order of the output ports. It also influences the order of
2199 * the automatic stream IDs if the trace's packet headers do not
2200 * contain a `stream_instance_id` field, in which case the data
2201 * stream file to stream ID association is always the same,
2202 * whatever the build and the system.
2203 *
2204 * Having a deterministic order here can help debugging and
2205 * testing.
2206 */
2207 g_ptr_array_sort(ctf_fs->trace->ds_file_groups,
2208 compare_ds_file_groups_by_first_path);
a0cd55ad
SM
2209 goto end;
2210error:
2211 ret = -1;
2212
f280892e 2213end:
a0cd55ad 2214 g_ptr_array_free(traces, TRUE);
f280892e
SM
2215 return ret;
2216}
2217
a38d7650
SM
2218static
2219GString *get_stream_instance_unique_name(
2220 struct ctf_fs_ds_file_group *ds_file_group)
2221{
2222 GString *name;
2223 struct ctf_fs_ds_file_info *ds_file_info;
2224
2225 name = g_string_new(NULL);
2226 if (!name) {
2227 goto end;
2228 }
2229
2230 /*
2231 * If there's more than one stream file in the stream file
2232 * group, the first (earliest) stream file's path is used as
2233 * the stream's unique name.
2234 */
2235 BT_ASSERT(ds_file_group->ds_file_infos->len > 0);
2236 ds_file_info = g_ptr_array_index(ds_file_group->ds_file_infos, 0);
2237 g_string_assign(name, ds_file_info->path->str);
2238
2239end:
2240 return name;
2241}
2242
f280892e
SM
2243/* Create the IR stream objects for ctf_fs_trace. */
2244
2245static
2246int create_streams_for_trace(struct ctf_fs_trace *ctf_fs_trace)
2247{
2248 int ret;
2249 GString *name = NULL;
2250 guint i;
98903a3e 2251 bt_logging_level log_level = ctf_fs_trace->log_level;
4c65a157 2252 bt_self_component *self_comp = ctf_fs_trace->self_comp;
f280892e
SM
2253
2254 for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
2255 struct ctf_fs_ds_file_group *ds_file_group =
2256 g_ptr_array_index(ctf_fs_trace->ds_file_groups, i);
2257 name = get_stream_instance_unique_name(ds_file_group);
2258
2259 if (!name) {
2260 goto error;
2261 }
2262
2263 if (ds_file_group->sc->ir_sc) {
2264 BT_ASSERT(ctf_fs_trace->trace);
2265
2266 if (ds_file_group->stream_id == UINT64_C(-1)) {
2267 /* No stream ID: use 0 */
2268 ds_file_group->stream = bt_stream_create_with_id(
2269 ds_file_group->sc->ir_sc,
2270 ctf_fs_trace->trace,
2271 ctf_fs_trace->next_stream_id);
2272 ctf_fs_trace->next_stream_id++;
2273 } else {
2274 /* Specific stream ID */
2275 ds_file_group->stream = bt_stream_create_with_id(
2276 ds_file_group->sc->ir_sc,
2277 ctf_fs_trace->trace,
2278 (uint64_t) ds_file_group->stream_id);
2279 }
2280 } else {
2281 ds_file_group->stream = NULL;
2282 }
2283
2284 if (!ds_file_group->stream) {
d23b766e
SM
2285 BT_COMP_LOGE_APPEND_CAUSE(self_comp,
2286 "Cannot create stream for DS file group: "
f280892e
SM
2287 "addr=%p, stream-name=\"%s\"",
2288 ds_file_group, name->str);
2289 goto error;
2290 }
2291
2292 ret = bt_stream_set_name(ds_file_group->stream,
2293 name->str);
2294 if (ret) {
d23b766e 2295 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot set stream's name: "
f280892e
SM
2296 "addr=%p, stream-name=\"%s\"",
2297 ds_file_group->stream, name->str);
2298 goto error;
2299 }
2300
2301 g_string_free(name, TRUE);
2302 name = NULL;
2303 }
2304
2305 ret = 0;
2306 goto end;
2307
2308error:
2309 ret = -1;
2310
2311end:
2312
2313 if (name) {
2314 g_string_free(name, TRUE);
2315 }
2316 return ret;
2317}
2318
c24f7ab4
SM
2319static const struct bt_param_validation_value_descr inputs_elem_descr = {
2320 .type = BT_VALUE_TYPE_STRING,
2321};
f280892e 2322
c24f7ab4
SM
2323static const struct bt_param_validation_map_value_entry_descr fs_params_entries_descr[] = {
2324 { "inputs", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY, {
2325 BT_VALUE_TYPE_ARRAY,
2326 .array = {
2327 .min_length = 1,
2328 .max_length = BT_PARAM_VALIDATION_INFINITE,
2329 .element_type = &inputs_elem_descr,
f280892e 2330 }
c24f7ab4
SM
2331 }},
2332 { "trace-name", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_STRING } },
2333 { "clock-class-offset-s", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_SIGNED_INTEGER } },
2334 { "clock-class-offset-ns", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_SIGNED_INTEGER } },
2335 { "force-clock-class-origin-unix-epoch", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
2336 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
2337};
f280892e 2338
f280892e 2339
d907165c 2340bool read_src_fs_parameters(const bt_value *params,
005d49d6
SM
2341 const bt_value **inputs,
2342 const bt_value **trace_name,
2343 struct ctf_fs_component *ctf_fs,
d23b766e
SM
2344 bt_self_component *self_comp,
2345 bt_self_component_class *self_comp_class) {
d907165c
SM
2346 bool ret;
2347 const bt_value *value;
98903a3e 2348 bt_logging_level log_level = ctf_fs->log_level;
c24f7ab4
SM
2349 enum bt_param_validation_status validate_value_status;
2350 gchar *error = NULL;
2351
2352 validate_value_status = bt_param_validation_validate(params,
2353 fs_params_entries_descr, &error);
2354 if (validate_value_status != BT_PARAM_VALIDATION_STATUS_OK) {
2355 BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
2356 "%s", error);
2357 ret = false;
2358 goto end;
2359 }
d907165c 2360
73760435
SM
2361 /* inputs parameter */
2362 *inputs = bt_value_map_borrow_entry_value_const(params, "inputs");
d907165c
SM
2363
2364 /* clock-class-offset-s parameter */
2365 value = bt_value_map_borrow_entry_value_const(params,
2366 "clock-class-offset-s");
2367 if (value) {
d907165c 2368 ctf_fs->metadata_config.clock_class_offset_s =
9c08c816 2369 bt_value_integer_signed_get(value);
d907165c
SM
2370 }
2371
2372 /* clock-class-offset-ns parameter */
2373 value = bt_value_map_borrow_entry_value_const(params,
2374 "clock-class-offset-ns");
2375 if (value) {
d907165c 2376 ctf_fs->metadata_config.clock_class_offset_ns =
9c08c816 2377 bt_value_integer_signed_get(value);
d907165c
SM
2378 }
2379
c0aa240b
FD
2380 /* force-clock-class-origin-unix-epoch parameter */
2381 value = bt_value_map_borrow_entry_value_const(params,
2382 "force-clock-class-origin-unix-epoch");
2383 if (value) {
c0aa240b
FD
2384 ctf_fs->metadata_config.force_clock_class_origin_unix_epoch =
2385 bt_value_bool_get(value);
2386 }
2387
005d49d6
SM
2388 /* trace-name parameter */
2389 *trace_name = bt_value_map_borrow_entry_value_const(params, "trace-name");
d907165c
SM
2390
2391 ret = true;
d907165c
SM
2392
2393end:
c24f7ab4 2394 g_free(error);
d907165c
SM
2395 return ret;
2396}
2397
5b29e799 2398static
d94d92ac 2399struct ctf_fs_component *ctf_fs_create(
d23b766e 2400 const bt_value *params,
b7d2695a 2401 bt_self_component_source *self_comp_src)
56a1cced 2402{
f280892e 2403 struct ctf_fs_component *ctf_fs = NULL;
73760435 2404 const bt_value *inputs_value;
005d49d6 2405 const bt_value *trace_name_value;
98903a3e
PP
2406 bt_self_component *self_comp =
2407 bt_self_component_source_as_self_component(self_comp_src);
56a1cced 2408
98903a3e 2409 ctf_fs = ctf_fs_component_create(bt_component_get_logging_level(
4c65a157 2410 bt_self_component_as_component(self_comp)), self_comp);
d907165c 2411 if (!ctf_fs) {
f280892e
SM
2412 goto error;
2413 }
2414
005d49d6 2415 if (!read_src_fs_parameters(params, &inputs_value, &trace_name_value,
b7d2695a 2416 ctf_fs, self_comp, NULL)) {
f280892e 2417 goto error;
56a1cced
JG
2418 }
2419
98903a3e 2420 bt_self_component_set_data(self_comp, ctf_fs);
56a1cced 2421
a0cd55ad 2422 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs, inputs_value,
b7d2695a 2423 trace_name_value, self_comp, NULL)) {
4f1f88a6
PP
2424 goto error;
2425 }
2426
a0cd55ad
SM
2427 if (create_streams_for_trace(ctf_fs->trace)) {
2428 goto error;
2429 }
f280892e 2430
a0cd55ad
SM
2431 if (create_ports_for_trace(ctf_fs, ctf_fs->trace, self_comp_src)) {
2432 goto error;
4f1f88a6
PP
2433 }
2434
1ef09eb5
JG
2435 goto end;
2436
56a1cced 2437error:
1a9f7075 2438 ctf_fs_destroy(ctf_fs);
e7a4393b 2439 ctf_fs = NULL;
98903a3e 2440 bt_self_component_set_data(self_comp, NULL);
1a9f7075 2441
1ef09eb5 2442end:
56a1cced
JG
2443 return ctf_fs;
2444}
2445
ea0b4b9e 2446BT_HIDDEN
21a9f056 2447bt_component_class_initialize_method_status ctf_fs_init(
d23b766e 2448 bt_self_component_source *self_comp_src,
59225a3e 2449 bt_self_component_source_configuration *config,
c88dd1cb 2450 const bt_value *params, __attribute__((unused)) void *init_method_data)
ea0b4b9e
JG
2451{
2452 struct ctf_fs_component *ctf_fs;
21a9f056
FD
2453 bt_component_class_initialize_method_status ret =
2454 BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
ea0b4b9e 2455
b7d2695a 2456 ctf_fs = ctf_fs_create(params, self_comp_src);
ea0b4b9e 2457 if (!ctf_fs) {
21a9f056 2458 ret = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
ea0b4b9e 2459 }
4c1456f0 2460
ea0b4b9e
JG
2461 return ret;
2462}
33f93973
PP
2463
2464BT_HIDDEN
d24d5663 2465bt_component_class_query_method_status ctf_fs_query(
b19ff26f 2466 bt_self_component_class_source *comp_class,
3c729b9a 2467 bt_private_query_executor *priv_query_exec,
b19ff26f 2468 const char *object, const bt_value *params,
7c14d641 2469 __attribute__((unused)) void *method_data,
b19ff26f 2470 const bt_value **result)
33f93973 2471{
d24d5663
PP
2472 bt_component_class_query_method_status status =
2473 BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
3c729b9a
PP
2474 bt_logging_level log_level = bt_query_executor_get_logging_level(
2475 bt_private_query_executor_as_query_executor_const(
2476 priv_query_exec));
33f93973 2477
2242b43d 2478 if (strcmp(object, "metadata-info") == 0) {
98903a3e
PP
2479 status = metadata_info_query(comp_class, params, log_level,
2480 result);
5f2a1585
SM
2481 } else if (strcmp(object, "babeltrace.trace-infos") == 0) {
2482 status = trace_infos_query(comp_class, params, log_level,
98903a3e 2483 result);
1a29b831 2484 } else if (!strcmp(object, "babeltrace.support-info")) {
73760435 2485 status = support_info_query(comp_class, params, log_level, result);
33f93973 2486 } else {
55314f2a 2487 BT_LOGE("Unknown query object `%s`", object);
76b6c2f7 2488 status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_UNKNOWN_OBJECT;
04c0ba87 2489 goto end;
33f93973 2490 }
33f93973 2491end:
d94d92ac 2492 return status;
33f93973 2493}
This page took 0.204656 seconds and 4 git commands to generate.