+int create_ports_for_trace(struct ctf_fs_component *ctf_fs,
+ struct ctf_fs_trace *ctf_fs_trace)
+{
+ int ret = 0;
+ size_t i;
+
+ /* Create one output port for each stream file group */
+ for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
+ struct ctf_fs_ds_file_group *ds_file_group =
+ g_ptr_array_index(ctf_fs_trace->ds_file_groups, i);
+
+ ret = create_one_port_for_trace(ctf_fs, ctf_fs_trace,
+ ds_file_group);
+ if (ret) {
+ BT_LOGE("Cannot create output port.");
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+static
+void ctf_fs_ds_file_info_destroy(struct ctf_fs_ds_file_info *ds_file_info)
+{
+ if (!ds_file_info) {
+ return;
+ }
+
+ if (ds_file_info->path) {
+ g_string_free(ds_file_info->path, TRUE);
+ }
+
+ ctf_fs_ds_index_destroy(ds_file_info->index);
+ g_free(ds_file_info);
+}
+
+static
+struct ctf_fs_ds_file_info *ctf_fs_ds_file_info_create(const char *path,
+ int64_t begin_ns, struct ctf_fs_ds_index *index)
+{
+ struct ctf_fs_ds_file_info *ds_file_info;
+
+ ds_file_info = g_new0(struct ctf_fs_ds_file_info, 1);
+ if (!ds_file_info) {
+ goto end;
+ }
+
+ ds_file_info->path = g_string_new(path);
+ if (!ds_file_info->path) {
+ ctf_fs_ds_file_info_destroy(ds_file_info);
+ ds_file_info = NULL;
+ goto end;
+ }
+
+ ds_file_info->begin_ns = begin_ns;
+ ds_file_info->index = index;
+ index = NULL;
+
+end:
+ ctf_fs_ds_index_destroy(index);
+ return ds_file_info;
+}
+
+static
+void ctf_fs_ds_file_group_destroy(struct ctf_fs_ds_file_group *ds_file_group)
+{
+ if (!ds_file_group) {
+ return;
+ }
+
+ if (ds_file_group->ds_file_infos) {
+ g_ptr_array_free(ds_file_group->ds_file_infos, TRUE);
+ }
+
+ bt_stream_put_ref(ds_file_group->stream);
+ bt_stream_class_put_ref(ds_file_group->stream_class);
+ g_free(ds_file_group);
+}
+
+static
+struct ctf_fs_ds_file_group *ctf_fs_ds_file_group_create(
+ struct ctf_fs_trace *ctf_fs_trace,
+ bt_stream_class *stream_class,
+ uint64_t stream_instance_id)
+{
+ struct ctf_fs_ds_file_group *ds_file_group;
+
+ ds_file_group = g_new0(struct ctf_fs_ds_file_group, 1);
+ if (!ds_file_group) {
+ goto error;
+ }
+
+ ds_file_group->ds_file_infos = g_ptr_array_new_with_free_func(
+ (GDestroyNotify) ctf_fs_ds_file_info_destroy);
+ if (!ds_file_group->ds_file_infos) {
+ goto error;
+ }
+
+ ds_file_group->stream_id = stream_instance_id;
+ BT_ASSERT(stream_class);
+ ds_file_group->stream_class = stream_class;
+ bt_stream_class_get_ref(ds_file_group->stream_class);
+ ds_file_group->ctf_fs_trace = ctf_fs_trace;
+ goto end;
+
+error:
+ ctf_fs_ds_file_group_destroy(ds_file_group);
+ ds_file_group = NULL;
+
+end:
+ return ds_file_group;
+}
+
+/* Replace by g_ptr_array_insert when we depend on glib >= 2.40. */
+static
+void array_insert(GPtrArray *array, gpointer element, size_t pos)
+{
+ size_t original_array_len = array->len;
+
+ /* Allocate an unused element at the end of the array. */
+ g_ptr_array_add(array, NULL);
+
+ /* If we are not inserting at the end, move the elements by one. */
+ if (pos < original_array_len) {
+ memmove(&(array->pdata[pos + 1]),
+ &(array->pdata[pos]),
+ (original_array_len - pos) * sizeof(gpointer));
+ }
+
+ /* Insert the value and bump the array len */
+ array->pdata[pos] = element;
+}
+
+static
+int ctf_fs_ds_file_group_add_ds_file_info(
+ struct ctf_fs_ds_file_group *ds_file_group,
+ const char *path, int64_t begin_ns,
+ struct ctf_fs_ds_index *index)
+{
+ struct ctf_fs_ds_file_info *ds_file_info;
+ gint i = 0;
+ int ret = 0;
+
+ /* Onwership of index is transferred. */
+ ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns, index);
+ index = NULL;
+ if (!ds_file_info) {
+ goto error;
+ }
+
+ /* Find a spot to insert this one */
+ for (i = 0; i < ds_file_group->ds_file_infos->len; i++) {
+ struct ctf_fs_ds_file_info *other_ds_file_info =
+ g_ptr_array_index(ds_file_group->ds_file_infos, i);
+
+ if (begin_ns < other_ds_file_info->begin_ns) {
+ break;
+ }
+ }
+
+ array_insert(ds_file_group->ds_file_infos, ds_file_info, i);
+ ds_file_info = NULL;
+ goto end;
+
+error:
+ ctf_fs_ds_file_info_destroy(ds_file_info);
+ ctf_fs_ds_index_destroy(index);
+ ret = -1;
+end:
+ return ret;
+}
+
+static
+int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
+ const char *path)
+{
+ bt_stream_class *stream_class = NULL;
+ int64_t stream_instance_id = -1;
+ int64_t begin_ns = -1;
+ struct ctf_fs_ds_file_group *ds_file_group = NULL;
+ bool add_group = false;
+ int ret;
+ size_t i;
+ struct ctf_fs_ds_file *ds_file = NULL;
+ struct ctf_fs_ds_index *index = NULL;
+ struct bt_msg_iter *msg_iter = NULL;
+ struct ctf_stream_class *sc = NULL;
+ struct bt_msg_iter_packet_properties props;
+
+ msg_iter = bt_msg_iter_create(ctf_fs_trace->metadata->tc,
+ bt_common_get_page_size() * 8, ctf_fs_ds_file_medops, NULL);
+ if (!msg_iter) {
+ BT_LOGE_STR("Cannot create a CTF message iterator.");
+ goto error;
+ }
+
+ ds_file = ctf_fs_ds_file_create(ctf_fs_trace, NULL, msg_iter,
+ NULL, path);
+ if (!ds_file) {
+ goto error;
+ }
+
+ ret = bt_msg_iter_get_packet_properties(ds_file->msg_iter, &props);
+ if (ret) {
+ BT_LOGE("Cannot get stream file's first packet's header and context fields (`%s`).",
+ path);
+ goto error;
+ }
+
+ sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
+ props.stream_class_id);
+ BT_ASSERT(sc);
+ stream_class = sc->ir_sc;
+ BT_ASSERT(stream_class);
+ stream_instance_id = props.data_stream_id;
+
+ if (props.snapshots.beginning_clock != UINT64_C(-1)) {
+ BT_ASSERT(sc->default_clock_class);
+ ret = bt_util_clock_cycles_to_ns_from_origin(
+ props.snapshots.beginning_clock,
+ sc->default_clock_class->frequency,
+ sc->default_clock_class->offset_seconds,
+ sc->default_clock_class->offset_cycles, &begin_ns);
+ if (ret) {
+ BT_LOGE("Cannot convert clock cycles to nanoseconds from origin (`%s`).",
+ path);
+ goto error;
+ }
+ }
+
+ index = ctf_fs_ds_file_build_index(ds_file);
+ if (!index) {
+ BT_LOGW("Failed to index CTF stream file \'%s\'",
+ ds_file->file->path->str);
+ }
+
+ if (begin_ns == -1) {
+ /*
+ * No beggining timestamp to sort the stream files
+ * within a stream file group, so consider that this
+ * file must be the only one within its group.
+ */
+ stream_instance_id = -1;
+ }
+
+ if (stream_instance_id == -1) {
+ /*
+ * No stream instance ID or no beginning timestamp:
+ * create a unique stream file group for this stream
+ * file because, even if there's a stream instance ID,
+ * there's no timestamp to order the file within its
+ * group.
+ */
+ ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace,
+ stream_class, stream_instance_id);
+ if (!ds_file_group) {
+ goto error;
+ }
+
+ ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group,
+ path, begin_ns, index);
+ /* Ownership of index is transferred. */
+ index = NULL;
+ if (ret) {
+ goto error;
+ }
+
+ add_group = true;
+ goto end;
+ }
+
+ BT_ASSERT(stream_instance_id != -1);
+ BT_ASSERT(begin_ns != -1);
+
+ /* Find an existing stream file group with this ID */
+ for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
+ ds_file_group = g_ptr_array_index(
+ ctf_fs_trace->ds_file_groups, i);
+
+ if (ds_file_group->stream_class == stream_class &&
+ ds_file_group->stream_id ==
+ stream_instance_id) {
+ break;
+ }
+
+ ds_file_group = NULL;
+ }
+
+ if (!ds_file_group) {
+ ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace,
+ stream_class, stream_instance_id);
+ if (!ds_file_group) {
+ goto error;
+ }
+
+ add_group = true;
+ }
+
+ ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group, path,
+ begin_ns, index);
+ index = NULL;
+ if (ret) {
+ goto error;
+ }
+
+ goto end;
+
+error:
+ ctf_fs_ds_file_group_destroy(ds_file_group);
+ ret = -1;
+
+end:
+ if (add_group && ds_file_group) {
+ g_ptr_array_add(ctf_fs_trace->ds_file_groups, ds_file_group);
+ }
+
+ ctf_fs_ds_file_destroy(ds_file);
+
+ if (msg_iter) {
+ bt_msg_iter_destroy(msg_iter);
+ }
+
+ ctf_fs_ds_index_destroy(index);
+ return ret;
+}
+
+static
+int create_ds_file_groups(struct ctf_fs_trace *ctf_fs_trace)