sink.ctf.fs: use bt2c::Logger
[babeltrace.git] / src / plugins / ctf / fs-sink / fs-sink.cpp
CommitLineData
15fe47e0 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
15fe47e0 3 *
0235b0db 4 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
15fe47e0
PP
5 */
6
c802cacb 7#include <glib.h>
c802cacb
SM
8#include <stdio.h>
9
10#include <babeltrace2/babeltrace.h>
11
578e048b 12#include "common/assert.h"
3c20ac12 13#include "cpp-common/vendor/fmt/format.h"
578e048b 14#include "ctfser/ctfser.h"
c802cacb 15
ce67f561 16#include "plugins/common/param-validation/param-validation.h"
15fe47e0 17
087cd0f5 18#include "fs-sink-ctf-meta.hpp"
c802cacb
SM
19#include "fs-sink-stream.hpp"
20#include "fs-sink-trace.hpp"
21#include "fs-sink.hpp"
c802cacb 22#include "translate-trace-ir-to-ctf-ir.hpp"
15fe47e0 23
4164020e 24static const char * const in_port_name = "in";
15fe47e0 25
4164020e
SM
26static bt_component_class_initialize_method_status
27ensure_output_dir_exists(struct fs_sink_comp *fs_sink)
15fe47e0 28{
4164020e
SM
29 bt_component_class_initialize_method_status status =
30 BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
31 int ret;
32
33 ret = g_mkdir_with_parents(fs_sink->output_dir_path->str, 0755);
34 if (ret) {
3c20ac12
SM
35 BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(
36 fs_sink->logger, "Cannot create directories for output directory",
37 ": output-dir-path=\"{}\"", fs_sink->output_dir_path->str);
4164020e
SM
38 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
39 goto end;
40 }
15fe47e0
PP
41
42end:
4164020e 43 return status;
15fe47e0
PP
44}
45
087cd0f5 46static bt_param_validation_map_value_entry_descr fs_sink_params_descr[] = {
88730e42
SM
47 {"path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
48 bt_param_validation_value_descr::makeString()},
49 {"assume-single-trace", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
50 bt_param_validation_value_descr::makeBool()},
51 {"ignore-discarded-events", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
52 bt_param_validation_value_descr::makeBool()},
53 {"ignore-discarded-packets", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
54 bt_param_validation_value_descr::makeBool()},
55 {"quiet", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL,
56 bt_param_validation_value_descr::makeBool()},
4164020e
SM
57 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
58
59static bt_component_class_initialize_method_status configure_component(struct fs_sink_comp *fs_sink,
60 const bt_value *params)
15fe47e0 61{
4164020e
SM
62 bt_component_class_initialize_method_status status;
63 const bt_value *value;
64 enum bt_param_validation_status validation_status;
65 gchar *validation_error;
66
67 validation_status =
68 bt_param_validation_validate(params, fs_sink_params_descr, &validation_error);
69 if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
70 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
3c20ac12 71 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "{}", validation_error);
4164020e
SM
72 goto end;
73 } else if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
74 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
75 goto end;
76 }
77
78 value = bt_value_map_borrow_entry_value_const(params, "path");
79 g_string_assign(fs_sink->output_dir_path, bt_value_string_get(value));
80
81 value = bt_value_map_borrow_entry_value_const(params, "assume-single-trace");
82 if (value) {
83 fs_sink->assume_single_trace = (bool) bt_value_bool_get(value);
84 }
85
86 value = bt_value_map_borrow_entry_value_const(params, "ignore-discarded-events");
87 if (value) {
88 fs_sink->ignore_discarded_events = (bool) bt_value_bool_get(value);
89 }
90
91 value = bt_value_map_borrow_entry_value_const(params, "ignore-discarded-packets");
92 if (value) {
93 fs_sink->ignore_discarded_packets = (bool) bt_value_bool_get(value);
94 }
95
96 value = bt_value_map_borrow_entry_value_const(params, "quiet");
97 if (value) {
98 fs_sink->quiet = (bool) bt_value_bool_get(value);
99 }
100
101 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
ce67f561 102
15fe47e0 103end:
4164020e
SM
104 g_free(validation_error);
105 return status;
15fe47e0
PP
106}
107
4164020e 108static void destroy_fs_sink_comp(struct fs_sink_comp *fs_sink)
15fe47e0 109{
4164020e
SM
110 if (!fs_sink) {
111 goto end;
112 }
15fe47e0 113
4164020e
SM
114 if (fs_sink->output_dir_path) {
115 g_string_free(fs_sink->output_dir_path, TRUE);
116 fs_sink->output_dir_path = NULL;
117 }
15fe47e0 118
4164020e
SM
119 if (fs_sink->traces) {
120 g_hash_table_destroy(fs_sink->traces);
121 fs_sink->traces = NULL;
122 }
15fe47e0 123
4164020e 124 BT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(fs_sink->upstream_iter);
150640e8 125 delete fs_sink;
15fe47e0
PP
126
127end:
4164020e 128 return;
15fe47e0
PP
129}
130
5bcd9f04
SM
131bt_component_class_initialize_method_status ctf_fs_sink_init(bt_self_component_sink *self_comp_sink,
132 bt_self_component_sink_configuration *,
133 const bt_value *params, void *)
15fe47e0 134{
4164020e
SM
135 bt_component_class_initialize_method_status status;
136 bt_self_component_add_port_status add_port_status;
137 struct fs_sink_comp *fs_sink = NULL;
138 bt_self_component *self_comp = bt_self_component_sink_as_self_component(self_comp_sink);
4164020e 139
3c20ac12 140 fs_sink = new fs_sink_comp {bt2::SelfSinkComponent {self_comp_sink}};
4164020e
SM
141 fs_sink->output_dir_path = g_string_new(NULL);
142 status = configure_component(fs_sink, params);
143 if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
144 /* configure_component() logs errors */
145 goto end;
146 }
147
148 if (fs_sink->assume_single_trace &&
149 g_file_test(fs_sink->output_dir_path->str, G_FILE_TEST_EXISTS)) {
3c20ac12
SM
150 BT_CPPLOGE_APPEND_CAUSE_SPEC(
151 fs_sink->logger, "Single trace mode, but output path exists: output-path=\"{}\"",
152 fs_sink->output_dir_path->str);
4164020e
SM
153 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
154 goto end;
155 }
156
157 status = ensure_output_dir_exists(fs_sink);
158 if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
159 /* ensure_output_dir_exists() logs errors */
160 goto end;
161 }
162
163 fs_sink->traces = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
164 (GDestroyNotify) fs_sink_trace_destroy);
165 if (!fs_sink->traces) {
3c20ac12 166 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to allocate one GHashTable.");
4164020e
SM
167 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
168 goto end;
169 }
170
171 add_port_status =
172 bt_self_component_sink_add_input_port(self_comp_sink, in_port_name, NULL, NULL);
173 if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
174 status = (bt_component_class_initialize_method_status) add_port_status;
3c20ac12 175 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to add input port.");
4164020e
SM
176 goto end;
177 }
178
179 bt_self_component_set_data(self_comp, fs_sink);
15fe47e0
PP
180
181end:
4164020e
SM
182 if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
183 destroy_fs_sink_comp(fs_sink);
184 }
15fe47e0 185
4164020e 186 return status;
15fe47e0
PP
187}
188
4164020e
SM
189static inline struct fs_sink_stream *borrow_stream(struct fs_sink_comp *fs_sink,
190 const bt_stream *ir_stream)
15fe47e0 191{
4164020e
SM
192 const bt_trace *ir_trace = bt_stream_borrow_trace_const(ir_stream);
193 struct fs_sink_trace *trace;
194 struct fs_sink_stream *stream = NULL;
195
196 trace = (fs_sink_trace *) g_hash_table_lookup(fs_sink->traces, ir_trace);
197 if (G_UNLIKELY(!trace)) {
198 if (fs_sink->assume_single_trace && g_hash_table_size(fs_sink->traces) > 0) {
3c20ac12
SM
199 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
200 "Single trace mode, but getting more than one trace: "
201 "stream-name=\"{}\"",
202 bt2c::maybeNull(bt_stream_get_name(ir_stream)));
4164020e
SM
203 goto end;
204 }
205
206 trace = fs_sink_trace_create(fs_sink, ir_trace);
207 if (!trace) {
208 goto end;
209 }
210 }
211
212 stream = (fs_sink_stream *) g_hash_table_lookup(trace->streams, ir_stream);
213 if (G_UNLIKELY(!stream)) {
214 stream = fs_sink_stream_create(trace, ir_stream);
215 if (!stream) {
216 goto end;
217 }
218 }
15fe47e0
PP
219
220end:
4164020e 221 return stream;
15fe47e0
PP
222}
223
4164020e
SM
224static inline bt_component_class_sink_consume_method_status
225handle_event_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
15fe47e0 226{
4164020e
SM
227 int ret;
228 bt_component_class_sink_consume_method_status status =
229 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
230 const bt_event *ir_event = bt_message_event_borrow_event_const(msg);
231 const bt_stream *ir_stream = bt_event_borrow_stream_const(ir_event);
232 struct fs_sink_stream *stream;
233 struct fs_sink_ctf_event_class *ec = NULL;
234 const bt_clock_snapshot *cs = NULL;
235
236 stream = borrow_stream(fs_sink, ir_stream);
237 if (G_UNLIKELY(!stream)) {
3c20ac12 238 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
4164020e
SM
239 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
240 goto end;
241 }
242
243 ret = try_translate_event_class_trace_ir_to_ctf_ir(fs_sink, stream->sc,
244 bt_event_borrow_class_const(ir_event), &ec);
245 if (ret) {
3c20ac12 246 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to translate event class to CTF IR.");
4164020e
SM
247 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
248 goto end;
249 }
250
251 BT_ASSERT_DBG(ec);
252
253 if (stream->sc->default_clock_class) {
254 cs = bt_message_event_borrow_default_clock_snapshot_const(msg);
255 }
256
257 /*
258 * If this event's stream does not support packets, then we
259 * lazily create artificial packets.
260 *
261 * The size of an artificial packet is arbitrarily at least
262 * 4 MiB (it usually is greater because we close it when
263 * comes the time to write a new event and the packet's content
264 * size is >= 4 MiB), except the last one which can be smaller.
265 */
266 if (G_UNLIKELY(!stream->sc->has_packets)) {
267 if (stream->packet_state.is_open &&
268 bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser) / 8 >= 4 * 1024 * 1024) {
269 /*
270 * Stream's current packet is larger than 4 MiB:
271 * close it. A new packet will be opened just
272 * below.
273 */
274 ret = fs_sink_stream_close_packet(stream, NULL);
275 if (ret) {
3c20ac12 276 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to close packet.");
4164020e
SM
277 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
278 goto end;
279 }
280 }
281
282 if (!stream->packet_state.is_open) {
283 /* Stream's packet is not currently opened: open it */
284 ret = fs_sink_stream_open_packet(stream, NULL, NULL);
285 if (ret) {
3c20ac12 286 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to open packet.");
4164020e
SM
287 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
288 goto end;
289 }
290 }
291 }
292
293 BT_ASSERT_DBG(stream->packet_state.is_open);
294 ret = fs_sink_stream_write_event(stream, cs, ir_event, ec);
295 if (G_UNLIKELY(ret)) {
3c20ac12 296 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to write event.");
4164020e
SM
297 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
298 goto end;
299 }
15fe47e0
PP
300
301end:
4164020e 302 return status;
15fe47e0
PP
303}
304
4164020e
SM
305static inline bt_component_class_sink_consume_method_status
306handle_packet_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
15fe47e0 307{
4164020e
SM
308 int ret;
309 bt_component_class_sink_consume_method_status status =
310 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
311 const bt_packet *ir_packet = bt_message_packet_beginning_borrow_packet_const(msg);
312 const bt_stream *ir_stream = bt_packet_borrow_stream_const(ir_packet);
313 struct fs_sink_stream *stream;
314 const bt_clock_snapshot *cs = NULL;
315
316 stream = borrow_stream(fs_sink, ir_stream);
317 if (G_UNLIKELY(!stream)) {
3c20ac12 318 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
4164020e
SM
319 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
320 goto end;
321 }
322
323 if (stream->sc->packets_have_ts_begin) {
324 cs = bt_message_packet_beginning_borrow_default_clock_snapshot_const(msg);
325 BT_ASSERT(cs);
326 }
327
328 /*
329 * If we previously received a discarded events message with
330 * a time range, make sure that its beginning time matches what's
331 * expected for CTF 1.8, that is:
332 *
333 * * Its beginning time is the previous packet's end
334 * time (or the current packet's beginning time if
335 * this is the first packet).
336 *
337 * We check this here instead of in handle_packet_end_msg()
338 * because we want to catch any incompatible message as early as
339 * possible to report the error.
340 *
341 * Validation of the discarded events message's end time is
342 * performed in handle_packet_end_msg().
343 */
344 if (stream->discarded_events_state.in_range) {
345 uint64_t expected_cs;
346
347 /*
348 * `stream->discarded_events_state.in_range` is only set
349 * when the stream class's discarded events have a time
350 * range.
351 *
352 * It is required that the packet beginning and end
353 * messages for this stream class have times when
354 * discarded events have a time range.
355 */
356 BT_ASSERT(stream->sc->discarded_events_has_ts);
357 BT_ASSERT(stream->sc->packets_have_ts_begin);
358 BT_ASSERT(stream->sc->packets_have_ts_end);
359
360 if (stream->prev_packet_state.end_cs == UINT64_C(-1)) {
361 /* We're opening the first packet */
362 expected_cs = bt_clock_snapshot_get_value(cs);
363 } else {
364 expected_cs = stream->prev_packet_state.end_cs;
365 }
366
367 if (stream->discarded_events_state.beginning_cs != expected_cs) {
3c20ac12
SM
368 BT_CPPLOGE_APPEND_CAUSE_SPEC(
369 fs_sink->logger,
370 "Incompatible discarded events message: "
371 "unexpected beginning time: "
372 "beginning-cs-val={}, "
373 "expected-beginning-cs-val={}, "
374 "stream-id={}, stream-name=\"{}\", "
375 "trace-name=\"{}\", path=\"{}/{}\"",
376 stream->discarded_events_state.beginning_cs, expected_cs,
377 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
378 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
379 stream->trace->path->str, stream->file_name->str);
4164020e
SM
380 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
381 goto end;
382 }
383 }
384
385 /*
386 * If we previously received a discarded packets message with a
387 * time range, make sure that its beginning and end times match
388 * what's expected for CTF 1.8, that is:
389 *
390 * * Its beginning time is the previous packet's end time.
391 *
392 * * Its end time is the current packet's beginning time.
393 */
394 if (stream->discarded_packets_state.in_range) {
395 uint64_t expected_end_cs;
396
397 /*
398 * `stream->discarded_packets_state.in_range` is only
399 * set when the stream class's discarded packets have a
400 * time range.
401 *
402 * It is required that the packet beginning and end
403 * messages for this stream class have times when
404 * discarded packets have a time range.
405 */
406 BT_ASSERT(stream->sc->discarded_packets_has_ts);
407 BT_ASSERT(stream->sc->packets_have_ts_begin);
408 BT_ASSERT(stream->sc->packets_have_ts_end);
409
410 /*
411 * It is not supported to have a discarded packets
412 * message _before_ the first packet: we cannot validate
413 * that its beginning time is compatible with CTF 1.8 in
414 * this case.
415 */
416 if (stream->prev_packet_state.end_cs == UINT64_C(-1)) {
3c20ac12
SM
417 BT_CPPLOGE_APPEND_CAUSE_SPEC(
418 fs_sink->logger,
419 "Incompatible discarded packets message "
420 "occurring before the stream's first packet: "
421 "stream-id={}, stream-name=\"{}\", "
422 "trace-name=\"{}\", path=\"{}/{}\"",
423 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
424 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
425 stream->trace->path->str, stream->file_name->str);
4164020e
SM
426 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
427 goto end;
428 }
429
430 if (stream->discarded_packets_state.beginning_cs != stream->prev_packet_state.end_cs) {
3c20ac12
SM
431 BT_CPPLOGE_APPEND_CAUSE_SPEC(
432 fs_sink->logger,
433 "Incompatible discarded packets message: "
434 "unexpected beginning time: "
435 "beginning-cs-val={}, "
436 "expected-beginning-cs-val={}, "
437 "stream-id={}, stream-name=\"{}\", "
438 "trace-name=\"{}\", path=\"{}/{}\"",
439 stream->discarded_packets_state.beginning_cs, stream->prev_packet_state.end_cs,
440 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
441 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
442 stream->trace->path->str, stream->file_name->str);
4164020e
SM
443 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
444 goto end;
445 }
446
447 expected_end_cs = bt_clock_snapshot_get_value(cs);
448
449 if (stream->discarded_packets_state.end_cs != expected_end_cs) {
3c20ac12
SM
450 BT_CPPLOGE_APPEND_CAUSE_SPEC(
451 fs_sink->logger,
452 "Incompatible discarded packets message: "
453 "unexpected end time: "
454 "end-cs-val={}, "
455 "expected-end-cs-val={}, "
456 "stream-id={}, stream-name=\"{}\", "
457 "trace-name=\"{}\", path=\"{}/{}\"",
458 stream->discarded_packets_state.end_cs, expected_end_cs,
459 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
460 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
461 stream->trace->path->str, stream->file_name->str);
4164020e
SM
462 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
463 goto end;
464 }
465 }
466
467 /*
468 * We're not in a discarded packets time range anymore since we
469 * require that the discarded packets time ranges go from one
470 * packet's end time to the next packet's beginning time, and
471 * we're handling a packet beginning message here.
472 */
473 stream->discarded_packets_state.in_range = false;
474
475 ret = fs_sink_stream_open_packet(stream, cs, ir_packet);
476 if (ret) {
3c20ac12 477 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to open packet.");
4164020e
SM
478 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
479 goto end;
480 }
15fe47e0
PP
481
482end:
4164020e 483 return status;
15fe47e0
PP
484}
485
4164020e
SM
486static inline bt_component_class_sink_consume_method_status
487handle_packet_end_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
15fe47e0 488{
4164020e
SM
489 int ret;
490 bt_component_class_sink_consume_method_status status =
491 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
492 const bt_packet *ir_packet = bt_message_packet_end_borrow_packet_const(msg);
493 const bt_stream *ir_stream = bt_packet_borrow_stream_const(ir_packet);
494 struct fs_sink_stream *stream;
495 const bt_clock_snapshot *cs = NULL;
496
497 stream = borrow_stream(fs_sink, ir_stream);
498 if (G_UNLIKELY(!stream)) {
3c20ac12 499 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
4164020e
SM
500 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
501 goto end;
502 }
503
504 if (stream->sc->packets_have_ts_end) {
505 cs = bt_message_packet_end_borrow_default_clock_snapshot_const(msg);
506 BT_ASSERT(cs);
507 }
508
509 /*
510 * If we previously received a discarded events message with
511 * a time range, make sure that its end time matches what's
512 * expected for CTF 1.8, that is:
513 *
514 * * Its end time is the current packet's end time.
515 *
516 * Validation of the discarded events message's beginning time
517 * is performed in handle_packet_beginning_msg().
518 */
519 if (stream->discarded_events_state.in_range) {
520 uint64_t expected_cs;
521
522 /*
523 * `stream->discarded_events_state.in_range` is only set
524 * when the stream class's discarded events have a time
525 * range.
526 *
527 * It is required that the packet beginning and end
528 * messages for this stream class have times when
529 * discarded events have a time range.
530 */
531 BT_ASSERT(stream->sc->discarded_events_has_ts);
532 BT_ASSERT(stream->sc->packets_have_ts_begin);
533 BT_ASSERT(stream->sc->packets_have_ts_end);
534
535 expected_cs = bt_clock_snapshot_get_value(cs);
536
537 if (stream->discarded_events_state.end_cs != expected_cs) {
3c20ac12
SM
538 BT_CPPLOGE_APPEND_CAUSE_SPEC(
539 fs_sink->logger,
540 "Incompatible discarded events message: "
541 "unexpected end time: "
542 "end-cs-val={}, "
543 "expected-end-cs-val={}, "
544 "stream-id={}, stream-name=\"{}\", "
545 "trace-name=\"{}\", path=\"{}/{}\"",
546 stream->discarded_events_state.end_cs, expected_cs, bt_stream_get_id(ir_stream),
547 bt2c::maybeNull(bt_stream_get_name(ir_stream)),
548 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
549 stream->trace->path->str, stream->file_name->str);
4164020e
SM
550 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
551 goto end;
552 }
553 }
554
555 ret = fs_sink_stream_close_packet(stream, cs);
556 if (ret) {
3c20ac12 557 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to close packet.");
4164020e
SM
558 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
559 goto end;
560 }
561
562 /*
563 * We're not in a discarded events time range anymore since we
564 * require that the discarded events time ranges go from one
565 * packet's end time to the next packet's end time, and we're
566 * handling a packet end message here.
567 */
568 stream->discarded_events_state.in_range = false;
15fe47e0
PP
569
570end:
4164020e 571 return status;
15fe47e0
PP
572}
573
4164020e
SM
574static inline bt_component_class_sink_consume_method_status
575handle_stream_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
15fe47e0 576{
4164020e
SM
577 bt_component_class_sink_consume_method_status status =
578 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
579 const bt_stream *ir_stream = bt_message_stream_beginning_borrow_stream_const(msg);
580 const bt_stream_class *ir_sc = bt_stream_borrow_class_const(ir_stream);
581 struct fs_sink_stream *stream;
582 bool packets_have_beginning_end_cs =
583 bt_stream_class_packets_have_beginning_default_clock_snapshot(ir_sc) &&
584 bt_stream_class_packets_have_end_default_clock_snapshot(ir_sc);
585
586 /*
587 * Not supported: discarded events or discarded packets support
588 * without packets support. Packets are the way to know where
589 * discarded events/packets occurred in CTF 1.8.
590 */
591 if (!bt_stream_class_supports_packets(ir_sc)) {
592 BT_ASSERT(!bt_stream_class_supports_discarded_packets(ir_sc));
593
594 if (!fs_sink->ignore_discarded_events && bt_stream_class_supports_discarded_events(ir_sc)) {
3c20ac12
SM
595 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
596 "Unsupported stream: "
597 "stream does not support packets, "
598 "but supports discarded events: "
599 "stream-addr={}, "
600 "stream-id={}, "
601 "stream-name=\"{}\"",
602 fmt::ptr(ir_stream), bt_stream_get_id(ir_stream),
603 bt2c::maybeNull(bt_stream_get_name(ir_stream)));
4164020e
SM
604 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
605 goto end;
606 }
607 }
608
609 /*
610 * Not supported: discarded events with default clock snapshots,
611 * but packet beginning/end without default clock snapshot.
612 */
613 if (!fs_sink->ignore_discarded_events &&
614 bt_stream_class_discarded_events_have_default_clock_snapshots(ir_sc) &&
615 !packets_have_beginning_end_cs) {
3c20ac12
SM
616 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
617 "Unsupported stream: discarded events have "
618 "default clock snapshots, but packets have no "
619 "beginning and/or end default clock snapshots: "
620 "stream-addr={}, "
621 "stream-id={}, "
622 "stream-name=\"{}\"",
623 fmt::ptr(ir_stream), bt_stream_get_id(ir_stream),
624 bt2c::maybeNull(bt_stream_get_name(ir_stream)));
4164020e
SM
625 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
626 goto end;
627 }
628
629 /*
630 * Not supported: discarded packets with default clock
631 * snapshots, but packet beginning/end without default clock
632 * snapshot.
633 */
634 if (!fs_sink->ignore_discarded_packets &&
635 bt_stream_class_discarded_packets_have_default_clock_snapshots(ir_sc) &&
636 !packets_have_beginning_end_cs) {
3c20ac12
SM
637 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
638 "Unsupported stream: discarded packets have "
639 "default clock snapshots, but packets have no "
640 "beginning and/or end default clock snapshots: "
641 "stream-addr={}, "
642 "stream-id={}, "
643 "stream-name=\"{}\"",
644 fmt::ptr(ir_stream), bt_stream_get_id(ir_stream),
645 bt2c::maybeNull(bt_stream_get_name(ir_stream)));
4164020e
SM
646 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
647 goto end;
648 }
649
650 stream = borrow_stream(fs_sink, ir_stream);
651 if (!stream) {
3c20ac12 652 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
4164020e
SM
653 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
654 goto end;
655 }
656
3c20ac12
SM
657 BT_CPPLOGI_SPEC(fs_sink->logger,
658 "Created new, empty stream file: "
659 "stream-id={}, stream-name=\"{}\", "
660 "trace-name=\"{}\", path=\"{}/{}\"",
661 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
662 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
663 stream->trace->path->str, stream->file_name->str);
15fe47e0
PP
664
665end:
4164020e 666 return status;
15fe47e0
PP
667}
668
4164020e
SM
669static inline bt_component_class_sink_consume_method_status
670handle_stream_end_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
15fe47e0 671{
4164020e
SM
672 bt_component_class_sink_consume_method_status status =
673 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
674 const bt_stream *ir_stream = bt_message_stream_end_borrow_stream_const(msg);
675 struct fs_sink_stream *stream;
676
677 stream = borrow_stream(fs_sink, ir_stream);
678 if (!stream) {
3c20ac12 679 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
4164020e
SM
680 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
681 goto end;
682 }
683
684 if (G_UNLIKELY(!stream->sc->has_packets && stream->packet_state.is_open)) {
685 /* Close stream's current artificial packet */
686 int ret = fs_sink_stream_close_packet(stream, NULL);
687
688 if (ret) {
3c20ac12 689 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to close packet.");
4164020e
SM
690 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
691 goto end;
692 }
693 }
694
3c20ac12
SM
695 BT_CPPLOGI_SPEC(fs_sink->logger,
696 "Closing stream file: "
697 "stream-id={}, stream-name=\"{}\", "
698 "trace-name=\"{}\", path=\"{}/{}\"",
699 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
700 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
701 stream->trace->path->str, stream->file_name->str);
4164020e
SM
702
703 /*
704 * This destroys the stream object and frees all its resources,
705 * closing the stream file.
706 */
707 g_hash_table_remove(stream->trace->streams, ir_stream);
15fe47e0
PP
708
709end:
4164020e 710 return status;
15fe47e0
PP
711}
712
4164020e
SM
713static inline bt_component_class_sink_consume_method_status
714handle_discarded_events_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
15fe47e0 715{
4164020e
SM
716 bt_component_class_sink_consume_method_status status =
717 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
718 const bt_stream *ir_stream = bt_message_discarded_events_borrow_stream_const(msg);
719 struct fs_sink_stream *stream;
720 const bt_clock_snapshot *cs = NULL;
721 bt_property_availability avail;
722 uint64_t count;
723
724 stream = borrow_stream(fs_sink, ir_stream);
725 if (!stream) {
3c20ac12 726 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
4164020e
SM
727 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
728 goto end;
729 }
730
731 if (fs_sink->ignore_discarded_events) {
3c20ac12
SM
732 BT_CPPLOGI_SPEC(fs_sink->logger,
733 "Ignoring discarded events message: "
734 "stream-id={}, stream-name=\"{}\", "
735 "trace-name=\"{}\", path=\"{}/{}\"",
736 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
737 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
738 stream->trace->path->str, stream->file_name->str);
4164020e
SM
739 goto end;
740 }
741
742 if (stream->discarded_events_state.in_range) {
3c20ac12
SM
743 BT_CPPLOGE_APPEND_CAUSE_SPEC(
744 fs_sink->logger,
745 "Unsupported contiguous discarded events message: "
746 "stream-id={}, stream-name=\"{}\", "
747 "trace-name=\"{}\", path=\"{}/{}\"",
748 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
749 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
750 stream->trace->path->str, stream->file_name->str);
4164020e
SM
751 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
752 goto end;
753 }
754
755 /*
756 * If we're currently in an opened packet (got a packet
757 * beginning message, but no packet end message yet), we do not
758 * support having a discarded events message with a time range
759 * because we require that the discarded events message's time
760 * range go from a packet's end time to the next packet's end
761 * time.
762 */
763 if (stream->packet_state.is_open && stream->sc->discarded_events_has_ts) {
3c20ac12
SM
764 BT_CPPLOGE_APPEND_CAUSE_SPEC(
765 fs_sink->logger,
766 "Unsupported discarded events message with "
767 "default clock snapshots occurring within a packet: "
768 "stream-id={}, stream-name=\"{}\", "
769 "trace-name=\"{}\", path=\"{}/{}\"",
770 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
771 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
772 stream->trace->path->str, stream->file_name->str);
4164020e
SM
773 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
774 goto end;
775 }
776
777 if (stream->sc->discarded_events_has_ts) {
778 /*
779 * Make the stream's state be in the time range of a
780 * discarded events message since we have the message's
781 * time range (`stream->sc->discarded_events_has_ts`).
782 */
783 stream->discarded_events_state.in_range = true;
784
785 /*
786 * The clock snapshot values will be validated when
787 * handling the next packet beginning and end messages
788 * (next calls to handle_packet_beginning_msg() and
789 * handle_packet_end_msg()).
790 */
791 cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(msg);
792 BT_ASSERT(cs);
793 stream->discarded_events_state.beginning_cs = bt_clock_snapshot_get_value(cs);
794 cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(msg);
795 BT_ASSERT(cs);
796 stream->discarded_events_state.end_cs = bt_clock_snapshot_get_value(cs);
797 }
798
799 avail = bt_message_discarded_events_get_count(msg, &count);
800 if (avail != BT_PROPERTY_AVAILABILITY_AVAILABLE) {
801 /*
802 * There's no specific count of discarded events: set it
803 * to 1 so that we know that we at least discarded
804 * something.
805 */
806 count = 1;
807 }
808
809 stream->packet_state.discarded_events_counter += count;
15fe47e0
PP
810
811end:
4164020e 812 return status;
15fe47e0
PP
813}
814
4164020e
SM
815static inline bt_component_class_sink_consume_method_status
816handle_discarded_packets_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
15fe47e0 817{
4164020e
SM
818 bt_component_class_sink_consume_method_status status =
819 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
820 const bt_stream *ir_stream = bt_message_discarded_packets_borrow_stream_const(msg);
821 struct fs_sink_stream *stream;
822 const bt_clock_snapshot *cs = NULL;
823 bt_property_availability avail;
824 uint64_t count;
825
826 stream = borrow_stream(fs_sink, ir_stream);
827 if (!stream) {
3c20ac12 828 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
4164020e
SM
829 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
830 goto end;
831 }
832
833 if (fs_sink->ignore_discarded_packets) {
3c20ac12
SM
834 BT_CPPLOGI_SPEC(fs_sink->logger,
835 "Ignoring discarded packets message: "
836 "stream-id={}, stream-name=\"{}\", "
837 "trace-name=\"{}\", path=\"{}/{}\"",
838 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
839 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
840 stream->trace->path->str, stream->file_name->str);
4164020e
SM
841 goto end;
842 }
843
844 if (stream->discarded_packets_state.in_range) {
3c20ac12
SM
845 BT_CPPLOGE_APPEND_CAUSE_SPEC(
846 fs_sink->logger,
847 "Unsupported contiguous discarded packets message: "
848 "stream-id={}, stream-name=\"{}\", "
849 "trace-name=\"{}\", path=\"{}/{}\"",
850 bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
851 bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
852 stream->trace->path->str, stream->file_name->str);
4164020e
SM
853 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
854 goto end;
855 }
856
857 /*
858 * Discarded packets messages are guaranteed to occur between
859 * packets.
860 */
861 BT_ASSERT(!stream->packet_state.is_open);
862
863 if (stream->sc->discarded_packets_has_ts) {
864 /*
865 * Make the stream's state be in the time range of a
866 * discarded packets message since we have the message's
867 * time range (`stream->sc->discarded_packets_has_ts`).
868 */
869 stream->discarded_packets_state.in_range = true;
870
871 /*
872 * The clock snapshot values will be validated when
873 * handling the next packet beginning message (next call
874 * to handle_packet_beginning_msg()).
875 */
876 cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(msg);
877 BT_ASSERT(cs);
878 stream->discarded_packets_state.beginning_cs = bt_clock_snapshot_get_value(cs);
879 cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(msg);
880 BT_ASSERT(cs);
881 stream->discarded_packets_state.end_cs = bt_clock_snapshot_get_value(cs);
882 }
883
884 avail = bt_message_discarded_packets_get_count(msg, &count);
885 if (avail != BT_PROPERTY_AVAILABILITY_AVAILABLE) {
886 /*
887 * There's no specific count of discarded packets: set
888 * it to 1 so that we know that we at least discarded
889 * something.
890 */
891 count = 1;
892 }
893
894 stream->packet_state.seq_num += count;
15fe47e0
PP
895
896end:
4164020e 897 return status;
15fe47e0
PP
898}
899
4164020e 900static inline void put_messages(bt_message_array_const msgs, uint64_t count)
15fe47e0 901{
4164020e 902 uint64_t i;
15fe47e0 903
4164020e
SM
904 for (i = 0; i < count; i++) {
905 BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
906 }
15fe47e0
PP
907}
908
4164020e 909bt_component_class_sink_consume_method_status ctf_fs_sink_consume(bt_self_component_sink *self_comp)
15fe47e0 910{
4164020e
SM
911 bt_component_class_sink_consume_method_status status =
912 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
913 struct fs_sink_comp *fs_sink;
914 bt_message_iterator_next_status next_status;
915 uint64_t msg_count = 0;
916 bt_message_array_const msgs;
917
918 fs_sink = (fs_sink_comp *) bt_self_component_get_data(
919 bt_self_component_sink_as_self_component(self_comp));
920 BT_ASSERT_DBG(fs_sink);
921 BT_ASSERT_DBG(fs_sink->upstream_iter);
922
923 /* Consume messages */
924 next_status = bt_message_iterator_next(fs_sink->upstream_iter, &msgs, &msg_count);
925 if (next_status < 0) {
926 status = (bt_component_class_sink_consume_method_status) next_status;
3c20ac12
SM
927 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
928 "Failed to get next message from upstream iterator.");
4164020e
SM
929 goto end;
930 }
931
932 switch (next_status) {
933 case BT_MESSAGE_ITERATOR_NEXT_STATUS_OK:
934 {
935 uint64_t i;
936
937 for (i = 0; i < msg_count; i++) {
938 const bt_message *msg = msgs[i];
939
940 BT_ASSERT_DBG(msg);
941
942 switch (bt_message_get_type(msg)) {
943 case BT_MESSAGE_TYPE_EVENT:
944 status = handle_event_msg(fs_sink, msg);
945 break;
946 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
947 status = handle_packet_beginning_msg(fs_sink, msg);
948 break;
949 case BT_MESSAGE_TYPE_PACKET_END:
950 status = handle_packet_end_msg(fs_sink, msg);
951 break;
952 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
953 /* Ignore */
3c20ac12
SM
954 BT_CPPLOGD_STR_SPEC(fs_sink->logger,
955 "Ignoring message iterator inactivity message.");
4164020e
SM
956 break;
957 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
958 status = handle_stream_beginning_msg(fs_sink, msg);
959 break;
960 case BT_MESSAGE_TYPE_STREAM_END:
961 status = handle_stream_end_msg(fs_sink, msg);
962 break;
963 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
964 status = handle_discarded_events_msg(fs_sink, msg);
965 break;
966 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
967 status = handle_discarded_packets_msg(fs_sink, msg);
968 break;
969 default:
970 bt_common_abort();
971 }
972
973 BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
974
975 if (status != BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK) {
3c20ac12
SM
976 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
977 "Failed to handle message: "
978 "generated CTF traces could be incomplete: "
979 "output-dir-path=\"{}\"",
980 fs_sink->output_dir_path->str);
4164020e
SM
981 goto error;
982 }
983 }
984
985 break;
986 }
987 case BT_MESSAGE_ITERATOR_NEXT_STATUS_AGAIN:
988 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_AGAIN;
989 break;
990 case BT_MESSAGE_ITERATOR_NEXT_STATUS_END:
991 /* TODO: Finalize all traces (should already be done?) */
992 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_END;
993 break;
994 default:
995 break;
996 }
997
998 goto end;
15fe47e0
PP
999
1000error:
4164020e
SM
1001 BT_ASSERT(status != BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK);
1002 put_messages(msgs, msg_count);
15fe47e0
PP
1003
1004end:
4164020e 1005 return status;
15fe47e0
PP
1006}
1007
e803df70 1008bt_component_class_sink_graph_is_configured_method_status
4164020e 1009ctf_fs_sink_graph_is_configured(bt_self_component_sink *self_comp)
15fe47e0 1010{
4164020e
SM
1011 bt_component_class_sink_graph_is_configured_method_status status;
1012 bt_message_iterator_create_from_sink_component_status msg_iter_status;
1013 fs_sink_comp *fs_sink = (fs_sink_comp *) bt_self_component_get_data(
1014 bt_self_component_sink_as_self_component(self_comp));
1015
1016 msg_iter_status = bt_message_iterator_create_from_sink_component(
1017 self_comp, bt_self_component_sink_borrow_input_port_by_name(self_comp, in_port_name),
1018 &fs_sink->upstream_iter);
1019 if (msg_iter_status != BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK) {
1020 status = (bt_component_class_sink_graph_is_configured_method_status) msg_iter_status;
3c20ac12 1021 BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to create upstream iterator.");
4164020e
SM
1022 goto end;
1023 }
1024
1025 status = BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK;
15fe47e0 1026end:
4164020e 1027 return status;
15fe47e0
PP
1028}
1029
15fe47e0
PP
1030void ctf_fs_sink_finalize(bt_self_component_sink *self_comp)
1031{
4164020e
SM
1032 fs_sink_comp *fs_sink = (fs_sink_comp *) bt_self_component_get_data(
1033 bt_self_component_sink_as_self_component(self_comp));
15fe47e0 1034
4164020e 1035 destroy_fs_sink_comp(fs_sink);
15fe47e0 1036}
This page took 0.125846 seconds and 4 git commands to generate.