From 1a9f7075566704f314c36f92339c2e2fed697523 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Mon, 22 May 2017 15:33:03 -0400 Subject: [PATCH] ctf.fs source: recurse to find multiples CTF traces MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit One port per CTF data stream amongst all the traces that are found from the user's starting path is created. The traces are named so as to be able to replicate the original tree by stripping their common prefix within slash boundaries. For example: user passes `hello` as the starting path, the component finds the following traces: hello/world/kilo hello/yes hello/ispep/zero/mini These traces would be named: world/kilo yes ispep/zero/mini Another example: user passes `hello` as the starting path, the component finds the following trace: hello/world/kilo In this case, the trace is named `kilo`. I used realpath() to normalize the paths and make sure that there aren't `.` or `..` in the trace's name. Opening a trace located directly in `/` is not supported. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- plugins/ctf/common/metadata/ast.h | 2 +- plugins/ctf/common/metadata/decoder.c | 4 +- plugins/ctf/common/metadata/decoder.h | 5 +- .../ctf/common/metadata/visitor-generate-ir.c | 8 +- plugins/ctf/fs-src/data-stream.c | 62 +- plugins/ctf/fs-src/data-stream.h | 3 +- plugins/ctf/fs-src/fs.c | 535 ++++++++++++++---- plugins/ctf/fs-src/fs.h | 59 +- plugins/ctf/fs-src/metadata.c | 11 +- plugins/ctf/fs-src/metadata.h | 2 +- plugins/ctf/lttng-live/metadata.c | 4 +- 11 files changed, 530 insertions(+), 165 deletions(-) diff --git a/plugins/ctf/common/metadata/ast.h b/plugins/ctf/common/metadata/ast.h index 3ab552aa..b06eb73f 100644 --- a/plugins/ctf/common/metadata/ast.h +++ b/plugins/ctf/common/metadata/ast.h @@ -309,7 +309,7 @@ const char *node_type(struct ctf_node *node); BT_HIDDEN struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd, - uint64_t clock_class_offset_ns); + uint64_t clock_class_offset_ns, const char *name); void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor); diff --git a/plugins/ctf/common/metadata/decoder.c b/plugins/ctf/common/metadata/decoder.c index 41badbb6..6d60c619 100644 --- a/plugins/ctf/common/metadata/decoder.c +++ b/plugins/ctf/common/metadata/decoder.c @@ -265,7 +265,7 @@ int ctf_metadata_decoder_packetized_file_stream_to_buf( BT_HIDDEN struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err, - uint64_t clock_class_offset_ns) + uint64_t clock_class_offset_ns, const char *name) { struct ctf_metadata_decoder *mdec = g_new0(struct ctf_metadata_decoder, 1); @@ -276,7 +276,7 @@ struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err, mdec->err_stream = err; mdec->visitor = ctf_visitor_generate_ir_create(err, - clock_class_offset_ns); + clock_class_offset_ns, name); if (!mdec->visitor) { ctf_metadata_decoder_destroy(mdec); mdec = NULL; diff --git a/plugins/ctf/common/metadata/decoder.h b/plugins/ctf/common/metadata/decoder.h index dd60c219..cf8ed00d 100644 --- a/plugins/ctf/common/metadata/decoder.h +++ b/plugins/ctf/common/metadata/decoder.h @@ -34,13 +34,14 @@ enum ctf_metadata_decoder_status { /* * Creates a CTF metadata decoder with `err` as the error stream (can * be `NULL` to disable error output). `clock_class_offset_ns` is an - * offset to apply to the decoded clock classes's offsets. + * offset to apply to the decoded clock classes's offsets. `name` is + * this decoder's trace's name. * * Returns `NULL` on error. */ BT_HIDDEN struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err, - uint64_t clock_class_offset_ns); + uint64_t clock_class_offset_ns, const char *name); /* * Destroys a CTF metadata decoder that you created with diff --git a/plugins/ctf/common/metadata/visitor-generate-ir.c b/plugins/ctf/common/metadata/visitor-generate-ir.c index c8d8e780..12e28398 100644 --- a/plugins/ctf/common/metadata/visitor-generate-ir.c +++ b/plugins/ctf/common/metadata/visitor-generate-ir.c @@ -4641,7 +4641,7 @@ end: BT_HIDDEN struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd, - uint64_t clock_class_offset_ns) + uint64_t clock_class_offset_ns, const char *name) { int ret; struct ctx *ctx = NULL; @@ -4653,6 +4653,12 @@ struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd, goto error; } + ret = bt_ctf_trace_set_name(trace, name); + if (ret) { + _FPERROR(efd, "cannot set trace's name to `%s`", name); + goto error; + } + /* Set packet header to NULL to override the default one */ ret = bt_ctf_trace_set_packet_header_type(trace, NULL); if (ret) { diff --git a/plugins/ctf/fs-src/data-stream.c b/plugins/ctf/fs-src/data-stream.c index bc0d1217..851c094e 100644 --- a/plugins/ctf/fs-src/data-stream.c +++ b/plugins/ctf/fs-src/data-stream.c @@ -350,74 +350,78 @@ end: BT_HIDDEN struct ctf_fs_stream *ctf_fs_stream_create( - struct ctf_fs_component *ctf_fs, const char *path) + struct ctf_fs_trace *ctf_fs_trace, const char *path) { int ret; - struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1); + struct ctf_fs_stream *ctf_fs_stream = g_new0(struct ctf_fs_stream, 1); - if (!stream) { + if (!ctf_fs_stream) { goto error; } - stream->file = ctf_fs_file_create(ctf_fs); - if (!stream->file) { + ctf_fs_stream->file = ctf_fs_file_create(ctf_fs_trace->ctf_fs); + if (!ctf_fs_stream->file) { goto error; } - stream->cc_prio_map = bt_get(ctf_fs->cc_prio_map); - g_string_assign(stream->file->path, path); - ret = ctf_fs_file_open(ctf_fs, stream->file, "rb"); + ctf_fs_stream->cc_prio_map = bt_get(ctf_fs_trace->cc_prio_map); + g_string_assign(ctf_fs_stream->file->path, path); + ret = ctf_fs_file_open(ctf_fs_trace->ctf_fs, ctf_fs_stream->file, "rb"); if (ret) { goto error; } - stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata->trace, - ctf_fs->page_size, medops, stream, - ctf_fs->error_fp); - if (!stream->notif_iter) { + ctf_fs_stream->notif_iter = bt_ctf_notif_iter_create( + ctf_fs_trace->metadata->trace, + ctf_fs_trace->ctf_fs->page_size, medops, ctf_fs_stream, + ctf_fs_trace->ctf_fs->error_fp); + if (!ctf_fs_stream->notif_iter) { goto error; } - stream->mmap_max_len = ctf_fs->page_size * 2048; - ret = init_stream_index(stream); + ctf_fs_stream->mmap_max_len = ctf_fs_trace->ctf_fs->page_size * 2048; + ret = init_stream_index(ctf_fs_stream); if (ret) { goto error; } + goto end; + error: /* Do not touch "borrowed" file. */ - ctf_fs_stream_destroy(stream); - stream = NULL; + ctf_fs_stream_destroy(ctf_fs_stream); + ctf_fs_stream = NULL; + end: - return stream; + return ctf_fs_stream; } BT_HIDDEN -void ctf_fs_stream_destroy(struct ctf_fs_stream *stream) +void ctf_fs_stream_destroy(struct ctf_fs_stream *ctf_fs_stream) { - if (!stream) { + if (!ctf_fs_stream) { return; } - bt_put(stream->cc_prio_map); + bt_put(ctf_fs_stream->cc_prio_map); - if (stream->file) { - ctf_fs_file_destroy(stream->file); + if (ctf_fs_stream->file) { + ctf_fs_file_destroy(ctf_fs_stream->file); } - if (stream->stream) { - BT_PUT(stream->stream); + if (ctf_fs_stream->stream) { + BT_PUT(ctf_fs_stream->stream); } - if (stream->notif_iter) { - bt_ctf_notif_iter_destroy(stream->notif_iter); + if (ctf_fs_stream->notif_iter) { + bt_ctf_notif_iter_destroy(ctf_fs_stream->notif_iter); } - if (stream->index.entries) { - g_array_free(stream->index.entries, TRUE); + if (ctf_fs_stream->index.entries) { + g_array_free(ctf_fs_stream->index.entries, TRUE); } - g_free(stream); + g_free(ctf_fs_stream); } BT_HIDDEN diff --git a/plugins/ctf/fs-src/data-stream.h b/plugins/ctf/fs-src/data-stream.h index 3d484425..60a3110b 100644 --- a/plugins/ctf/fs-src/data-stream.h +++ b/plugins/ctf/fs-src/data-stream.h @@ -33,6 +33,7 @@ struct ctf_fs_component; struct ctf_fs_file; +struct ctf_fs_trace; struct ctf_fs_stream; struct index_entry { @@ -48,7 +49,7 @@ struct index { BT_HIDDEN struct ctf_fs_stream *ctf_fs_stream_create( - struct ctf_fs_component *ctf_fs, const char *path); + struct ctf_fs_trace *ctf_fs_trace, const char *path); BT_HIDDEN void ctf_fs_stream_destroy(struct ctf_fs_stream *stream); diff --git a/plugins/ctf/fs-src/fs.c b/plugins/ctf/fs-src/fs.c index d50966f7..6fc53e3c 100644 --- a/plugins/ctf/fs-src/fs.c +++ b/plugins/ctf/fs-src/fs.c @@ -3,10 +3,9 @@ * * Babeltrace CTF file system Reader Component * + * Copyright 2015-2017 Philippe Proulx * Copyright 2016 Jérémie Galarneau * - * Author: Jérémie Galarneau - * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -76,39 +75,29 @@ enum bt_notification_iterator_status ctf_fs_iterator_init( struct bt_private_notification_iterator *it, struct bt_private_port *port) { - struct ctf_fs_stream *stream = NULL; - struct ctf_fs_component *ctf_fs; + struct ctf_fs_stream *ctf_fs_stream = NULL; struct ctf_fs_port_data *port_data; - struct bt_private_component *priv_comp = - bt_private_notification_iterator_get_private_component(it); enum bt_notification_iterator_status ret = BT_NOTIFICATION_ITERATOR_STATUS_OK; - assert(priv_comp); - - ctf_fs = bt_private_component_get_user_data(priv_comp); - if (!ctf_fs) { - ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; - goto error; - } - port_data = bt_private_port_get_user_data(port); if (!port_data) { ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; goto error; } - stream = ctf_fs_stream_create(ctf_fs, port_data->path->str); - if (!stream) { + ctf_fs_stream = ctf_fs_stream_create(port_data->ctf_fs_trace, + port_data->path->str); + if (!ctf_fs_stream) { goto error; } - ret = bt_private_notification_iterator_set_user_data(it, stream); + ret = bt_private_notification_iterator_set_user_data(it, ctf_fs_stream); if (ret) { goto error; } - stream = NULL; + ctf_fs_stream = NULL; goto end; error: @@ -119,40 +108,59 @@ error: } end: - ctf_fs_stream_destroy(stream); - bt_put(priv_comp); + ctf_fs_stream_destroy(ctf_fs_stream); return ret; } static -void ctf_fs_destroy_data(struct ctf_fs_component *ctf_fs) +void ctf_fs_destroy(struct ctf_fs_component *ctf_fs) { if (!ctf_fs) { return; } - if (ctf_fs->trace_path) { - g_string_free(ctf_fs->trace_path, TRUE); + if (ctf_fs->traces) { + g_ptr_array_free(ctf_fs->traces, TRUE); } if (ctf_fs->port_data) { g_ptr_array_free(ctf_fs->port_data, TRUE); } - if (ctf_fs->metadata) { - ctf_fs_metadata_fini(ctf_fs->metadata); - g_free(ctf_fs->metadata); + g_free(ctf_fs); +} + +static +void ctf_fs_trace_destroy(void *data) +{ + struct ctf_fs_trace *ctf_fs_trace = data; + + if (!ctf_fs_trace) { + return; } - bt_put(ctf_fs->cc_prio_map); - g_free(ctf_fs); + if (ctf_fs_trace->path) { + g_string_free(ctf_fs_trace->path, TRUE); + } + + if (ctf_fs_trace->name) { + g_string_free(ctf_fs_trace->name, TRUE); + } + + if (ctf_fs_trace->metadata) { + ctf_fs_metadata_fini(ctf_fs_trace->metadata); + g_free(ctf_fs_trace->metadata); + } + + bt_put(ctf_fs_trace->cc_prio_map); + g_free(ctf_fs_trace); } void ctf_fs_finalize(struct bt_private_component *component) { void *data = bt_private_component_get_user_data(component); - ctf_fs_destroy_data(data); + ctf_fs_destroy(data); } static @@ -171,13 +179,14 @@ void port_data_destroy(void *data) { } static -int create_one_port(struct ctf_fs_component *ctf_fs, - const char *stream_basename, const char *stream_path) +int create_one_port_for_trace(struct ctf_fs_trace *ctf_fs_trace, + const char *stream_path) { int ret = 0; struct bt_private_port *port = NULL; struct ctf_fs_port_data *port_data = NULL; GString *port_name = NULL; + struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs; port_name = g_string_new(NULL); if (!port_name) { @@ -185,10 +194,8 @@ int create_one_port(struct ctf_fs_component *ctf_fs, } /* Assign the name for the new output port */ - g_string_assign(port_name, ""); - g_string_printf(port_name, "trace0-stream-%s", stream_basename); - PDBG("Creating one port named `%s` associated with path `%s`\n", - port_name->str, stream_path); + g_string_printf(port_name, "%s", stream_path); + PDBG("Creating one port named `%s`\n", port_name->str); /* Create output port for this file */ port_data = g_new0(struct ctf_fs_port_data, 1); @@ -196,6 +203,7 @@ int create_one_port(struct ctf_fs_component *ctf_fs, goto error; } + port_data->ctf_fs_trace = ctf_fs_trace; port_data->path = g_string_new(stream_path); if (!port_data->path) { goto error; @@ -225,19 +233,20 @@ end: } static -int create_ports(struct ctf_fs_component *ctf_fs) +int create_ports_for_trace(struct ctf_fs_trace *ctf_fs_trace) { int ret = 0; const char *basename; GError *error = NULL; GDir *dir = NULL; struct ctf_fs_file *file = NULL; + struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs; /* Create one output port for each stream file */ - dir = g_dir_open(ctf_fs->trace_path->str, 0, &error); + dir = g_dir_open(ctf_fs_trace->path->str, 0, &error); if (!dir) { PERR("Cannot open directory `%s`: %s (code %d)\n", - ctf_fs->trace_path->str, error->message, + ctf_fs_trace->path->str, error->message, error->code); goto error; } @@ -245,28 +254,31 @@ int create_ports(struct ctf_fs_component *ctf_fs) while ((basename = g_dir_read_name(dir))) { if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) { /* Ignore the metadata stream. */ - PDBG("Ignoring metadata file `%s`\n", basename); + PDBG("Ignoring metadata file `%s/%s`\n", + ctf_fs_trace->path->str, basename); continue; } if (basename[0] == '.') { - PDBG("Ignoring hidden file `%s`\n", basename); + PDBG("Ignoring hidden file `%s/%s`\n", + ctf_fs_trace->path->str, basename); continue; } /* Create the file. */ file = ctf_fs_file_create(ctf_fs); if (!file) { - PERR("Cannot create stream file object for file `%s`\n", - basename); + PERR("Cannot create stream file object for file `%s/%s`\n", + ctf_fs_trace->path->str, basename); goto error; } /* Create full path string. */ g_string_append_printf(file->path, "%s/%s", - ctf_fs->trace_path->str, basename); + ctf_fs_trace->path->str, basename); if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) { - PDBG("Ignoring non-regular file `%s`\n", basename); + PDBG("Ignoring non-regular file `%s`\n", + file->path->str); ctf_fs_file_destroy(file); file = NULL; continue; @@ -274,22 +286,22 @@ int create_ports(struct ctf_fs_component *ctf_fs) ret = ctf_fs_file_open(ctf_fs, file, "rb"); if (ret) { - PERR("Cannot open stream file `%s`\n", basename); + PERR("Cannot open stream file `%s`\n", file->path->str); goto error; } if (file->size == 0) { /* Skip empty stream. */ - PDBG("Ignoring empty file `%s`\n", basename); + PDBG("Ignoring empty file `%s`\n", file->path->str); ctf_fs_file_destroy(file); file = NULL; continue; } - ret = create_one_port(ctf_fs, basename, file->path->str); + ret = create_one_port_for_trace(ctf_fs_trace, file->path->str); if (ret) { PERR("Cannot create output port for file `%s`\n", - basename); + file->path->str); goto error; } @@ -317,30 +329,31 @@ end: } static -int create_cc_prio_map(struct ctf_fs_component *ctf_fs) +int create_cc_prio_map(struct ctf_fs_trace *ctf_fs_trace) { int ret = 0; size_t i; int count; - assert(ctf_fs); - ctf_fs->cc_prio_map = bt_clock_class_priority_map_create(); - if (!ctf_fs->cc_prio_map) { + assert(ctf_fs_trace); + ctf_fs_trace->cc_prio_map = bt_clock_class_priority_map_create(); + if (!ctf_fs_trace->cc_prio_map) { ret = -1; goto end; } - count = bt_ctf_trace_get_clock_class_count(ctf_fs->metadata->trace); + count = bt_ctf_trace_get_clock_class_count( + ctf_fs_trace->metadata->trace); assert(count >= 0); for (i = 0; i < count; i++) { struct bt_ctf_clock_class *clock_class = bt_ctf_trace_get_clock_class_by_index( - ctf_fs->metadata->trace, i); + ctf_fs_trace->metadata->trace, i); assert(clock_class); ret = bt_clock_class_priority_map_add_clock_class( - ctf_fs->cc_prio_map, clock_class, 0); + ctf_fs_trace->cc_prio_map, clock_class, 0); BT_PUT(clock_class); if (ret) { @@ -352,13 +365,344 @@ end: return ret; } +static +struct ctf_fs_trace *ctf_fs_trace_create(struct ctf_fs_component *ctf_fs, + const char *path, const char *name) +{ + struct ctf_fs_trace *ctf_fs_trace; + int ret; + + ctf_fs_trace = g_new0(struct ctf_fs_trace, 1); + if (!ctf_fs_trace) { + goto end; + } + + ctf_fs_trace->ctf_fs = ctf_fs; + ctf_fs_trace->path = g_string_new(path); + if (!ctf_fs_trace->path) { + goto error; + } + + ctf_fs_trace->name = g_string_new(name); + if (!ctf_fs_trace->name) { + goto error; + } + + ctf_fs_trace->metadata = g_new0(struct ctf_fs_metadata, 1); + if (!ctf_fs_trace->metadata) { + goto error; + } + + ret = ctf_fs_metadata_set_trace(ctf_fs_trace); + if (ret) { + goto error; + } + + ret = create_cc_prio_map(ctf_fs_trace); + if (ret) { + goto error; + } + + ret = create_ports_for_trace(ctf_fs_trace); + if (ret) { + goto error; + } + + goto end; + +error: + ctf_fs_trace_destroy(ctf_fs_trace); + ctf_fs_trace = NULL; +end: + return ctf_fs_trace; +} + +static +int path_is_ctf_trace(const char *path) +{ + GString *metadata_path = g_string_new(NULL); + int ret = 0; + + if (!metadata_path) { + ret = -1; + goto end; + } + + g_string_printf(metadata_path, "%s/%s", path, CTF_FS_METADATA_FILENAME); + + if (g_file_test(metadata_path->str, G_FILE_TEST_IS_REGULAR)) { + ret = 1; + goto end; + } + +end: + g_string_free(metadata_path, TRUE); + return ret; +} + +static +int add_trace_path(struct ctf_fs_component *ctf_fs, GList **trace_paths, + const char *path) +{ + GString *path_str = g_string_new(NULL); + int ret = 0; + char *rp = NULL; + + if (!path_str) { + ret = -1; + goto end; + } + + /* + * Find the real path so that we don't have relative components + * in the trace name. This also squashes consecutive slashes and + * removes any slash at the end. + */ + rp = realpath(path, NULL); + if (!rp) { + PERR("realpath() failed: %s (%d)\n", strerror(errno), errno); + ret = -1; + goto end; + } + + if (strcmp(rp, "/") == 0) { + PERR("Opening a trace in `/` is not supported.\n"); + ret = -1; + goto end; + } + + g_string_assign(path_str, rp); + *trace_paths = g_list_prepend(*trace_paths, path_str); + assert(*trace_paths); + +end: + free(rp); + return ret; +} + +static +int find_ctf_traces(struct ctf_fs_component *ctf_fs, + GList **trace_paths, const char *start_path) +{ + int ret; + GError *error = NULL; + GDir *dir = NULL; + const char *basename = NULL; + + /* Check if the starting path is a CTF trace itself */ + ret = path_is_ctf_trace(start_path); + if (ret < 0) { + goto end; + } + + if (ret) { + /* + * Do not even recurse: a CTF trace cannot contain + * another CTF trace. + */ + ret = add_trace_path(ctf_fs, trace_paths, start_path); + goto end; + } + + /* Look for subdirectories */ + if (!g_file_test(start_path, G_FILE_TEST_IS_DIR)) { + /* Starting path is not a directory: end of recursion */ + goto end; + } + + dir = g_dir_open(start_path, 0, &error); + if (!dir) { + if (error->code == G_FILE_ERROR_ACCES) { + PDBG("Cannot open directory `%s`: %s (code %d): continuing\n", + start_path, error->message, error->code); + goto end; + } + + PERR("Cannot open directory `%s`: %s (code %d)\n", + start_path, error->message, error->code); + ret = -1; + goto end; + } + + while ((basename = g_dir_read_name(dir))) { + GString *sub_path = g_string_new(NULL); + + if (!sub_path) { + ret = -1; + goto end; + } + + g_string_printf(sub_path, "%s/%s", start_path, basename); + ret = find_ctf_traces(ctf_fs, trace_paths, sub_path->str); + g_string_free(sub_path, TRUE); + if (ret) { + goto end; + } + } + +end: + if (dir) { + g_dir_close(dir); + } + + if (error) { + g_error_free(error); + } + + return ret; +} + +static +GList *create_trace_names(GList *trace_paths) { + GList *trace_names = NULL; + size_t chars_to_strip = 0; + size_t at = 0; + GList *node; + bool done = false; + + /* + * Find the number of characters to strip from the beginning, + * that is, the longest prefix until a common slash (also + * stripped). + */ + while (true) { + gchar common_ch = '\0'; + + for (node = trace_paths; node; node = g_list_next(node)) { + GString *gstr = node->data; + gchar this_ch = gstr->str[at]; + + if (this_ch == '\0') { + done = true; + break; + } + + if (common_ch == '\0') { + /* + * Establish the expected common + * character at this position. + */ + common_ch = this_ch; + continue; + } + + if (this_ch != common_ch) { + done = true; + break; + } + } + + if (done) { + break; + } + + if (common_ch == '/') { + /* + * Common character is a slash: safe to include + * this slash in the number of characters to + * strip because the paths are guaranteed not to + * end with slash. + */ + chars_to_strip = at + 1; + } + + at++; + } + + /* Create the trace names */ + for (node = trace_paths; node; node = g_list_next(node)) { + GString *trace_name = g_string_new(NULL); + GString *trace_path = node->data; + + g_string_assign(trace_name, &trace_path->str[chars_to_strip]); + trace_names = g_list_append(trace_names, trace_name); + } + + return trace_names; +} + +static +int create_ctf_fs_traces(struct ctf_fs_component *ctf_fs, + const char *path_param) +{ + struct ctf_fs_trace *ctf_fs_trace = NULL; + int ret = 0; + GList *trace_paths = NULL; + GList *trace_names = NULL; + GList *tp_node; + GList *tn_node; + + ret = find_ctf_traces(ctf_fs, &trace_paths, path_param); + if (ret) { + goto error; + } + + if (!trace_paths) { + PERR("No CTF traces recursively found in `%s`.\n", + path_param); + goto error; + } + + trace_names = create_trace_names(trace_paths); + if (!trace_names) { + PERR("Cannot create trace names from trace paths.\n"); + goto error; + } + + for (tp_node = trace_paths, tn_node = trace_names; tp_node; + tp_node = g_list_next(tp_node), + tn_node = g_list_next(tn_node)) { + GString *trace_path = tp_node->data; + GString *trace_name = tn_node->data; + + ctf_fs_trace = ctf_fs_trace_create(ctf_fs, trace_path->str, + trace_name->str); + if (!ctf_fs_trace) { + PERR("Cannot create trace for `%s`.\n", + trace_path->str); + goto error; + } + } + + g_ptr_array_add(ctf_fs->traces, ctf_fs_trace); + ctf_fs_trace = NULL; + goto end; + +error: + ret = -1; + ctf_fs_trace_destroy(ctf_fs_trace); + +end: + for (tp_node = trace_paths; tp_node; tp_node = g_list_next(tp_node)) { + if (tp_node->data) { + g_string_free(tp_node->data, TRUE); + } + } + + for (tn_node = trace_names; tn_node; tn_node = g_list_next(tn_node)) { + if (tn_node->data) { + g_string_free(tn_node->data, TRUE); + } + } + + if (trace_paths) { + g_list_free(trace_paths); + } + + if (trace_names) { + g_list_free(trace_names); + } + + return ret; +} + static struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, struct bt_value *params) { struct ctf_fs_component *ctf_fs; struct bt_value *value = NULL; - const char *path; + const char *path_param; int ret; ctf_fs = g_new0(struct ctf_fs_component, 1); @@ -366,36 +710,23 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, goto end; } + ret = bt_private_component_set_user_data(priv_comp, ctf_fs); + assert(ret == 0); + /* * We don't need to get a new reference here because as long as * our private ctf_fs_component object exists, the containing * private component should also exist. */ ctf_fs->priv_comp = priv_comp; - - /* FIXME: should probably look for a source URI */ value = bt_value_map_get(params, "path"); - if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) { - goto error; - } - - ret = bt_value_string_get(value, &path); - if (ret) { - goto error; - } - - ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy); - if (!ctf_fs->port_data) { + if (!bt_value_is_string(value)) { goto error; } - ctf_fs->trace_path = g_string_new(path); - if (!ctf_fs->trace_path) { - BT_PUT(value); - goto error; - } - bt_put(value); - + ret = bt_value_string_get(value, &path_param); + assert(ret == 0); + BT_PUT(value); value = bt_value_map_get(params, "offset-s"); if (value) { int64_t offset; @@ -406,13 +737,9 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, goto error; } ret = bt_value_integer_get(value, &offset); - if (ret != BT_VALUE_STATUS_OK) { - fprintf(stderr, - "Failed to get offset-s value\n"); - goto error; - } + assert(ret == 0); ctf_fs->options.clock_offset = offset; - bt_put(value); + BT_PUT(value); } value = bt_value_map_get(params, "offset-ns"); @@ -425,35 +752,24 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, goto error; } ret = bt_value_integer_get(value, &offset); - if (ret != BT_VALUE_STATUS_OK) { - fprintf(stderr, - "Failed to get offset-ns value\n"); - goto error; - } + assert(ret == 0); ctf_fs->options.clock_offset_ns = offset; - bt_put(value); + BT_PUT(value); } ctf_fs->error_fp = stderr; ctf_fs->page_size = (size_t) getpagesize(); - - // FIXME: check error. - ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1); - if (!ctf_fs->metadata) { - goto error; - } - - ret = ctf_fs_metadata_set_trace(ctf_fs); - if (ret) { + ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy); + if (!ctf_fs->port_data) { goto error; } - ret = create_cc_prio_map(ctf_fs); - if (ret) { + ctf_fs->traces = g_ptr_array_new_with_free_func(ctf_fs_trace_destroy); + if (!ctf_fs->traces) { goto error; } - ret = create_ports(ctf_fs); + ret = create_ctf_fs_traces(ctf_fs, path_param); if (ret) { goto error; } @@ -461,9 +777,13 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, goto end; error: - ctf_fs_destroy_data(ctf_fs); + ctf_fs_destroy(ctf_fs); ctf_fs = NULL; + ret = bt_private_component_set_user_data(priv_comp, NULL); + assert(ret == 0); + end: + bt_put(value); return ctf_fs; } @@ -474,23 +794,12 @@ enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp, struct ctf_fs_component *ctf_fs; enum bt_component_status ret = BT_COMPONENT_STATUS_OK; - assert(priv_comp); ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0; ctf_fs = ctf_fs_create(priv_comp, params); if (!ctf_fs) { - ret = BT_COMPONENT_STATUS_NOMEM; - goto end; + ret = BT_COMPONENT_STATUS_ERROR; } - ret = bt_private_component_set_user_data(priv_comp, ctf_fs); - if (ret != BT_COMPONENT_STATUS_OK) { - goto error; - } -end: - return ret; -error: - (void) bt_private_component_set_user_data(priv_comp, NULL); - ctf_fs_destroy_data(ctf_fs); return ret; } diff --git a/plugins/ctf/fs-src/fs.h b/plugins/ctf/fs-src/fs.h index acc14a1a..63b299a0 100644 --- a/plugins/ctf/fs-src/fs.h +++ b/plugins/ctf/fs-src/fs.h @@ -38,25 +38,43 @@ BT_HIDDEN extern bool ctf_fs_debug; struct ctf_fs_file { + /* Weak */ struct ctf_fs_component *ctf_fs; + + /* Owned by this */ GString *path; + + /* Owned by this */ FILE *fp; + off_t size; }; struct ctf_fs_metadata { + /* Owned by this */ struct bt_ctf_trace *trace; + + /* Owned by this */ + char *text; + uint8_t uuid[16]; bool is_uuid_set; int bo; - char *text; }; struct ctf_fs_stream { + /* Owned by this */ struct ctf_fs_file *file; + + /* Owned by this */ struct bt_ctf_stream *stream; + + /* Owned by this */ struct bt_clock_class_priority_map *cc_prio_map; + + /* Owned by this */ struct bt_ctf_notif_iter *notif_iter; + /* A stream is assumed to be indexed. */ struct index index; void *mmap_addr; @@ -81,21 +99,44 @@ struct ctf_fs_component_options { uint64_t clock_offset_ns; }; -struct ctf_fs_port_data { - GString *path; -}; - struct ctf_fs_component { + /* Weak */ struct bt_private_component *priv_comp; - GString *trace_path; + + /* Array of struct ctf_fs_port_data *, owned by this */ + GPtrArray *port_data; + + /* Array of struct ctf_fs_trace *, owned by this */ + GPtrArray *traces; + + struct ctf_fs_component_options options; FILE *error_fp; size_t page_size; - struct ctf_fs_component_options options; +}; + +struct ctf_fs_trace { + /* Weak */ + struct ctf_fs_component *ctf_fs; + + /* Owned by this */ struct ctf_fs_metadata *metadata; + + /* Owned by this */ struct bt_clock_class_priority_map *cc_prio_map; - /* Array of struct ctf_fs_port_data *, owned by this */ - GPtrArray *port_data; + /* Owned by this */ + GString *path; + + /* Owned by this */ + GString *name; +}; + +struct ctf_fs_port_data { + /* Owned by this */ + GString *path; + + /* Weak */ + struct ctf_fs_trace *ctf_fs_trace; }; BT_HIDDEN diff --git a/plugins/ctf/fs-src/metadata.c b/plugins/ctf/fs-src/metadata.c index 24252733..c6b50953 100644 --- a/plugins/ctf/fs-src/metadata.c +++ b/plugins/ctf/fs-src/metadata.c @@ -101,13 +101,14 @@ end: return file; } -int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs) +int ctf_fs_metadata_set_trace(struct ctf_fs_trace *ctf_fs_trace) { int ret = 0; + struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs; struct ctf_fs_file *file = NULL; struct ctf_metadata_decoder *metadata_decoder = NULL; - file = get_file(ctf_fs, ctf_fs->trace_path->str); + file = get_file(ctf_fs, ctf_fs_trace->path->str); if (!file) { PERR("Cannot create metadata file object\n"); ret = -1; @@ -116,7 +117,7 @@ int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs) metadata_decoder = ctf_metadata_decoder_create(ctf_fs->error_fp, ctf_fs->options.clock_offset * NSEC_PER_SEC + - ctf_fs->options.clock_offset_ns); + ctf_fs->options.clock_offset_ns, ctf_fs_trace->name->str); if (!metadata_decoder) { PERR("Cannot create metadata decoder object\n"); ret = -1; @@ -129,9 +130,9 @@ int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs) goto end; } - ctf_fs->metadata->trace = ctf_metadata_decoder_get_trace( + ctf_fs_trace->metadata->trace = ctf_metadata_decoder_get_trace( metadata_decoder); - assert(ctf_fs->metadata->trace); + assert(ctf_fs_trace->metadata->trace); end: ctf_fs_file_destroy(file); diff --git a/plugins/ctf/fs-src/metadata.h b/plugins/ctf/fs-src/metadata.h index 85a77268..cb822ad4 100644 --- a/plugins/ctf/fs-src/metadata.h +++ b/plugins/ctf/fs-src/metadata.h @@ -38,7 +38,7 @@ BT_HIDDEN void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata); BT_HIDDEN -int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs); +int ctf_fs_metadata_set_trace(struct ctf_fs_trace *ctf_fs_trace); BT_HIDDEN FILE *ctf_fs_metadata_open_file(const char *trace_path); diff --git a/plugins/ctf/lttng-live/metadata.c b/plugins/ctf/lttng-live/metadata.c index d3b7b095..7c8ce4dd 100644 --- a/plugins/ctf/lttng-live/metadata.c +++ b/plugins/ctf/lttng-live/metadata.c @@ -239,7 +239,9 @@ int lttng_live_metadata_create_stream(struct lttng_live_session *session, } metadata->stream_id = stream_id; //TODO: add clock offset option - metadata->decoder = ctf_metadata_decoder_create(stderr, 0); + //TODO: add (preferably unique) trace's name + metadata->decoder = ctf_metadata_decoder_create(stderr, 0, + "lttng-live"); if (!metadata->decoder) { goto error; } -- 2.34.1