Adapt `sink.ctf.fs` to current API
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 8 Mar 2019 16:06:38 +0000 (11:06 -0500)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Thu, 2 May 2019 20:50:15 +0000 (20:50 +0000)
commit15fe47e0499a9805421da82a25c026f3eb359eaa
treea11c16061aa70601eb7e8dc462a643398080a881
parentd6981059a3b2d68025cd9b1b246cc18d0eb6f0b1
Adapt `sink.ctf.fs` to current API

This patch is a complete rewrite of the `sink.ctf.fs` component class to
work with the current library's API.

Changes
=======
A `sink.ctf.fs` component does not use the CTF writer API anymore: it
tracks its own traces and streams, and writes data thanks to the common,
internal ctfser API (also used by CTF writer).

On the metadata side, the component class has its own CTF IR data
structures. They are based on the common CTF source IR data structures,
but they have additional fields and otherwise contain only what's needed
for a `sink.ctf.fs` component to work.

A `sink.ctf.fs` component systematically "protects" structure FC member
and variant FC option names with a leading `_`. This is suggested by
TSDL 1.8. Because of this, any enumeration FC label could be what
selects a following variant FC option, so enumeration FC labels are also
escaped with `_`. This is a temporary measure which matches the
behaviour of `src.ctf.fs` and `src.ctf.lttng-live`. We should solve this
at the API level later.

If the component fails to resolve the length FC of a dynamic array FC or
the selector FC of a variant FC, it falls back to creating its own
length FC or selector FC just above the requesting FC, within the same
structure FC, giving it a name which avoids any clash with other
members. Here's an example (trace IR, as TSDL):

    struct {
        struct {
            integer { size = 8; } len;
        } s;
        string str[s.len];
    }

This layout is perfectly valid from the trace IR's point of view.
However it is known to fail in Babeltrace 1 and Trace Compass (but is
accepted by Babeltrace 2), so the actual TSDL output for this becomes:

    struct {
        struct {
            integer { size = 8; } _len;
        } _s;
        integer { size = 32; } ___str_len;
        string { encoding = UTF8; } _str[___str_len];
    }

The same goes for a variant FC's selector FC:

    struct {
        struct {
            enum : integer { size = 8; } {
                A = 1,
                B = 5,
                C = 17 ... 24
            } tag;
        } s;
        variant <s.tag> {
            integer { size = 8; } A;
            string B;
            struct { } C;
        } var;
    }

becomes:

    struct {
        struct {
            enum : integer { size = 8; } {
                "_A" = 1,
                "_B" = 5,
                "_C" = 17 ... 24,
            } _tag;
        } _s;
        enum : integer { size = 16; } {
            "_A" = 0,
            "_B" = 1,
            "_C" = 2,
        } ___var_tag;
        variant <___var_tag> {
            integer { size = 8; } _A;
            string { encoding = UTF8; } _B;
            struct { } _C;
        } _var;
    }

This way we don't lose the original length/selector field value while
still writing the dynamic array/variant field.

A generated dynamic array FC's length FC is a 32-bit unsigned integer FC
(should be enough) while a generated variant FC's selector FC is a
16-bit unsigned enumeration FC.

A `sink.ctf.fs` component writes its events to the appropriate streams
as it receives them, as opposed to CTF writer which flushes a whole
packet when calling bt_ctf_stream_flush(). This means a packet's total
size is not limited to the available memory.

A `sink.ctf.fs` component generates a new trace UUID instead of using
the original trace class's UUID. The logic behind this is that there is
no way to know that the received trace and streams match exactly the
original trace and streams (the source and filters can modify them), so
systematically using the original UUID could lead to two different CTF
traces having the same UUID.

A `sink.ctf.fs` component writes the metadata file of a given CTF trace
and closes it when the upstream message iterator ends or when the trace
is destroyed. The component does not take a trace or trace class
reference: it registers a trace destruction listener so that it can free
the resources associated to a trace (and its streams) as soon as it's
destroyed. Also, it frees the resouces associated to a given stream when
getting a stream end message for it.

The way output directory paths and stream file names are created is
unchanged from the previous version. The `assume-single-trace` parameter
still exists.

There are three new parameters:

`ignore-discarded-events` (boolean):
    Ignore discarded events messages. This can be useful because there
    are limitations (see below) regarding where discarded events
    messages can be in the message flow, and what their beginning and
    end times can be.

`ignore-discarded-packets` (boolean):
    Ignore discarded packets messages. This can be useful because there
    are limitations (see below) regarding where discarded packets
    messages can be in the message flow, and what their beginning and
    end times can be.

`quiet` (boolean):
    Do not print anything. When the component is not quiet, it prints a
    message to the standard output every time it creates a complete CTF
    trace with the absolute path to it.

Known limitations
=================
This component class is not complete, in that it does not support all
the features of Babeltrace 2. For most cases, there should be no problem
using it to write streams created by a `src.ctf.fs` or
`src.ctf.lttng-live` component.

As of this patch, the known limitations are:

* Only names which are valid in TSDL are supported. This applies to:

  * Trace class environment keys.
  * Structure FC member names.
  * Variant FC option names.
  * Clock class names.

* The value type of a trace class environment entry must be integer or
  string.

* Unknown stream clocks are not supported.

* Stream activity messages are ignored.

* Discarded events and packets messages must occur between packets.

* There must not be more than one discarded events message or more than
  one discarded packets message between packets.

* The time range of a discarded events message must be from the last
  packet's end time to the next packet's end time, except when it occurs
  before the first packet of a given stream, where its beginning time
  must be the first packet's beginning time.

* The time range of a discarded packets message must be from the last
  packet's end time to the next packet's beginning time.

All the constraints above are checked as soon as possible and, when one
is not satisfied, the component fails with a detailed error.

The very strict and very CTF-ish limitations regarding discarded events
and packets messages are the reason why I added the aforementioned
`ignore-discarded-events` and `ignore-discarded-packets` parameters.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
19 files changed:
include/babeltrace/ctfser-internal.h
plugins/ctf/Makefile.am
plugins/ctf/fs-sink/Makefile.am
plugins/ctf/fs-sink/fs-sink-ctf-meta.h [new file with mode: 0644]
plugins/ctf/fs-sink/fs-sink-stream.c [new file with mode: 0644]
plugins/ctf/fs-sink/fs-sink-stream.h [new file with mode: 0644]
plugins/ctf/fs-sink/fs-sink-trace.c [new file with mode: 0644]
plugins/ctf/fs-sink/fs-sink-trace.h [new file with mode: 0644]
plugins/ctf/fs-sink/fs-sink.c [new file with mode: 0644]
plugins/ctf/fs-sink/fs-sink.h [new file with mode: 0644]
plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c [new file with mode: 0644]
plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.h [new file with mode: 0644]
plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c [new file with mode: 0644]
plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.h [new file with mode: 0644]
plugins/ctf/fs-sink/write.c [deleted file]
plugins/ctf/fs-sink/writer.c [deleted file]
plugins/ctf/fs-sink/writer.h [deleted file]
plugins/ctf/fs-src/Makefile.am
plugins/ctf/plugin.c
This page took 0.027087 seconds and 4 git commands to generate.