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