src.ctf.fs: remove ctf_msg_iter_seek_whence parameter to medium ops seek
[babeltrace.git] / src / plugins / ctf / fs-src / data-stream-file.c
CommitLineData
e98a2d6e 1/*
94cf822e 2 * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
fc9a526c 3 * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
e98a2d6e
PP
4 * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
5 *
e98a2d6e
PP
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
2e42d046
SM
25#define BT_COMP_LOG_SELF_COMP (self_comp)
26#define BT_LOG_OUTPUT_LEVEL (log_level)
98903a3e 27#define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/DS"
d9c39b0a 28#include "logging/comp-logging.h"
98903a3e 29
0fbb9a9f 30#include <stdlib.h>
e98a2d6e
PP
31#include <stdio.h>
32#include <stdint.h>
33#include <stdlib.h>
e98a2d6e
PP
34#include <glib.h>
35#include <inttypes.h>
578e048b
MJ
36#include "compat/mman.h"
37#include "compat/endian.h"
3fadfbc0 38#include <babeltrace2/babeltrace.h>
578e048b 39#include "common/common.h"
78586d8a
JG
40#include "file.h"
41#include "metadata.h"
d6e69534 42#include "../common/msg-iter/msg-iter.h"
578e048b 43#include "common/assert.h"
94cf822e 44#include "data-stream-file.h"
e9383dfd 45#include <string.h>
e98a2d6e 46
4f1f88a6 47static inline
94cf822e 48size_t remaining_mmap_bytes(struct ctf_fs_ds_file *ds_file)
e98a2d6e 49{
e9bfbfe0
SM
50 BT_ASSERT_DBG(ds_file->mmap_len >= ds_file->request_offset_in_mapping);
51 return ds_file->mmap_len - ds_file->request_offset_in_mapping;
e98a2d6e
PP
52}
53
5b29e799 54static
887a9995
SM
55enum ctf_msg_iter_medium_status ds_file_munmap(
56 struct ctf_fs_ds_file *ds_file)
e98a2d6e 57{
887a9995 58 enum ctf_msg_iter_medium_status status;
2e42d046
SM
59 bt_self_component *self_comp = ds_file->self_comp;
60 bt_logging_level log_level = ds_file->log_level;
e98a2d6e 61
9f5571db
SM
62 BT_ASSERT(ds_file);
63
64 if (!ds_file->mmap_addr) {
887a9995 65 status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
94cf822e
PP
66 goto end;
67 }
68
04394229 69 if (bt_munmap(ds_file->mmap_addr, ds_file->mmap_len)) {
4c65a157 70 BT_COMP_LOGE_ERRNO("Cannot memory-unmap file",
cd232764 71 ": address=%p, size=%zu, file_path=\"%s\", file=%p",
94cf822e 72 ds_file->mmap_addr, ds_file->mmap_len,
9e0c8dbb 73 ds_file->file ? ds_file->file->path->str : "NULL",
cd232764 74 ds_file->file ? ds_file->file->fp : NULL);
887a9995 75 status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
fc9a526c 76 goto end;
e98a2d6e 77 }
94cf822e
PP
78
79 ds_file->mmap_addr = NULL;
80
887a9995 81 status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
fc9a526c 82end:
887a9995 83 return status;
e98a2d6e
PP
84}
85
5b29e799 86static
18a1979b 87enum ctf_msg_iter_medium_status ds_file_mmap_next(
94cf822e 88 struct ctf_fs_ds_file *ds_file)
e98a2d6e 89{
887a9995 90 enum ctf_msg_iter_medium_status status;
2e42d046
SM
91 bt_self_component *self_comp = ds_file->self_comp;
92 bt_logging_level log_level = ds_file->log_level;
e98a2d6e
PP
93
94 /* Unmap old region */
94cf822e 95 if (ds_file->mmap_addr) {
887a9995
SM
96 status = ds_file_munmap(ds_file);
97 if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
98 goto end;
e98a2d6e
PP
99 }
100
2f5a009b 101 /*
2c701ca6 102 * mmap_len is guaranteed to be page-aligned except on the
2f5a009b
JG
103 * last mapping where it may not be possible (since the file's
104 * size itself may not be a page multiple).
105 */
e9bfbfe0
SM
106 ds_file->mmap_offset_in_file += ds_file->mmap_len;
107 ds_file->request_offset_in_mapping = 0;
e98a2d6e
PP
108 }
109
e9bfbfe0 110 ds_file->mmap_len = MIN(ds_file->file->size - ds_file->mmap_offset_in_file,
94cf822e 111 ds_file->mmap_max_len);
2c701ca6 112 if (ds_file->mmap_len == 0) {
887a9995 113 status = CTF_MSG_ITER_MEDIUM_STATUS_EOF;
e0f6a64a
JG
114 goto end;
115 }
e98a2d6e 116 /* Map new region */
f6ccaed9 117 BT_ASSERT(ds_file->mmap_len);
04394229 118 ds_file->mmap_addr = bt_mmap((void *) 0, ds_file->mmap_len,
94cf822e 119 PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp),
e9bfbfe0 120 ds_file->mmap_offset_in_file, ds_file->log_level);
94cf822e 121 if (ds_file->mmap_addr == MAP_FAILED) {
4c65a157 122 BT_COMP_LOGE("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %jd: %s",
94cf822e 123 ds_file->mmap_len, ds_file->file->path->str,
e9bfbfe0 124 ds_file->file->fp, (intmax_t) ds_file->mmap_offset_in_file,
78586d8a 125 strerror(errno));
887a9995
SM
126 status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
127 goto end;
e98a2d6e
PP
128 }
129
887a9995 130 status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
e98a2d6e 131end:
887a9995 132 return status;
e98a2d6e
PP
133}
134
5b29e799 135static
18a1979b 136enum ctf_msg_iter_medium_status medop_request_bytes(
e98a2d6e
PP
137 size_t request_sz, uint8_t **buffer_addr,
138 size_t *buffer_sz, void *data)
139{
18a1979b
SM
140 enum ctf_msg_iter_medium_status status =
141 CTF_MSG_ITER_MEDIUM_STATUS_OK;
94cf822e 142 struct ctf_fs_ds_file *ds_file = data;
2e42d046
SM
143 bt_self_component *self_comp = ds_file->self_comp;
144 bt_logging_level log_level = ds_file->log_level;
e98a2d6e
PP
145
146 if (request_sz == 0) {
147 goto end;
148 }
149
de2abea4
FD
150 /*
151 * Check if we have at least one memory-mapped byte left. If we don't,
152 * mmap the next file.
153 */
94cf822e 154 if (remaining_mmap_bytes(ds_file) == 0) {
e98a2d6e 155 /* Are we at the end of the file? */
e9bfbfe0 156 if (ds_file->mmap_offset_in_file >= ds_file->file->size) {
4c65a157 157 BT_COMP_LOGD("Reached end of file \"%s\" (%p)",
94cf822e 158 ds_file->file->path->str, ds_file->file->fp);
18a1979b 159 status = CTF_MSG_ITER_MEDIUM_STATUS_EOF;
e98a2d6e
PP
160 goto end;
161 }
162
94cf822e 163 status = ds_file_mmap_next(ds_file);
e0f6a64a 164 switch (status) {
18a1979b 165 case CTF_MSG_ITER_MEDIUM_STATUS_OK:
e0f6a64a 166 break;
18a1979b 167 case CTF_MSG_ITER_MEDIUM_STATUS_EOF:
e0f6a64a
JG
168 goto end;
169 default:
4c65a157 170 BT_COMP_LOGE("Cannot memory-map next region of file \"%s\" (%p)",
94cf822e
PP
171 ds_file->file->path->str,
172 ds_file->file->fp);
e98a2d6e
PP
173 goto error;
174 }
175 }
176
94cf822e 177 *buffer_sz = MIN(remaining_mmap_bytes(ds_file), request_sz);
de2abea4 178 BT_ASSERT(ds_file->mmap_addr);
e9bfbfe0
SM
179 *buffer_addr = ((uint8_t *) ds_file->mmap_addr) + ds_file->request_offset_in_mapping;
180 ds_file->request_offset_in_mapping += *buffer_sz;
e98a2d6e
PP
181 goto end;
182
183error:
18a1979b 184 status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
e98a2d6e
PP
185
186end:
187 return status;
188}
189
5b29e799 190static
fc917f65 191bt_stream *medop_borrow_stream(bt_stream_class *stream_class, int64_t stream_id,
b92735af 192 void *data)
e98a2d6e 193{
94cf822e 194 struct ctf_fs_ds_file *ds_file = data;
b19ff26f
PP
195 bt_stream_class *ds_file_stream_class;
196 bt_stream *stream = NULL;
e5be10ef 197
40f4ba76 198 ds_file_stream_class = bt_stream_borrow_class(
e5be10ef 199 ds_file->stream);
94cf822e 200
94cf822e
PP
201 if (stream_class != ds_file_stream_class) {
202 /*
203 * Not supported: two packets described by two different
204 * stream classes within the same data stream file.
205 */
206 goto end;
e98a2d6e
PP
207 }
208
94cf822e
PP
209 stream = ds_file->stream;
210
211end:
212 return stream;
e98a2d6e
PP
213}
214
9e0c8dbb 215static
701a0903 216enum ctf_msg_iter_medium_status medop_seek(off_t offset, void *data)
9e0c8dbb 217{
887a9995 218 enum ctf_msg_iter_medium_status status;
9e0c8dbb 219 struct ctf_fs_ds_file *ds_file = data;
de2abea4 220 off_t offset_in_mapping, file_size = ds_file->file->size;
2e42d046
SM
221 bt_self_component *self_comp = ds_file->self_comp;
222 bt_logging_level log_level = ds_file->log_level;
9e0c8dbb 223
701a0903
SM
224 if (offset < 0 || offset > file_size) {
225 BT_COMP_LOGE("Invalid medium seek request: offset=%jd, file-size=%jd",
226 (intmax_t) offset, (intmax_t) file_size);
887a9995 227 status = CTF_MSG_ITER_MEDIUM_STATUS_INVAL;
9e0c8dbb
JG
228 goto end;
229 }
230
de2abea4
FD
231 /* If there is no current mapping, map the right file directly. */
232 if (!ds_file->mmap_addr) {
233 goto map_requested_offset;
234 }
235
9e0c8dbb
JG
236 /*
237 * Determine whether or not the destination is contained within the
238 * current mapping.
239 */
e9bfbfe0
SM
240 if (offset < ds_file->mmap_offset_in_file ||
241 offset >= ds_file->mmap_offset_in_file + ds_file->mmap_len) {
4c65a157 242 BT_COMP_LOGD("Medium seek request cannot be accomodated by the current "
63489ca2 243 "file mapping: offset=%jd, mmap-offset=%jd, "
e9bfbfe0 244 "mmap-len=%zu", (intmax_t) offset, (intmax_t) ds_file->mmap_offset_in_file,
9e0c8dbb 245 ds_file->mmap_len);
887a9995
SM
246 status = ds_file_munmap(ds_file);
247 if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
9e0c8dbb
JG
248 goto end;
249 }
de2abea4 250 goto map_requested_offset;
9e0c8dbb 251 } else {
e9bfbfe0 252 ds_file->request_offset_in_mapping = offset - ds_file->mmap_offset_in_file;
de2abea4
FD
253 goto test_end;
254 }
255
256map_requested_offset:
257 offset_in_mapping = offset %
3b16a19b 258 bt_mmap_get_offset_align_size(ds_file->log_level);
de2abea4 259
e9bfbfe0
SM
260 ds_file->mmap_offset_in_file = offset - offset_in_mapping;
261 ds_file->request_offset_in_mapping = offset_in_mapping;
887a9995
SM
262 status = ds_file_mmap_next(ds_file);
263 if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
de2abea4 264 goto end;
9e0c8dbb
JG
265 }
266
de2abea4 267test_end:
9e0c8dbb 268 ds_file->end_reached = (offset == file_size);
887a9995
SM
269
270 status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
9e0c8dbb 271end:
887a9995 272 return status;
9e0c8dbb
JG
273}
274
6de92955 275BT_HIDDEN
18a1979b 276struct ctf_msg_iter_medium_ops ctf_fs_ds_file_medops = {
e98a2d6e 277 .request_bytes = medop_request_bytes,
312c056a 278 .borrow_stream = medop_borrow_stream,
9e0c8dbb 279 .seek = medop_seek,
e98a2d6e 280};
6de92955 281
6834784d
SM
282static
283struct ctf_fs_ds_index_entry *ctf_fs_ds_index_entry_create(
284 bt_self_component *self_comp, bt_logging_level log_level)
285{
286 struct ctf_fs_ds_index_entry *entry;
287
288 entry = g_new0(struct ctf_fs_ds_index_entry, 1);
289 if (!entry) {
290 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate a ctf_fs_ds_index_entry.");
291 goto end;
292 }
293
294 entry->packet_seq_num = UINT64_MAX;
295
296end:
297 return entry;
298}
299
97ade20b 300static
0f2d58c9 301int convert_cycles_to_ns(struct ctf_clock_class *clock_class,
97ade20b 302 uint64_t cycles, int64_t *ns)
b6c3dcb2 303{
0f2d58c9
PP
304 return bt_util_clock_cycles_to_ns_from_origin(cycles,
305 clock_class->frequency, clock_class->offset_seconds,
306 clock_class->offset_cycles, ns);
97ade20b
JG
307}
308
309static
310struct ctf_fs_ds_index *build_index_from_idx_file(
bf012bde 311 struct ctf_fs_ds_file *ds_file,
6d54260a
SM
312 struct ctf_fs_ds_file_info *file_info,
313 struct ctf_msg_iter *msg_iter)
97ade20b
JG
314{
315 int ret;
b6c3dcb2
JG
316 gchar *directory = NULL;
317 gchar *basename = NULL;
318 GString *index_basename = NULL;
319 gchar *index_file_path = NULL;
320 GMappedFile *mapped_file = NULL;
321 gsize filesize;
97ade20b
JG
322 const char *mmap_begin = NULL, *file_pos = NULL;
323 const struct ctf_packet_index_file_hdr *header = NULL;
324 struct ctf_fs_ds_index *index = NULL;
de38c26a 325 struct ctf_fs_ds_index_entry *index_entry = NULL, *prev_index_entry = NULL;
b6c3dcb2
JG
326 uint64_t total_packets_size = 0;
327 size_t file_index_entry_size;
328 size_t file_entry_count;
329 size_t i;
44c440bc 330 struct ctf_stream_class *sc;
18a1979b 331 struct ctf_msg_iter_packet_properties props;
1984ac2b 332 uint32_t version_major, version_minor;
2e42d046
SM
333 bt_self_component *self_comp = ds_file->self_comp;
334 bt_logging_level log_level = ds_file->log_level;
97ade20b 335
4c65a157 336 BT_COMP_LOGI("Building index from .idx file of stream file %s",
97ade20b 337 ds_file->file->path->str);
6d54260a 338 ret = ctf_msg_iter_get_packet_properties(msg_iter, &props);
97ade20b 339 if (ret) {
4c65a157 340 BT_COMP_LOGI_STR("Cannot read first packet's header and context fields.");
44c440bc
PP
341 goto error;
342 }
343
44c440bc
PP
344 sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
345 props.stream_class_id);
346 BT_ASSERT(sc);
347 if (!sc->default_clock_class) {
4c65a157 348 BT_COMP_LOGI_STR("Cannot find stream class's default clock class.");
97ade20b
JG
349 goto error;
350 }
b6c3dcb2
JG
351
352 /* Look for index file in relative path index/name.idx. */
94cf822e 353 basename = g_path_get_basename(ds_file->file->path->str);
b6c3dcb2 354 if (!basename) {
4c65a157 355 BT_COMP_LOGE("Cannot get the basename of datastream file %s",
55314f2a 356 ds_file->file->path->str);
97ade20b 357 goto error;
b6c3dcb2
JG
358 }
359
94cf822e 360 directory = g_path_get_dirname(ds_file->file->path->str);
b6c3dcb2 361 if (!directory) {
4c65a157 362 BT_COMP_LOGE("Cannot get dirname of datastream file %s",
55314f2a 363 ds_file->file->path->str);
97ade20b 364 goto error;
b6c3dcb2
JG
365 }
366
367 index_basename = g_string_new(basename);
368 if (!index_basename) {
4c65a157 369 BT_COMP_LOGE_STR("Cannot allocate index file basename string");
97ade20b 370 goto error;
b6c3dcb2
JG
371 }
372
373 g_string_append(index_basename, ".idx");
374 index_file_path = g_build_filename(directory, "index",
375 index_basename->str, NULL);
376 mapped_file = g_mapped_file_new(index_file_path, FALSE, NULL);
06367fa3 377 if (!mapped_file) {
4c65a157 378 BT_COMP_LOGD("Cannot create new mapped file %s",
55314f2a 379 index_file_path);
97ade20b 380 goto error;
06367fa3 381 }
d14940a7
JG
382
383 /*
384 * The g_mapped_file API limits us to 4GB files on 32-bit.
385 * Traces with such large indexes have never been seen in the wild,
386 * but this would need to be adjusted to support them.
387 */
b6c3dcb2
JG
388 filesize = g_mapped_file_get_length(mapped_file);
389 if (filesize < sizeof(*header)) {
4c65a157 390 BT_COMP_LOGW("Invalid LTTng trace index file: "
d14940a7
JG
391 "file size (%zu bytes) < header size (%zu bytes)",
392 filesize, sizeof(*header));
97ade20b 393 goto error;
b6c3dcb2
JG
394 }
395
396 mmap_begin = g_mapped_file_get_contents(mapped_file);
397 header = (struct ctf_packet_index_file_hdr *) mmap_begin;
398
399 file_pos = g_mapped_file_get_contents(mapped_file) + sizeof(*header);
400 if (be32toh(header->magic) != CTF_INDEX_MAGIC) {
4c65a157 401 BT_COMP_LOGW_STR("Invalid LTTng trace index: \"magic\" field validation failed");
97ade20b 402 goto error;
b6c3dcb2 403 }
b6c3dcb2 404
1984ac2b
SM
405 version_major = be32toh(header->index_major);
406 version_minor = be32toh(header->index_minor);
407 if (version_major != 1) {
408 BT_COMP_LOGW(
409 "Unknown LTTng trace index version: "
410 "major=%" PRIu32 ", minor=%" PRIu32,
411 version_major, version_minor);
412 goto error;
413 }
414
b6c3dcb2
JG
415 file_index_entry_size = be32toh(header->packet_index_len);
416 file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size;
97ade20b 417 if ((filesize - sizeof(*header)) % file_index_entry_size) {
4c65a157 418 BT_COMP_LOGW("Invalid LTTng trace index: the index's size after the header "
d14940a7
JG
419 "(%zu bytes) is not a multiple of the index entry size "
420 "(%zu bytes)", (filesize - sizeof(*header)),
421 sizeof(*header));
97ade20b 422 goto error;
b6c3dcb2
JG
423 }
424
4c65a157 425 index = ctf_fs_ds_index_create(ds_file->log_level, ds_file->self_comp);
97ade20b
JG
426 if (!index) {
427 goto error;
b6c3dcb2 428 }
97ade20b 429
b6c3dcb2
JG
430 for (i = 0; i < file_entry_count; i++) {
431 struct ctf_packet_index *file_index =
432 (struct ctf_packet_index *) file_pos;
433 uint64_t packet_size = be64toh(file_index->packet_size);
434
435 if (packet_size % CHAR_BIT) {
4c65a157 436 BT_COMP_LOGW("Invalid packet size encountered in LTTng trace index file");
97ade20b 437 goto error;
b6c3dcb2
JG
438 }
439
6834784d
SM
440 index_entry = ctf_fs_ds_index_entry_create(
441 ds_file->self_comp, ds_file->log_level);
7ed5243a 442 if (!index_entry) {
6834784d
SM
443 BT_COMP_LOGE_APPEND_CAUSE(ds_file->self_comp,
444 "Failed to create a ctf_fs_ds_index_entry.");
7ed5243a
FD
445 goto error;
446 }
447
bf012bde
FD
448 /* Set path to stream file. */
449 index_entry->path = file_info->path->str;
450
b6c3dcb2
JG
451 /* Convert size in bits to bytes. */
452 packet_size /= CHAR_BIT;
97ade20b 453 index_entry->packet_size = packet_size;
b6c3dcb2 454
97ade20b 455 index_entry->offset = be64toh(file_index->offset);
de38c26a 456 if (i != 0 && index_entry->offset < prev_index_entry->offset) {
4c65a157 457 BT_COMP_LOGW("Invalid, non-monotonic, packet offset encountered in LTTng trace index file: "
d14940a7 458 "previous offset=%" PRIu64 ", current offset=%" PRIu64,
9dd33658 459 prev_index_entry->offset, index_entry->offset);
97ade20b 460 goto error;
b6c3dcb2
JG
461 }
462
97ade20b
JG
463 index_entry->timestamp_begin = be64toh(file_index->timestamp_begin);
464 index_entry->timestamp_end = be64toh(file_index->timestamp_end);
465 if (index_entry->timestamp_end < index_entry->timestamp_begin) {
4c65a157 466 BT_COMP_LOGW("Invalid packet time bounds encountered in LTTng trace index file (begin > end): "
d14940a7
JG
467 "timestamp_begin=%" PRIu64 "timestamp_end=%" PRIu64,
468 index_entry->timestamp_begin,
469 index_entry->timestamp_end);
97ade20b
JG
470 goto error;
471 }
472
473 /* Convert the packet's bound to nanoseconds since Epoch. */
44c440bc 474 ret = convert_cycles_to_ns(sc->default_clock_class,
97ade20b
JG
475 index_entry->timestamp_begin,
476 &index_entry->timestamp_begin_ns);
477 if (ret) {
4c65a157 478 BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch during index parsing");
97ade20b
JG
479 goto error;
480 }
44c440bc 481 ret = convert_cycles_to_ns(sc->default_clock_class,
97ade20b
JG
482 index_entry->timestamp_end,
483 &index_entry->timestamp_end_ns);
484 if (ret) {
4c65a157 485 BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch during LTTng trace index parsing");
97ade20b 486 goto error;
b6c3dcb2
JG
487 }
488
6834784d
SM
489 if (version_minor >= 1) {
490 index_entry->packet_seq_num = be64toh(file_index->packet_seq_num);
491 }
492
b6c3dcb2
JG
493 total_packets_size += packet_size;
494 file_pos += file_index_entry_size;
7ed5243a 495
de38c26a 496 prev_index_entry = index_entry;
f35a48bc
SM
497
498 /* Give ownership of `index_entry` to `index->entries`. */
499 g_ptr_array_add(index->entries, index_entry);
500 index_entry = NULL;
b6c3dcb2
JG
501 }
502
503 /* Validate that the index addresses the complete stream. */
94cf822e 504 if (ds_file->file->size != total_packets_size) {
4c65a157 505 BT_COMP_LOGW("Invalid LTTng trace index file; indexed size != stream file size: "
9e0c8dbb 506 "file-size=%" PRIu64 ", total-packets-size=%" PRIu64,
d14940a7 507 ds_file->file->size, total_packets_size);
97ade20b 508 goto error;
b6c3dcb2
JG
509 }
510end:
511 g_free(directory);
512 g_free(basename);
513 g_free(index_file_path);
06367fa3
JG
514 if (index_basename) {
515 g_string_free(index_basename, TRUE);
516 }
517 if (mapped_file) {
518 g_mapped_file_unref(mapped_file);
519 }
97ade20b
JG
520 return index;
521error:
522 ctf_fs_ds_index_destroy(index);
7ed5243a 523 g_free(index_entry);
97ade20b 524 index = NULL;
b6c3dcb2
JG
525 goto end;
526}
527
9e0c8dbb
JG
528static
529int init_index_entry(struct ctf_fs_ds_index_entry *entry,
44c440bc 530 struct ctf_fs_ds_file *ds_file,
18a1979b 531 struct ctf_msg_iter_packet_properties *props,
44c440bc 532 off_t packet_size, off_t packet_offset)
9e0c8dbb 533{
ca79a87c 534 int ret = 0;
44c440bc 535 struct ctf_stream_class *sc;
2e42d046
SM
536 bt_self_component *self_comp = ds_file->self_comp;
537 bt_logging_level log_level = ds_file->log_level;
9e0c8dbb 538
44c440bc
PP
539 sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
540 props->stream_class_id);
541 BT_ASSERT(sc);
f6ccaed9 542 BT_ASSERT(packet_offset >= 0);
9e0c8dbb 543 entry->offset = packet_offset;
f6ccaed9 544 BT_ASSERT(packet_size >= 0);
9e0c8dbb
JG
545 entry->packet_size = packet_size;
546
83ebb7f1 547 if (props->snapshots.beginning_clock != UINT64_C(-1)) {
41bd46eb
FD
548 entry->timestamp_begin = props->snapshots.beginning_clock;
549
83ebb7f1
PP
550 /* Convert the packet's bound to nanoseconds since Epoch. */
551 ret = convert_cycles_to_ns(sc->default_clock_class,
552 props->snapshots.beginning_clock,
553 &entry->timestamp_begin_ns);
554 if (ret) {
4c65a157 555 BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
83ebb7f1
PP
556 goto end;
557 }
558 } else {
41bd46eb 559 entry->timestamp_begin = UINT64_C(-1);
83ebb7f1 560 entry->timestamp_begin_ns = UINT64_C(-1);
9e0c8dbb
JG
561 }
562
83ebb7f1 563 if (props->snapshots.end_clock != UINT64_C(-1)) {
41bd46eb
FD
564 entry->timestamp_end = props->snapshots.end_clock;
565
566 /* Convert the packet's bound to nanoseconds since Epoch. */
83ebb7f1
PP
567 ret = convert_cycles_to_ns(sc->default_clock_class,
568 props->snapshots.end_clock,
569 &entry->timestamp_end_ns);
570 if (ret) {
4c65a157 571 BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
83ebb7f1
PP
572 goto end;
573 }
574 } else {
41bd46eb 575 entry->timestamp_end = UINT64_C(-1);
83ebb7f1 576 entry->timestamp_end_ns = UINT64_C(-1);
9e0c8dbb 577 }
0b29603d 578
9e0c8dbb 579end:
9e0c8dbb
JG
580 return ret;
581}
582
583static
584struct ctf_fs_ds_index *build_index_from_stream_file(
bf012bde 585 struct ctf_fs_ds_file *ds_file,
6d54260a
SM
586 struct ctf_fs_ds_file_info *file_info,
587 struct ctf_msg_iter *msg_iter)
9e0c8dbb
JG
588{
589 int ret;
590 struct ctf_fs_ds_index *index = NULL;
18a1979b 591 enum ctf_msg_iter_status iter_status = CTF_MSG_ITER_STATUS_OK;
fc917f65 592 off_t current_packet_offset_bytes = 0;
2e42d046
SM
593 bt_self_component *self_comp = ds_file->self_comp;
594 bt_logging_level log_level = ds_file->log_level;
9e0c8dbb 595
4c65a157 596 BT_COMP_LOGI("Indexing stream file %s", ds_file->file->path->str);
9e0c8dbb 597
4c65a157 598 index = ctf_fs_ds_index_create(ds_file->log_level, ds_file->self_comp);
9e0c8dbb
JG
599 if (!index) {
600 goto error;
601 }
602
2b601d0c 603 while (true) {
44c440bc 604 off_t current_packet_size_bytes;
7ed5243a 605 struct ctf_fs_ds_index_entry *index_entry;
18a1979b 606 struct ctf_msg_iter_packet_properties props;
9e0c8dbb 607
fc917f65 608 if (current_packet_offset_bytes < 0) {
4c65a157 609 BT_COMP_LOGE_STR("Cannot get the current packet's offset.");
fc917f65
PP
610 goto error;
611 } else if (current_packet_offset_bytes > ds_file->file->size) {
4c65a157 612 BT_COMP_LOGE_STR("Unexpected current packet's offset (larger than file).");
fc917f65
PP
613 goto error;
614 } else if (current_packet_offset_bytes == ds_file->file->size) {
615 /* No more data */
616 break;
617 }
618
6d54260a 619 iter_status = ctf_msg_iter_seek(msg_iter,
fc917f65 620 current_packet_offset_bytes);
18a1979b 621 if (iter_status != CTF_MSG_ITER_STATUS_OK) {
9e0c8dbb
JG
622 goto error;
623 }
312c056a 624
18a1979b 625 iter_status = ctf_msg_iter_get_packet_properties(
6d54260a 626 msg_iter, &props);
18a1979b 627 if (iter_status != CTF_MSG_ITER_STATUS_OK) {
9e0c8dbb
JG
628 goto error;
629 }
630
fc917f65
PP
631 if (props.exp_packet_total_size >= 0) {
632 current_packet_size_bytes =
633 (uint64_t) props.exp_packet_total_size / 8;
634 } else {
635 current_packet_size_bytes = ds_file->file->size;
636 }
9e0c8dbb 637
fc917f65 638 if (current_packet_offset_bytes + current_packet_size_bytes >
9e0c8dbb 639 ds_file->file->size) {
4c65a157 640 BT_COMP_LOGW("Invalid packet size reported in file: stream=\"%s\", "
9e0c8dbb
JG
641 "packet-offset=%jd, packet-size-bytes=%jd, "
642 "file-size=%jd",
643 ds_file->file->path->str,
df0fc0bf
JR
644 (intmax_t) current_packet_offset_bytes,
645 (intmax_t) current_packet_size_bytes,
646 (intmax_t) ds_file->file->size);
9e0c8dbb
JG
647 goto error;
648 }
649
6834784d
SM
650 index_entry = ctf_fs_ds_index_entry_create(
651 ds_file->self_comp, ds_file->log_level);
7ed5243a 652 if (!index_entry) {
6834784d
SM
653 BT_COMP_LOGE_APPEND_CAUSE(ds_file->self_comp,
654 "Failed to create a ctf_fs_ds_index_entry.");
9e0c8dbb
JG
655 goto error;
656 }
657
bf012bde
FD
658 /* Set path to stream file. */
659 index_entry->path = file_info->path->str;
660
7ed5243a 661 ret = init_index_entry(index_entry, ds_file, &props,
fc917f65 662 current_packet_size_bytes, current_packet_offset_bytes);
9e0c8dbb 663 if (ret) {
7ed5243a 664 g_free(index_entry);
9e0c8dbb
JG
665 goto error;
666 }
7ed5243a
FD
667
668 g_ptr_array_add(index->entries, index_entry);
669
ca633588 670 current_packet_offset_bytes += current_packet_size_bytes;
4c65a157 671 BT_COMP_LOGD("Seeking to next packet: current-packet-offset=%jd, "
ca633588 672 "next-packet-offset=%jd",
df0fc0bf
JR
673 (intmax_t) (current_packet_offset_bytes - current_packet_size_bytes),
674 (intmax_t) current_packet_offset_bytes);
9e0c8dbb 675 }
312c056a 676
9e0c8dbb 677end:
9e0c8dbb 678 return index;
312c056a 679
9e0c8dbb
JG
680error:
681 ctf_fs_ds_index_destroy(index);
682 index = NULL;
683 goto end;
684}
685
e7a4393b 686BT_HIDDEN
94cf822e
PP
687struct ctf_fs_ds_file *ctf_fs_ds_file_create(
688 struct ctf_fs_trace *ctf_fs_trace,
f5f7e8df 689 bt_self_message_iterator *self_msg_iter,
98903a3e
PP
690 bt_stream *stream, const char *path,
691 bt_logging_level log_level)
e98a2d6e 692{
b6c3dcb2 693 int ret;
3b16a19b 694 const size_t offset_align = bt_mmap_get_offset_align_size(log_level);
94cf822e 695 struct ctf_fs_ds_file *ds_file = g_new0(struct ctf_fs_ds_file, 1);
e98a2d6e 696
94cf822e 697 if (!ds_file) {
e98a2d6e
PP
698 goto error;
699 }
700
98903a3e 701 ds_file->log_level = log_level;
4c65a157 702 ds_file->self_comp = ctf_fs_trace->self_comp;
f5f7e8df 703 ds_file->self_msg_iter = self_msg_iter;
4c65a157 704 ds_file->file = ctf_fs_file_create(log_level, ds_file->self_comp);
94cf822e 705 if (!ds_file->file) {
4f1f88a6
PP
706 goto error;
707 }
708
398454ed 709 ds_file->stream = stream;
c5b9b441 710 bt_stream_get_ref(ds_file->stream);
44c440bc 711 ds_file->metadata = ctf_fs_trace->metadata;
94cf822e 712 g_string_assign(ds_file->file->path, path);
55314f2a 713 ret = ctf_fs_file_open(ds_file->file, "rb");
4f1f88a6
PP
714 if (ret) {
715 goto error;
716 }
717
3b16a19b 718 ds_file->mmap_max_len = offset_align * 2048;
94cf822e 719
e98a2d6e 720 goto end;
1a9f7075 721
e98a2d6e 722error:
78586d8a 723 /* Do not touch "borrowed" file. */
94cf822e
PP
724 ctf_fs_ds_file_destroy(ds_file);
725 ds_file = NULL;
1a9f7075 726
e98a2d6e 727end:
94cf822e 728 return ds_file;
e98a2d6e
PP
729}
730
97ade20b
JG
731BT_HIDDEN
732struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(
bf012bde 733 struct ctf_fs_ds_file *ds_file,
6d54260a
SM
734 struct ctf_fs_ds_file_info *file_info,
735 struct ctf_msg_iter *msg_iter)
97ade20b 736{
9e0c8dbb 737 struct ctf_fs_ds_index *index;
2e42d046
SM
738 bt_self_component *self_comp = ds_file->self_comp;
739 bt_logging_level log_level = ds_file->log_level;
9e0c8dbb 740
6d54260a 741 index = build_index_from_idx_file(ds_file, file_info, msg_iter);
9e0c8dbb
JG
742 if (index) {
743 goto end;
744 }
745
4c65a157 746 BT_COMP_LOGI("Failed to build index from .index file; "
9e0c8dbb 747 "falling back to stream indexing.");
6d54260a 748 index = build_index_from_stream_file(ds_file, file_info, msg_iter);
9e0c8dbb
JG
749end:
750 return index;
97ade20b
JG
751}
752
7ed5243a 753BT_HIDDEN
4c65a157
PP
754struct ctf_fs_ds_index *ctf_fs_ds_index_create(bt_logging_level log_level,
755 bt_self_component *self_comp)
7ed5243a
FD
756{
757 struct ctf_fs_ds_index *index = g_new0(struct ctf_fs_ds_index, 1);
758
759 if (!index) {
4c65a157 760 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
98903a3e 761 "Failed to allocate index");
7ed5243a
FD
762 goto error;
763 }
764
765 index->entries = g_ptr_array_new_with_free_func((GDestroyNotify) g_free);
766 if (!index->entries) {
4c65a157 767 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
98903a3e 768 "Failed to allocate index entries.");
7ed5243a
FD
769 goto error;
770 }
771
772 goto end;
773
774error:
775 ctf_fs_ds_index_destroy(index);
776 index = NULL;
777end:
778 return index;
779}
780
5b29e799 781BT_HIDDEN
94cf822e 782void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *ds_file)
e98a2d6e 783{
94cf822e 784 if (!ds_file) {
5b29e799 785 return;
043e2020
JG
786 }
787
c5b9b441 788 bt_stream_put_ref(ds_file->stream);
94cf822e 789 (void) ds_file_munmap(ds_file);
0982a26d 790
94cf822e
PP
791 if (ds_file->file) {
792 ctf_fs_file_destroy(ds_file->file);
e98a2d6e
PP
793 }
794
94cf822e 795 g_free(ds_file);
e98a2d6e 796}
4f1f88a6 797
97ade20b
JG
798BT_HIDDEN
799void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index)
800{
801 if (!index) {
802 return;
803 }
804
805 if (index->entries) {
7ed5243a 806 g_ptr_array_free(index->entries, TRUE);
97ade20b
JG
807 }
808 g_free(index);
809}
This page took 0.110278 seconds and 4 git commands to generate.