X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=src%2Fplugins%2Fctf%2Ffs-src%2Fdata-stream-file.cpp;h=d2f7e102eb85734881aa90dbc4ca9e899632e835;hb=e27adb90396a8c985b7d27004f82c56ff9c31b3d;hp=1a49d87889c1c76ec0efc330fbe7680fb94d1280;hpb=ecd7492f21a492b70569d5ecc1d3a808241b63f0;p=babeltrace.git diff --git a/src/plugins/ctf/fs-src/data-stream-file.cpp b/src/plugins/ctf/fs-src/data-stream-file.cpp index 1a49d878..d2f7e102 100644 --- a/src/plugins/ctf/fs-src/data-stream-file.cpp +++ b/src/plugins/ctf/fs-src/data-stream-file.cpp @@ -6,27 +6,21 @@ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation */ -#define BT_COMP_LOG_SELF_COMP (self_comp) -#define BT_LOG_OUTPUT_LEVEL (log_level) -#define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/DS" -#include "logging/comp-logging.h" - -#include -#include -#include -#include #include -#include -#include "compat/mman.h" -#include "compat/endian.h" -#include -#include "common/common.h" -#include "file.hpp" -#include "metadata.hpp" -#include "../common/msg-iter/msg-iter.hpp" -#include "common/assert.h" +#include +#include + +#include "compat/endian.h" /* IWYU pragma: keep */ +#include "compat/mman.h" /* IWYU: pragma keep */ +#include "cpp-common/bt2c/glib-up.hpp" +#include "cpp-common/bt2s/make-unique.hpp" +#include "cpp-common/vendor/fmt/format.h" + +#include "../common/src/msg-iter/msg-iter.hpp" #include "data-stream-file.hpp" -#include +#include "file.hpp" +#include "fs.hpp" +#include "lttng-index.hpp" static inline size_t remaining_mmap_bytes(struct ctf_fs_ds_file *ds_file) { @@ -46,31 +40,24 @@ static bool offset_ist_mapped(struct ctf_fs_ds_file *ds_file, off_t offset_in_fi static enum ctf_msg_iter_medium_status ds_file_munmap(struct ctf_fs_ds_file *ds_file) { - enum ctf_msg_iter_medium_status status; - bt_self_component *self_comp = ds_file->self_comp; - bt_logging_level log_level = ds_file->log_level; - BT_ASSERT(ds_file); if (!ds_file->mmap_addr) { - status = CTF_MSG_ITER_MEDIUM_STATUS_OK; - goto end; + return CTF_MSG_ITER_MEDIUM_STATUS_OK; } if (bt_munmap(ds_file->mmap_addr, ds_file->mmap_len)) { - BT_COMP_LOGE_ERRNO("Cannot memory-unmap file", - ": address=%p, size=%zu, file_path=\"%s\", file=%p", ds_file->mmap_addr, - ds_file->mmap_len, ds_file->file ? ds_file->file->path->str : "NULL", - ds_file->file ? ds_file->file->fp : NULL); - status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; - goto end; + BT_CPPLOGE_ERRNO_SPEC(ds_file->logger, "Cannot memory-unmap file", + ": address={}, size={}, file_path=\"{}\", file={}", + fmt::ptr(ds_file->mmap_addr), ds_file->mmap_len, + ds_file->file ? ds_file->file->path : "NULL", + ds_file->file ? fmt::ptr(ds_file->file->fp) : NULL); + return CTF_MSG_ITER_MEDIUM_STATUS_ERROR; } ds_file->mmap_addr = NULL; - status = CTF_MSG_ITER_MEDIUM_STATUS_OK; -end: - return status; + return CTF_MSG_ITER_MEDIUM_STATUS_OK; } /* @@ -87,10 +74,6 @@ end: static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_file, off_t requested_offset_in_file) { - enum ctf_msg_iter_medium_status status; - bt_self_component *self_comp = ds_file->self_comp; - bt_logging_level log_level = ds_file->log_level; - /* Ensure the requested offset is in the file range. */ BT_ASSERT(requested_offset_in_file >= 0); BT_ASSERT(requested_offset_in_file < ds_file->file->size); @@ -102,14 +85,13 @@ static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_fi if (offset_ist_mapped(ds_file, requested_offset_in_file)) { ds_file->request_offset_in_mapping = requested_offset_in_file - ds_file->mmap_offset_in_file; - status = CTF_MSG_ITER_MEDIUM_STATUS_OK; - goto end; + return CTF_MSG_ITER_MEDIUM_STATUS_OK; } /* Unmap old region */ - status = ds_file_munmap(ds_file); + ctf_msg_iter_medium_status status = ds_file_munmap(ds_file); if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) { - goto end; + return status; } /* @@ -117,7 +99,8 @@ static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_fi * contains `requested_offset_in_file`. */ ds_file->request_offset_in_mapping = - requested_offset_in_file % bt_mmap_get_offset_align_size(ds_file->log_level); + requested_offset_in_file % + bt_mmap_get_offset_align_size(static_cast(ds_file->logger.level())); ds_file->mmap_offset_in_file = requested_offset_in_file - ds_file->request_offset_in_mapping; ds_file->mmap_len = MIN(ds_file->file->size - ds_file->mmap_offset_in_file, ds_file->mmap_max_len); @@ -125,20 +108,17 @@ static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_fi BT_ASSERT(ds_file->mmap_len > 0); ds_file->mmap_addr = - bt_mmap((void *) 0, ds_file->mmap_len, PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp), - ds_file->mmap_offset_in_file, ds_file->log_level); + bt_mmap(ds_file->mmap_len, PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp.get()), + ds_file->mmap_offset_in_file, static_cast(ds_file->logger.level())); if (ds_file->mmap_addr == MAP_FAILED) { - BT_COMP_LOGE("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %jd: %s", - ds_file->mmap_len, ds_file->file->path->str, ds_file->file->fp, - (intmax_t) ds_file->mmap_offset_in_file, strerror(errno)); - status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; - goto end; + BT_CPPLOGE_SPEC(ds_file->logger, + "Cannot memory-map address (size {}) of file \"{}\" ({}) at offset {}: {}", + ds_file->mmap_len, ds_file->file->path, fmt::ptr(ds_file->file->fp), + (intmax_t) ds_file->mmap_offset_in_file, strerror(errno)); + return CTF_MSG_ITER_MEDIUM_STATUS_ERROR; } - status = CTF_MSG_ITER_MEDIUM_STATUS_OK; - -end: - return status; + return CTF_MSG_ITER_MEDIUM_STATUS_OK; } /* @@ -154,8 +134,6 @@ end: static enum ctf_msg_iter_medium_status ds_file_mmap_next(struct ctf_fs_ds_file *ds_file) { - enum ctf_msg_iter_medium_status status; - /* * If we're called, it's because more bytes are requested but we have * given all the bytes of the current mapping. @@ -167,23 +145,16 @@ static enum ctf_msg_iter_medium_status ds_file_mmap_next(struct ctf_fs_ds_file * * no next mapping. */ if (ds_file->mmap_offset_in_file + ds_file->mmap_len == ds_file->file->size) { - status = CTF_MSG_ITER_MEDIUM_STATUS_EOF; - goto end; + return CTF_MSG_ITER_MEDIUM_STATUS_EOF; } - status = ds_file_mmap(ds_file, ds_file->mmap_offset_in_file + ds_file->mmap_len); - -end: - return status; + return ds_file_mmap(ds_file, ds_file->mmap_offset_in_file + ds_file->mmap_len); } static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, uint8_t **buffer_addr, size_t *buffer_sz, void *data) { - enum ctf_msg_iter_medium_status status = CTF_MSG_ITER_MEDIUM_STATUS_OK; struct ctf_fs_ds_file *ds_file = (struct ctf_fs_ds_file *) data; - bt_self_component *self_comp = ds_file->self_comp; - bt_logging_level log_level = ds_file->log_level; BT_ASSERT(request_sz > 0); @@ -194,22 +165,21 @@ static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, ui if (remaining_mmap_bytes(ds_file) == 0) { /* Are we at the end of the file? */ if (ds_file->mmap_offset_in_file >= ds_file->file->size) { - BT_COMP_LOGD("Reached end of file \"%s\" (%p)", ds_file->file->path->str, - ds_file->file->fp); - status = CTF_MSG_ITER_MEDIUM_STATUS_EOF; - goto end; + BT_CPPLOGD_SPEC(ds_file->logger, "Reached end of file \"{}\" ({})", ds_file->file->path, + fmt::ptr(ds_file->file->fp)); + return CTF_MSG_ITER_MEDIUM_STATUS_EOF; } - status = ds_file_mmap_next(ds_file); + ctf_msg_iter_medium_status status = ds_file_mmap_next(ds_file); switch (status) { case CTF_MSG_ITER_MEDIUM_STATUS_OK: break; case CTF_MSG_ITER_MEDIUM_STATUS_EOF: - goto end; + return CTF_MSG_ITER_MEDIUM_STATUS_EOF; default: - BT_COMP_LOGE("Cannot memory-map next region of file \"%s\" (%p)", - ds_file->file->path->str, ds_file->file->fp); - goto error; + BT_CPPLOGE_SPEC(ds_file->logger, "Cannot memory-map next region of file \"{}\" ({})", + ds_file->file->path, fmt::ptr(ds_file->file->fp)); + return status; } } @@ -220,35 +190,26 @@ static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, ui *buffer_addr = ((uint8_t *) ds_file->mmap_addr) + ds_file->request_offset_in_mapping; ds_file->request_offset_in_mapping += *buffer_sz; - goto end; -error: - status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; - -end: - return status; + return CTF_MSG_ITER_MEDIUM_STATUS_OK; } static bt_stream *medop_borrow_stream(bt_stream_class *stream_class, int64_t, void *data) { struct ctf_fs_ds_file *ds_file = (struct ctf_fs_ds_file *) data; bt_stream_class *ds_file_stream_class; - bt_stream *stream = NULL; - ds_file_stream_class = bt_stream_borrow_class(ds_file->stream); + ds_file_stream_class = ds_file->stream->cls().libObjPtr(); if (stream_class != ds_file_stream_class) { /* * Not supported: two packets described by two different * stream classes within the same data stream file. */ - goto end; + return nullptr; } - stream = ds_file->stream; - -end: - return stream; + return ds_file->stream->libObjPtr(); } static enum ctf_msg_iter_medium_status medop_seek(off_t offset, void *data) @@ -270,27 +231,31 @@ struct ctf_msg_iter_medium_ops ctf_fs_ds_file_medops = { struct ctf_fs_ds_group_medops_data { + explicit ctf_fs_ds_group_medops_data(const bt2c::Logger& parentLogger) : + logger {parentLogger, "PLUGIN/SRC.CTF.FS/DS-GROUP-MEDOPS"} + { + } + + bt2c::Logger logger; + /* Weak, set once at creation time. */ - struct ctf_fs_ds_file_group *ds_file_group; + struct ctf_fs_ds_file_group *ds_file_group = nullptr; /* * Index (as in element rank) of the index entry of ds_file_groups' * index we will read next (so, the one after the one we are reading * right now). */ - guint next_index_entry_index; + guint next_index_entry_index = 0; /* * File we are currently reading. Changes whenever we switch to * reading another data file. - * - * Owned by this. */ - struct ctf_fs_ds_file *file; + ctf_fs_ds_file::UP file; /* Weak, for context / logging / appending causes. */ - bt_self_message_iterator *self_msg_iter; - bt_logging_level log_level; + bt_self_message_iterator *self_msg_iter = nullptr; }; static enum ctf_msg_iter_medium_status medop_group_request_bytes(size_t request_sz, @@ -300,7 +265,7 @@ static enum ctf_msg_iter_medium_status medop_group_request_bytes(size_t request_ struct ctf_fs_ds_group_medops_data *data = (struct ctf_fs_ds_group_medops_data *) void_data; /* Return bytes from the current file. */ - return medop_request_bytes(request_sz, buffer_addr, buffer_sz, data->file); + return medop_request_bytes(request_sz, buffer_addr, buffer_sz, data->file.get()); } static bt_stream *medop_group_borrow_stream(bt_stream_class *stream_class, int64_t stream_id, @@ -308,7 +273,7 @@ static bt_stream *medop_group_borrow_stream(bt_stream_class *stream_class, int64 { struct ctf_fs_ds_group_medops_data *data = (struct ctf_fs_ds_group_medops_data *) void_data; - return medop_borrow_stream(stream_class, stream_id, data->file); + return medop_borrow_stream(stream_class, stream_id, data->file.get()); } /* @@ -318,27 +283,20 @@ static bt_stream *medop_group_borrow_stream(bt_stream_class *stream_class, int64 static enum ctf_msg_iter_medium_status ctf_fs_ds_group_medops_set_file(struct ctf_fs_ds_group_medops_data *data, - struct ctf_fs_ds_index_entry *index_entry, - bt_self_message_iterator *self_msg_iter, bt_logging_level log_level) + struct ctf_fs_ds_index_entry *index_entry) { - enum ctf_msg_iter_medium_status status; - BT_ASSERT(data); BT_ASSERT(index_entry); /* Check if that file is already the one mapped. */ - if (!data->file || strcmp(index_entry->path, data->file->file->path->str) != 0) { - /* Destroy the previously used file. */ - ctf_fs_ds_file_destroy(data->file); - + if (!data->file || data->file->file->path != index_entry->path) { /* Create the new file. */ data->file = ctf_fs_ds_file_create(data->ds_file_group->ctf_fs_trace, data->ds_file_group->stream, - index_entry->path, log_level); + index_entry->path, data->logger); if (!data->file) { - BT_MSG_ITER_LOGE_APPEND_CAUSE(self_msg_iter, "failed to create ctf_fs_ds_file."); - status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; - goto end; + BT_CPPLOGE_APPEND_CAUSE_SPEC(data->logger, "failed to create ctf_fs_ds_file."); + return CTF_MSG_ITER_MEDIUM_STATUS_ERROR; } } @@ -346,86 +304,50 @@ ctf_fs_ds_group_medops_set_file(struct ctf_fs_ds_group_medops_data *data, * Ensure the right portion of the file will be returned on the next * request_bytes call. */ - status = ds_file_mmap(data->file, index_entry->offset); - if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) { - goto end; - } - - status = CTF_MSG_ITER_MEDIUM_STATUS_OK; - -end: - return status; + return ds_file_mmap(data->file.get(), index_entry->offset.bytes()); } static enum ctf_msg_iter_medium_status medop_group_switch_packet(void *void_data) { struct ctf_fs_ds_group_medops_data *data = (struct ctf_fs_ds_group_medops_data *) void_data; - struct ctf_fs_ds_index_entry *index_entry; - enum ctf_msg_iter_medium_status status; /* If we have gone through all index entries, we are done. */ - if (data->next_index_entry_index >= data->ds_file_group->index->entries->len) { - status = CTF_MSG_ITER_MEDIUM_STATUS_EOF; - goto end; + if (data->next_index_entry_index >= data->ds_file_group->index.entries.size()) { + return CTF_MSG_ITER_MEDIUM_STATUS_EOF; } /* * Otherwise, look up the next index entry / packet and prepare it * for reading. */ - index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index( - data->ds_file_group->index->entries, data->next_index_entry_index); - - status = - ctf_fs_ds_group_medops_set_file(data, index_entry, data->self_msg_iter, data->log_level); + ctf_msg_iter_medium_status status = ctf_fs_ds_group_medops_set_file( + data, &data->ds_file_group->index.entries[data->next_index_entry_index]); if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) { - goto end; + return status; } data->next_index_entry_index++; - status = CTF_MSG_ITER_MEDIUM_STATUS_OK; -end: - return status; + return CTF_MSG_ITER_MEDIUM_STATUS_OK; } -void ctf_fs_ds_group_medops_data_destroy(struct ctf_fs_ds_group_medops_data *data) +void ctf_fs_ds_group_medops_data_deleter::operator()(ctf_fs_ds_group_medops_data *data) noexcept { - if (!data) { - goto end; - } - - ctf_fs_ds_file_destroy(data->file); - - g_free(data); - -end: - return; + delete data; } enum ctf_msg_iter_medium_status ctf_fs_ds_group_medops_data_create( struct ctf_fs_ds_file_group *ds_file_group, bt_self_message_iterator *self_msg_iter, - bt_logging_level log_level, struct ctf_fs_ds_group_medops_data **out) + const bt2c::Logger& parentLogger, ctf_fs_ds_group_medops_data_up& out) { - struct ctf_fs_ds_group_medops_data *data; - enum ctf_msg_iter_medium_status status; - BT_ASSERT(self_msg_iter); BT_ASSERT(ds_file_group); - BT_ASSERT(ds_file_group->index); - BT_ASSERT(ds_file_group->index->entries->len > 0); - - data = g_new0(struct ctf_fs_ds_group_medops_data, 1); - if (!data) { - BT_MSG_ITER_LOGE_APPEND_CAUSE(self_msg_iter, - "Failed to allocate a struct ctf_fs_ds_group_medops_data"); - status = CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR; - goto error; - } + BT_ASSERT(!ds_file_group->index.entries.empty()); + + out.reset(new ctf_fs_ds_group_medops_data {parentLogger}); - data->ds_file_group = ds_file_group; - data->self_msg_iter = self_msg_iter; - data->log_level = log_level; + out->ds_file_group = ds_file_group; + out->self_msg_iter = self_msg_iter; /* * No need to prepare the first file. ctf_msg_iter will call @@ -433,15 +355,7 @@ enum ctf_msg_iter_medium_status ctf_fs_ds_group_medops_data_create( * done then. */ - *out = data; - status = CTF_MSG_ITER_MEDIUM_STATUS_OK; - goto end; - -error: - ctf_fs_ds_group_medops_data_destroy(data); - -end: - return status; + return CTF_MSG_ITER_MEDIUM_STATUS_OK; } void ctf_fs_ds_group_medops_data_reset(struct ctf_fs_ds_group_medops_data *data) @@ -462,23 +376,6 @@ struct ctf_msg_iter_medium_ops ctf_fs_ds_group_medops = { .borrow_stream = medop_group_borrow_stream, }; -static struct ctf_fs_ds_index_entry *ctf_fs_ds_index_entry_create(bt_self_component *self_comp, - bt_logging_level log_level) -{ - struct ctf_fs_ds_index_entry *entry; - - entry = g_new0(struct ctf_fs_ds_index_entry, 1); - if (!entry) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate a ctf_fs_ds_index_entry."); - goto end; - } - - entry->packet_seq_num = UINT64_MAX; - -end: - return entry; -} - static int convert_cycles_to_ns(struct ctf_clock_class *clock_class, uint64_t cycles, int64_t *ns) { return bt_util_clock_cycles_to_ns_from_origin(cycles, clock_class->frequency, @@ -486,70 +383,49 @@ static int convert_cycles_to_ns(struct ctf_clock_class *clock_class, uint64_t cy clock_class->offset_cycles, ns); } -static struct ctf_fs_ds_index *build_index_from_idx_file(struct ctf_fs_ds_file *ds_file, - struct ctf_fs_ds_file_info *file_info, - struct ctf_msg_iter *msg_iter) +static bt2s::optional +build_index_from_idx_file(struct ctf_fs_ds_file *ds_file, struct ctf_fs_ds_file_info *file_info, + struct ctf_msg_iter *msg_iter) { - int ret; - gchar *directory = NULL; - gchar *basename = NULL; - GString *index_basename = NULL; - gchar *index_file_path = NULL; - GMappedFile *mapped_file = NULL; - gsize filesize; - const char *mmap_begin = NULL, *file_pos = NULL; - const struct ctf_packet_index_file_hdr *header = NULL; - struct ctf_fs_ds_index *index = NULL; - struct ctf_fs_ds_index_entry *index_entry = NULL, *prev_index_entry = NULL; - uint64_t total_packets_size = 0; - size_t file_index_entry_size; - size_t file_entry_count; - size_t i; - struct ctf_stream_class *sc; - struct ctf_msg_iter_packet_properties props; - uint32_t version_major, version_minor; - bt_self_component *self_comp = ds_file->self_comp; - bt_logging_level log_level = ds_file->log_level; - - BT_COMP_LOGI("Building index from .idx file of stream file %s", ds_file->file->path->str); - ret = ctf_msg_iter_get_packet_properties(msg_iter, &props); + BT_CPPLOGI_SPEC(ds_file->logger, "Building index from .idx file of stream file {}", + ds_file->file->path); + ctf_msg_iter_packet_properties props; + int ret = ctf_msg_iter_get_packet_properties(msg_iter, &props); if (ret) { - BT_COMP_LOGI_STR("Cannot read first packet's header and context fields."); - goto error; + BT_CPPLOGI_SPEC(ds_file->logger, "Cannot read first packet's header and context fields."); + return bt2s::nullopt; } - sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props.stream_class_id); + ctf_stream_class *sc = + ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props.stream_class_id); BT_ASSERT(sc); if (!sc->default_clock_class) { - BT_COMP_LOGI_STR("Cannot find stream class's default clock class."); - goto error; + BT_CPPLOGI_SPEC(ds_file->logger, "Cannot find stream class's default clock class."); + return bt2s::nullopt; } /* Look for index file in relative path index/name.idx. */ - basename = g_path_get_basename(ds_file->file->path->str); + bt2c::GCharUP basename {g_path_get_basename(ds_file->file->path.c_str())}; if (!basename) { - BT_COMP_LOGE("Cannot get the basename of datastream file %s", ds_file->file->path->str); - goto error; + BT_CPPLOGE_SPEC(ds_file->logger, "Cannot get the basename of datastream file {}", + ds_file->file->path); + return bt2s::nullopt; } - directory = g_path_get_dirname(ds_file->file->path->str); + bt2c::GCharUP directory {g_path_get_dirname(ds_file->file->path.c_str())}; if (!directory) { - BT_COMP_LOGE("Cannot get dirname of datastream file %s", ds_file->file->path->str); - goto error; + BT_CPPLOGE_SPEC(ds_file->logger, "Cannot get dirname of datastream file {}", + ds_file->file->path); + return bt2s::nullopt; } - index_basename = g_string_new(basename); - if (!index_basename) { - BT_COMP_LOGE_STR("Cannot allocate index file basename string"); - goto error; - } - - g_string_append(index_basename, ".idx"); - index_file_path = g_build_filename(directory, "index", index_basename->str, NULL); - mapped_file = g_mapped_file_new(index_file_path, FALSE, NULL); + std::string index_basename = fmt::format("{}.idx", basename.get()); + bt2c::GCharUP index_file_path { + g_build_filename(directory.get(), "index", index_basename.c_str(), NULL)}; + bt2c::GMappedFileUP mapped_file {g_mapped_file_new(index_file_path.get(), FALSE, NULL)}; if (!mapped_file) { - BT_COMP_LOGD("Cannot create new mapped file %s", index_file_path); - goto error; + BT_CPPLOGD_SPEC(ds_file->logger, "Cannot create new mapped file {}", index_file_path.get()); + return bt2s::nullopt; } /* @@ -557,406 +433,306 @@ static struct ctf_fs_ds_index *build_index_from_idx_file(struct ctf_fs_ds_file * * Traces with such large indexes have never been seen in the wild, * but this would need to be adjusted to support them. */ - filesize = g_mapped_file_get_length(mapped_file); - if (filesize < sizeof(*header)) { - BT_COMP_LOGW("Invalid LTTng trace index file: " - "file size (%zu bytes) < header size (%zu bytes)", - filesize, sizeof(*header)); - goto error; + gsize filesize = g_mapped_file_get_length(mapped_file.get()); + if (filesize < sizeof(ctf_packet_index_file_hdr)) { + BT_CPPLOGW_SPEC(ds_file->logger, + "Invalid LTTng trace index file: " + "file size ({} bytes) < header size ({} bytes)", + filesize, sizeof(ctf_packet_index_file_hdr)); + return bt2s::nullopt; } - mmap_begin = g_mapped_file_get_contents(mapped_file); - header = (struct ctf_packet_index_file_hdr *) mmap_begin; + const char *mmap_begin = g_mapped_file_get_contents(mapped_file.get()); + const ctf_packet_index_file_hdr *header = (const ctf_packet_index_file_hdr *) mmap_begin; - file_pos = g_mapped_file_get_contents(mapped_file) + sizeof(*header); + const char *file_pos = g_mapped_file_get_contents(mapped_file.get()) + sizeof(*header); if (be32toh(header->magic) != CTF_INDEX_MAGIC) { - BT_COMP_LOGW_STR("Invalid LTTng trace index: \"magic\" field validation failed"); - goto error; + BT_CPPLOGW_SPEC(ds_file->logger, + "Invalid LTTng trace index: \"magic\" field validation failed"); + return bt2s::nullopt; } - version_major = be32toh(header->index_major); - version_minor = be32toh(header->index_minor); + uint32_t version_major = be32toh(header->index_major); + uint32_t version_minor = be32toh(header->index_minor); if (version_major != 1) { - BT_COMP_LOGW("Unknown LTTng trace index version: " - "major=%" PRIu32 ", minor=%" PRIu32, - version_major, version_minor); - goto error; + BT_CPPLOGW_SPEC(ds_file->logger, "Unknown LTTng trace index version: major={}, minor={}", + version_major, version_minor); + return bt2s::nullopt; } - file_index_entry_size = be32toh(header->packet_index_len); + size_t file_index_entry_size = be32toh(header->packet_index_len); if (file_index_entry_size < CTF_INDEX_1_0_SIZE) { - BT_COMP_LOGW( + BT_CPPLOGW_SPEC( + ds_file->logger, "Invalid `packet_index_len` in LTTng trace index file (`packet_index_len` < CTF index 1.0 index entry size): " - "packet_index_len=%zu, CTF_INDEX_1_0_SIZE=%zu", + "packet_index_len={}, CTF_INDEX_1_0_SIZE={}", file_index_entry_size, CTF_INDEX_1_0_SIZE); - goto error; + return bt2s::nullopt; } - file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size; + size_t file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size; if ((filesize - sizeof(*header)) % file_index_entry_size) { - BT_COMP_LOGW("Invalid LTTng trace index: the index's size after the header " - "(%zu bytes) is not a multiple of the index entry size " - "(%zu bytes)", - (filesize - sizeof(*header)), sizeof(*header)); - goto error; + BT_CPPLOGW_SPEC(ds_file->logger, + "Invalid LTTng trace index: the index's size after the header " + "({} bytes) is not a multiple of the index entry size " + "({} bytes)", + (filesize - sizeof(*header)), sizeof(*header)); + return bt2s::nullopt; } - index = ctf_fs_ds_index_create(ds_file->log_level, ds_file->self_comp); - if (!index) { - goto error; - } + ctf_fs_ds_index index; + ctf_fs_ds_index_entry *prev_index_entry = nullptr; + auto totalPacketsSize = bt2c::DataLen::fromBytes(0); - for (i = 0; i < file_entry_count; i++) { + for (size_t i = 0; i < file_entry_count; i++) { struct ctf_packet_index *file_index = (struct ctf_packet_index *) file_pos; - uint64_t packet_size = be64toh(file_index->packet_size); - - if (packet_size % CHAR_BIT) { - BT_COMP_LOGW("Invalid packet size encountered in LTTng trace index file"); - goto error; - } + const auto packetSize = bt2c::DataLen::fromBits(be64toh(file_index->packet_size)); - index_entry = ctf_fs_ds_index_entry_create(ds_file->self_comp, ds_file->log_level); - if (!index_entry) { - BT_COMP_LOGE_APPEND_CAUSE(ds_file->self_comp, - "Failed to create a ctf_fs_ds_index_entry."); - goto error; + if (packetSize.hasExtraBits()) { + BT_CPPLOGW_SPEC(ds_file->logger, + "Invalid packet size encountered in LTTng trace index file"); + return bt2s::nullopt; } - /* Set path to stream file. */ - index_entry->path = file_info->path->str; - - /* Convert size in bits to bytes. */ - packet_size /= CHAR_BIT; - index_entry->packet_size = packet_size; + const auto offset = bt2c::DataLen::fromBytes(be64toh(file_index->offset)); - index_entry->offset = be64toh(file_index->offset); - if (i != 0 && index_entry->offset < prev_index_entry->offset) { - BT_COMP_LOGW( + if (i != 0 && offset < prev_index_entry->offset) { + BT_CPPLOGW_SPEC( + ds_file->logger, "Invalid, non-monotonic, packet offset encountered in LTTng trace index file: " - "previous offset=%" PRIu64 ", current offset=%" PRIu64, - prev_index_entry->offset, index_entry->offset); - goto error; + "previous offset={} bytes, current offset={} bytes", + prev_index_entry->offset.bytes(), offset.bytes()); + return bt2s::nullopt; } - index_entry->timestamp_begin = be64toh(file_index->timestamp_begin); - index_entry->timestamp_end = be64toh(file_index->timestamp_end); - if (index_entry->timestamp_end < index_entry->timestamp_begin) { - BT_COMP_LOGW( + ctf_fs_ds_index_entry index_entry {file_info->path.c_str(), offset, packetSize}; + index_entry.timestamp_begin = be64toh(file_index->timestamp_begin); + index_entry.timestamp_end = be64toh(file_index->timestamp_end); + if (index_entry.timestamp_end < index_entry.timestamp_begin) { + BT_CPPLOGW_SPEC( + ds_file->logger, "Invalid packet time bounds encountered in LTTng trace index file (begin > end): " - "timestamp_begin=%" PRIu64 "timestamp_end=%" PRIu64, - index_entry->timestamp_begin, index_entry->timestamp_end); - goto error; + "timestamp_begin={}, timestamp_end={}", + index_entry.timestamp_begin, index_entry.timestamp_end); + return bt2s::nullopt; } /* Convert the packet's bound to nanoseconds since Epoch. */ - ret = convert_cycles_to_ns(sc->default_clock_class, index_entry->timestamp_begin, - &index_entry->timestamp_begin_ns); + ret = convert_cycles_to_ns(sc->default_clock_class, index_entry.timestamp_begin, + &index_entry.timestamp_begin_ns); if (ret) { - BT_COMP_LOGI_STR( + BT_CPPLOGI_SPEC( + ds_file->logger, "Failed to convert raw timestamp to nanoseconds since Epoch during index parsing"); - goto error; + return bt2s::nullopt; } - ret = convert_cycles_to_ns(sc->default_clock_class, index_entry->timestamp_end, - &index_entry->timestamp_end_ns); + ret = convert_cycles_to_ns(sc->default_clock_class, index_entry.timestamp_end, + &index_entry.timestamp_end_ns); if (ret) { - BT_COMP_LOGI_STR( + BT_CPPLOGI_SPEC( + ds_file->logger, "Failed to convert raw timestamp to nanoseconds since Epoch during LTTng trace index parsing"); - goto error; + return bt2s::nullopt; } if (version_minor >= 1) { - index_entry->packet_seq_num = be64toh(file_index->packet_seq_num); + index_entry.packet_seq_num = be64toh(file_index->packet_seq_num); } - total_packets_size += packet_size; + totalPacketsSize += packetSize; file_pos += file_index_entry_size; - prev_index_entry = index_entry; + index.entries.emplace_back(index_entry); - /* Give ownership of `index_entry` to `index->entries`. */ - g_ptr_array_add(index->entries, index_entry); - index_entry = NULL; + prev_index_entry = &index.entries.back(); } /* Validate that the index addresses the complete stream. */ - if (ds_file->file->size != total_packets_size) { - BT_COMP_LOGW("Invalid LTTng trace index file; indexed size != stream file size: " - "file-size=%" PRIu64 ", total-packets-size=%" PRIu64, - ds_file->file->size, total_packets_size); - goto error; - } -end: - g_free(directory); - g_free(basename); - g_free(index_file_path); - if (index_basename) { - g_string_free(index_basename, TRUE); - } - if (mapped_file) { - g_mapped_file_unref(mapped_file); + if (ds_file->file->size != totalPacketsSize.bytes()) { + BT_CPPLOGW_SPEC(ds_file->logger, + "Invalid LTTng trace index file; indexed size != stream file size: " + "file-size={} bytes, total-packets-size={} bytes", + ds_file->file->size, totalPacketsSize.bytes()); + return bt2s::nullopt; } + return index; -error: - ctf_fs_ds_index_destroy(index); - g_free(index_entry); - index = NULL; - goto end; } -static int init_index_entry(struct ctf_fs_ds_index_entry *entry, struct ctf_fs_ds_file *ds_file, - struct ctf_msg_iter_packet_properties *props, off_t packet_size, - off_t packet_offset) +static int init_index_entry(ctf_fs_ds_index_entry& entry, struct ctf_fs_ds_file *ds_file, + struct ctf_msg_iter_packet_properties *props) { - int ret = 0; - struct ctf_stream_class *sc; - bt_self_component *self_comp = ds_file->self_comp; - bt_logging_level log_level = ds_file->log_level; - - sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props->stream_class_id); + ctf_stream_class *sc = + ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props->stream_class_id); BT_ASSERT(sc); - BT_ASSERT(packet_offset >= 0); - entry->offset = packet_offset; - BT_ASSERT(packet_size >= 0); - entry->packet_size = packet_size; if (props->snapshots.beginning_clock != UINT64_C(-1)) { - entry->timestamp_begin = props->snapshots.beginning_clock; + entry.timestamp_begin = props->snapshots.beginning_clock; /* Convert the packet's bound to nanoseconds since Epoch. */ - ret = convert_cycles_to_ns(sc->default_clock_class, props->snapshots.beginning_clock, - &entry->timestamp_begin_ns); + int ret = convert_cycles_to_ns(sc->default_clock_class, props->snapshots.beginning_clock, + &entry.timestamp_begin_ns); if (ret) { - BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch."); - goto end; + BT_CPPLOGI_SPEC(ds_file->logger, + "Failed to convert raw timestamp to nanoseconds since Epoch."); + return ret; } } else { - entry->timestamp_begin = UINT64_C(-1); - entry->timestamp_begin_ns = UINT64_C(-1); + entry.timestamp_begin = UINT64_C(-1); + entry.timestamp_begin_ns = UINT64_C(-1); } if (props->snapshots.end_clock != UINT64_C(-1)) { - entry->timestamp_end = props->snapshots.end_clock; + entry.timestamp_end = props->snapshots.end_clock; /* Convert the packet's bound to nanoseconds since Epoch. */ - ret = convert_cycles_to_ns(sc->default_clock_class, props->snapshots.end_clock, - &entry->timestamp_end_ns); + int ret = convert_cycles_to_ns(sc->default_clock_class, props->snapshots.end_clock, + &entry.timestamp_end_ns); if (ret) { - BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch."); - goto end; + BT_CPPLOGI_SPEC(ds_file->logger, + "Failed to convert raw timestamp to nanoseconds since Epoch."); + return ret; } } else { - entry->timestamp_end = UINT64_C(-1); - entry->timestamp_end_ns = UINT64_C(-1); + entry.timestamp_end = UINT64_C(-1); + entry.timestamp_end_ns = UINT64_C(-1); } -end: - return ret; + return 0; } -static struct ctf_fs_ds_index *build_index_from_stream_file(struct ctf_fs_ds_file *ds_file, - struct ctf_fs_ds_file_info *file_info, - struct ctf_msg_iter *msg_iter) +static bt2s::optional +build_index_from_stream_file(struct ctf_fs_ds_file *ds_file, struct ctf_fs_ds_file_info *file_info, + struct ctf_msg_iter *msg_iter) { - int ret; - struct ctf_fs_ds_index *index = NULL; - enum ctf_msg_iter_status iter_status = CTF_MSG_ITER_STATUS_OK; - off_t current_packet_offset_bytes = 0; - bt_self_component *self_comp = ds_file->self_comp; - bt_logging_level log_level = ds_file->log_level; - - BT_COMP_LOGI("Indexing stream file %s", ds_file->file->path->str); - - index = ctf_fs_ds_index_create(ds_file->log_level, ds_file->self_comp); - if (!index) { - goto error; - } + BT_CPPLOGI_SPEC(ds_file->logger, "Indexing stream file {}", ds_file->file->path); + + ctf_fs_ds_index index; + auto currentPacketOffset = bt2c::DataLen::fromBytes(0); while (true) { - off_t current_packet_size_bytes; - struct ctf_fs_ds_index_entry *index_entry; struct ctf_msg_iter_packet_properties props; - if (current_packet_offset_bytes < 0) { - BT_COMP_LOGE_STR("Cannot get the current packet's offset."); - goto error; - } else if (current_packet_offset_bytes > ds_file->file->size) { - BT_COMP_LOGE_STR("Unexpected current packet's offset (larger than file)."); - goto error; - } else if (current_packet_offset_bytes == ds_file->file->size) { + if (currentPacketOffset.bytes() > ds_file->file->size) { + BT_CPPLOGE_SPEC(ds_file->logger, + "Unexpected current packet's offset (larger than file)."); + return bt2s::nullopt; + } else if (currentPacketOffset.bytes() == ds_file->file->size) { /* No more data */ break; } - iter_status = ctf_msg_iter_seek(msg_iter, current_packet_offset_bytes); + ctf_msg_iter_status iter_status = ctf_msg_iter_seek(msg_iter, currentPacketOffset.bytes()); if (iter_status != CTF_MSG_ITER_STATUS_OK) { - goto error; + return bt2s::nullopt; } iter_status = ctf_msg_iter_get_packet_properties(msg_iter, &props); if (iter_status != CTF_MSG_ITER_STATUS_OK) { - goto error; + return bt2s::nullopt; } - if (props.exp_packet_total_size >= 0) { - current_packet_size_bytes = (uint64_t) props.exp_packet_total_size / 8; - } else { - current_packet_size_bytes = ds_file->file->size; - } - - if (current_packet_offset_bytes + current_packet_size_bytes > ds_file->file->size) { - BT_COMP_LOGW("Invalid packet size reported in file: stream=\"%s\", " - "packet-offset=%jd, packet-size-bytes=%jd, " - "file-size=%jd", - ds_file->file->path->str, (intmax_t) current_packet_offset_bytes, - (intmax_t) current_packet_size_bytes, (intmax_t) ds_file->file->size); - goto error; - } - - index_entry = ctf_fs_ds_index_entry_create(ds_file->self_comp, ds_file->log_level); - if (!index_entry) { - BT_COMP_LOGE_APPEND_CAUSE(ds_file->self_comp, - "Failed to create a ctf_fs_ds_index_entry."); - goto error; + /* + * Get the current packet size from the packet header, if set. Else, + * assume there is a single packet in the file, so take the file size + * as the packet size. + */ + const auto currentPacketSize = props.exp_packet_total_size >= 0 ? + bt2c::DataLen::fromBits(props.exp_packet_total_size) : + bt2c::DataLen::fromBytes(ds_file->file->size); + + if ((currentPacketOffset + currentPacketSize).bytes() > ds_file->file->size) { + BT_CPPLOGW_SPEC(ds_file->logger, + "Invalid packet size reported in file: stream=\"{}\", " + "packet-offset-bytes={}, packet-size-bytes={}, " + "file-size-bytes={}", + ds_file->file->path, currentPacketOffset.bytes(), + currentPacketSize.bytes(), ds_file->file->size); + return bt2s::nullopt; } - /* Set path to stream file. */ - index_entry->path = file_info->path->str; + ctf_fs_ds_index_entry index_entry {file_info->path, currentPacketOffset, currentPacketSize}; - ret = init_index_entry(index_entry, ds_file, &props, current_packet_size_bytes, - current_packet_offset_bytes); + int ret = init_index_entry(index_entry, ds_file, &props); if (ret) { - g_free(index_entry); - goto error; + return bt2s::nullopt; } - g_ptr_array_add(index->entries, index_entry); + index.entries.emplace_back(index_entry); - current_packet_offset_bytes += current_packet_size_bytes; - BT_COMP_LOGD("Seeking to next packet: current-packet-offset=%jd, " - "next-packet-offset=%jd", - (intmax_t) (current_packet_offset_bytes - current_packet_size_bytes), - (intmax_t) current_packet_offset_bytes); + currentPacketOffset += currentPacketSize; + BT_CPPLOGD_SPEC(ds_file->logger, + "Seeking to next packet: current-packet-offset-bytes={}, " + "next-packet-offset-bytes={}", + (currentPacketOffset - currentPacketSize).bytes(), + currentPacketOffset.bytes()); } -end: return index; - -error: - ctf_fs_ds_index_destroy(index); - index = NULL; - goto end; } -struct ctf_fs_ds_file *ctf_fs_ds_file_create(struct ctf_fs_trace *ctf_fs_trace, bt_stream *stream, - const char *path, bt_logging_level log_level) +ctf_fs_ds_file::UP ctf_fs_ds_file_create(struct ctf_fs_trace *ctf_fs_trace, + bt2::Stream::Shared stream, const char *path, + const bt2c::Logger& parentLogger) { - int ret; - const size_t offset_align = bt_mmap_get_offset_align_size(log_level); - struct ctf_fs_ds_file *ds_file = g_new0(struct ctf_fs_ds_file, 1); - - if (!ds_file) { - goto error; - } - - ds_file->log_level = log_level; - ds_file->self_comp = ctf_fs_trace->self_comp; - ds_file->file = ctf_fs_file_create(log_level, ds_file->self_comp); - if (!ds_file->file) { - goto error; - } + auto ds_file = bt2s::make_unique(parentLogger); - ds_file->stream = stream; - bt_stream_get_ref(ds_file->stream); - ds_file->metadata = ctf_fs_trace->metadata; - g_string_assign(ds_file->file->path, path); - ret = ctf_fs_file_open(ds_file->file, "rb"); + ds_file->file = bt2s::make_unique(parentLogger); + ds_file->stream = std::move(stream); + ds_file->metadata = ctf_fs_trace->metadata.get(); + ds_file->file->path = path; + int ret = ctf_fs_file_open(ds_file->file.get(), "rb"); if (ret) { - goto error; + return nullptr; } + const size_t offset_align = + bt_mmap_get_offset_align_size(static_cast(ds_file->logger.level())); ds_file->mmap_max_len = offset_align * 2048; - goto end; - -error: - /* Do not touch "borrowed" file. */ - ctf_fs_ds_file_destroy(ds_file); - ds_file = NULL; - -end: return ds_file; } -struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(struct ctf_fs_ds_file *ds_file, - struct ctf_fs_ds_file_info *file_info, - struct ctf_msg_iter *msg_iter) +bt2s::optional ctf_fs_ds_file_build_index(struct ctf_fs_ds_file *ds_file, + struct ctf_fs_ds_file_info *file_info, + struct ctf_msg_iter *msg_iter) { - struct ctf_fs_ds_index *index; - bt_self_component *self_comp = ds_file->self_comp; - bt_logging_level log_level = ds_file->log_level; - - index = build_index_from_idx_file(ds_file, file_info, msg_iter); + auto index = build_index_from_idx_file(ds_file, file_info, msg_iter); if (index) { - goto end; + return index; } - BT_COMP_LOGI("Failed to build index from .index file; " - "falling back to stream indexing."); - index = build_index_from_stream_file(ds_file, file_info, msg_iter); -end: - return index; + BT_CPPLOGI_SPEC(ds_file->logger, "Failed to build index from .index file; " + "falling back to stream indexing."); + return build_index_from_stream_file(ds_file, file_info, msg_iter); } -struct ctf_fs_ds_index *ctf_fs_ds_index_create(bt_logging_level log_level, - bt_self_component *self_comp) +ctf_fs_ds_file::~ctf_fs_ds_file() { - struct ctf_fs_ds_index *index = g_new0(struct ctf_fs_ds_index, 1); - - if (!index) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, "Failed to allocate index"); - goto error; - } - - index->entries = g_ptr_array_new_with_free_func((GDestroyNotify) g_free); - if (!index->entries) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, - "Failed to allocate index entries."); - goto error; - } - - goto end; - -error: - ctf_fs_ds_index_destroy(index); - index = NULL; -end: - return index; + (void) ds_file_munmap(this); } -void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *ds_file) +ctf_fs_ds_file_info::UP ctf_fs_ds_file_info_create(const char *path, int64_t begin_ns) { - if (!ds_file) { - return; - } - - bt_stream_put_ref(ds_file->stream); - (void) ds_file_munmap(ds_file); - - if (ds_file->file) { - ctf_fs_file_destroy(ds_file->file); - } + ctf_fs_ds_file_info::UP ds_file_info = bt2s::make_unique(); - g_free(ds_file); + ds_file_info->path = path; + ds_file_info->begin_ns = begin_ns; + return ds_file_info; } -void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index) +void ctf_fs_ds_file_group::insert_ds_file_info_sorted(ctf_fs_ds_file_info::UP ds_file_info) { - if (!index) { - return; - } + /* Find the spot where to insert this ds_file_info. */ + auto it = this->ds_file_infos.begin(); + + for (; it != this->ds_file_infos.end(); ++it) { + const ctf_fs_ds_file_info& other_ds_file_info = **it; - if (index->entries) { - g_ptr_array_free(index->entries, TRUE); + if (ds_file_info->begin_ns < other_ds_file_info.begin_ns) { + break; + } } - g_free(index); + + this->ds_file_infos.insert(it, std::move(ds_file_info)); }