.gitignore: add installed_files.txt
[babeltrace.git] / src / plugins / ctf / fs-src / data-stream-file.cpp
... / ...
CommitLineData
1/*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 */
8
9#include <glib.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <sys/stat.h>
13
14#include "compat/endian.h" /* IWYU pragma: keep */
15#include "compat/mman.h" /* IWYU: pragma keep */
16#include "cpp-common/bt2c/glib-up.hpp"
17#include "cpp-common/bt2s/make-unique.hpp"
18#include "cpp-common/vendor/fmt/format.h"
19
20#include "../common/src/pkt-props.hpp"
21#include "data-stream-file.hpp"
22#include "file.hpp"
23#include "lttng-index.hpp"
24
25using namespace bt2c::literals::datalen;
26
27static bt2c::DataLen getFileSize(const char * const path, const bt2c::Logger& logger)
28{
29 struct stat st;
30 if (stat(path, &st) != 0) {
31 BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
32 "Failed to stat stream file", "path={}", path);
33 }
34
35 return bt2c::DataLen::fromBytes(st.st_size);
36}
37
38ctf_fs_ds_file_info::ctf_fs_ds_file_info(std::string pathParam, const bt2c::Logger& parentLogger) :
39 logger {parentLogger, "PLUGIN/SRC.CTF.FS/DS-FILE-INFO"}, path(std::move(pathParam)),
40 size(getFileSize(path.c_str(), logger))
41{
42}
43
44/*
45 * Return true if `offset_in_file` is in the current mapping.
46 */
47
48static bool offset_ist_mapped(struct ctf_fs_ds_file *ds_file, off_t offset_in_file)
49{
50 if (!ds_file->mmap_addr)
51 return false;
52
53 return offset_in_file >= ds_file->mmap_offset_in_file &&
54 offset_in_file < (ds_file->mmap_offset_in_file + ds_file->mmap_len);
55}
56
57enum ds_file_status
58{
59 DS_FILE_STATUS_OK = 0,
60 DS_FILE_STATUS_ERROR = -1,
61 DS_FILE_STATUS_EOF = 1,
62};
63
64static ds_file_status ds_file_munmap(struct ctf_fs_ds_file *ds_file)
65{
66 BT_ASSERT(ds_file);
67
68 if (!ds_file->mmap_addr) {
69 return DS_FILE_STATUS_OK;
70 }
71
72 if (bt_munmap(ds_file->mmap_addr, ds_file->mmap_len)) {
73 BT_CPPLOGE_ERRNO_SPEC(ds_file->logger, "Cannot memory-unmap file",
74 ": address={}, size={}, file_path=\"{}\", file={}",
75 fmt::ptr(ds_file->mmap_addr), ds_file->mmap_len,
76 ds_file->file ? ds_file->file->path : "NULL",
77 ds_file->file ? fmt::ptr(ds_file->file->fp) : nullptr);
78 return DS_FILE_STATUS_ERROR;
79 }
80
81 ds_file->mmap_addr = NULL;
82
83 return DS_FILE_STATUS_OK;
84}
85
86/*
87 * mmap a region of `ds_file` such that `requested_offset_in_file` is in the
88 * mapping. If the currently mmap-ed region already contains
89 * `requested_offset_in_file`, the mapping is kept.
90 *
91 * `requested_offset_in_file` must be a valid offset in the file.
92 */
93static ds_file_status ds_file_mmap(struct ctf_fs_ds_file *ds_file, off_t requested_offset_in_file)
94{
95 /* Ensure the requested offset is in the file range. */
96 BT_ASSERT(requested_offset_in_file >= 0);
97 BT_ASSERT(requested_offset_in_file < ds_file->file->size);
98
99 /*
100 * If the mapping already contains the requested range, we have nothing to
101 * do.
102 */
103 if (offset_ist_mapped(ds_file, requested_offset_in_file)) {
104 return DS_FILE_STATUS_OK;
105 }
106
107 /* Unmap old region */
108 ds_file_status status = ds_file_munmap(ds_file);
109 if (status != DS_FILE_STATUS_OK) {
110 return status;
111 }
112
113 /*
114 * Compute a mapping that has the required alignment properties and
115 * contains `requested_offset_in_file`.
116 */
117 size_t alignment = bt_mmap_get_offset_align_size(static_cast<int>(ds_file->logger.level()));
118 ds_file->mmap_offset_in_file =
119 requested_offset_in_file - (requested_offset_in_file % alignment);
120 ds_file->mmap_len =
121 MIN(ds_file->file->size - ds_file->mmap_offset_in_file, ds_file->mmap_max_len);
122
123 BT_ASSERT(ds_file->mmap_len > 0);
124 BT_ASSERT(requested_offset_in_file >= ds_file->mmap_offset_in_file);
125 BT_ASSERT(requested_offset_in_file < (ds_file->mmap_offset_in_file + ds_file->mmap_len));
126
127 ds_file->mmap_addr =
128 bt_mmap(ds_file->mmap_len, PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp.get()),
129 ds_file->mmap_offset_in_file, static_cast<int>(ds_file->logger.level()));
130 if (ds_file->mmap_addr == MAP_FAILED) {
131 BT_CPPLOGE_SPEC(ds_file->logger,
132 "Cannot memory-map address (size {}) of file \"{}\" ({}) at offset {}: {}",
133 ds_file->mmap_len, ds_file->file->path, fmt::ptr(ds_file->file->fp),
134 (intmax_t) ds_file->mmap_offset_in_file, strerror(errno));
135 return DS_FILE_STATUS_ERROR;
136 }
137
138 return DS_FILE_STATUS_OK;
139}
140
141void ctf_fs_ds_index::updateOffsetsInStream()
142{
143 auto offsetInStream = 0_bytes;
144
145 for (ctf_fs_ds_index_entry& entry : this->entries) {
146 entry.offsetInStream = offsetInStream;
147 offsetInStream += entry.packetSize;
148 }
149}
150
151static int convert_cycles_to_ns(const ctf::src::ClkCls& clockClass, uint64_t cycles, int64_t *ns)
152{
153 return bt_util_clock_cycles_to_ns_from_origin(cycles, clockClass.freq(),
154 clockClass.offsetFromOrigin().seconds(),
155 clockClass.offsetFromOrigin().cycles(), ns);
156}
157
158static bt2s::optional<ctf_fs_ds_index>
159build_index_from_idx_file(const ctf_fs_ds_file_info& fileInfo, const ctf::src::TraceCls& traceCls)
160{
161 const char *path = fileInfo.path.c_str();
162 BT_CPPLOGI_SPEC(fileInfo.logger, "Building index from .idx file of stream file {}", path);
163
164 /* Look for index file in relative path index/name.idx. */
165 bt2c::GCharUP basename {g_path_get_basename(path)};
166 if (!basename) {
167 BT_CPPLOGE_SPEC(fileInfo.logger, "Cannot get the basename of datastream file {}", path);
168 return bt2s::nullopt;
169 }
170
171 bt2c::GCharUP directory {g_path_get_dirname(path)};
172 if (!directory) {
173 BT_CPPLOGE_SPEC(fileInfo.logger, "Cannot get dirname of datastream file {}", path);
174 return bt2s::nullopt;
175 }
176
177 std::string index_basename = fmt::format("{}.idx", basename.get());
178 bt2c::GCharUP index_file_path {
179 g_build_filename(directory.get(), "index", index_basename.c_str(), NULL)};
180 bt2c::GMappedFileUP mapped_file {g_mapped_file_new(index_file_path.get(), FALSE, NULL)};
181 if (!mapped_file) {
182 BT_CPPLOGD_SPEC(fileInfo.logger, "Cannot create new mapped file {}", index_file_path.get());
183 return bt2s::nullopt;
184 }
185
186 /*
187 * The g_mapped_file API limits us to 4GB files on 32-bit.
188 * Traces with such large indexes have never been seen in the wild,
189 * but this would need to be adjusted to support them.
190 */
191 gsize filesize = g_mapped_file_get_length(mapped_file.get());
192 if (filesize < sizeof(ctf_packet_index_file_hdr)) {
193 BT_CPPLOGW_SPEC(fileInfo.logger,
194 "Invalid LTTng trace index file: "
195 "file size ({} bytes) < header size ({} bytes)",
196 filesize, sizeof(ctf_packet_index_file_hdr));
197 return bt2s::nullopt;
198 }
199
200 const char *mmap_begin = g_mapped_file_get_contents(mapped_file.get());
201 const ctf_packet_index_file_hdr *header = (const ctf_packet_index_file_hdr *) mmap_begin;
202
203 const char *file_pos = g_mapped_file_get_contents(mapped_file.get()) + sizeof(*header);
204 if (be32toh(header->magic) != CTF_INDEX_MAGIC) {
205 BT_CPPLOGW_SPEC(fileInfo.logger,
206 "Invalid LTTng trace index: \"magic\" field validation failed");
207 return bt2s::nullopt;
208 }
209
210 uint32_t version_major = be32toh(header->index_major);
211 uint32_t version_minor = be32toh(header->index_minor);
212 if (version_major != 1) {
213 BT_CPPLOGW_SPEC(fileInfo.logger, "Unknown LTTng trace index version: major={}, minor={}",
214 version_major, version_minor);
215 return bt2s::nullopt;
216 }
217
218 size_t file_index_entry_size = be32toh(header->packet_index_len);
219 if (file_index_entry_size < CTF_INDEX_1_0_SIZE) {
220 BT_CPPLOGW_SPEC(
221 fileInfo.logger,
222 "Invalid `packet_index_len` in LTTng trace index file (`packet_index_len` < CTF index 1.0 index entry size): "
223 "packet_index_len={}, CTF_INDEX_1_0_SIZE={}",
224 file_index_entry_size, CTF_INDEX_1_0_SIZE);
225 return bt2s::nullopt;
226 }
227
228 size_t file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size;
229 if ((filesize - sizeof(*header)) % file_index_entry_size) {
230 BT_CPPLOGW_SPEC(fileInfo.logger,
231 "Invalid LTTng trace index: the index's size after the header "
232 "({} bytes) is not a multiple of the index entry size "
233 "({} bytes)",
234 (filesize - sizeof(*header)), sizeof(*header));
235 return bt2s::nullopt;
236 }
237
238 /*
239 * We need the clock class to convert cycles to ns. For that, we need the
240 * stream class. Read the stream class id from the first packet's header.
241 * We don't know the size of that packet yet, so pretend that it spans the
242 * whole file (the reader will only read the header anyway).
243 */
244 ctf_fs_ds_index_entry tempIndexEntry {path, 0_bits, fileInfo.size};
245 ctf_fs_ds_index tempIndex;
246 tempIndex.entries.emplace_back(tempIndexEntry);
247
248 ctf::src::fs::Medium::UP medium =
249 bt2s::make_unique<ctf::src::fs::Medium>(tempIndex, fileInfo.logger);
250 ctf::src::PktProps props =
251 ctf::src::readPktProps(traceCls, std::move(medium), 0_bytes, fileInfo.logger);
252
253 const ctf::src::DataStreamCls *sc = props.dataStreamCls;
254 BT_ASSERT(sc);
255 if (!sc->defClkCls()) {
256 BT_CPPLOGI_SPEC(fileInfo.logger, "Cannot find stream class's default clock class.");
257 return bt2s::nullopt;
258 }
259
260 ctf_fs_ds_index index;
261 ctf_fs_ds_index_entry *prev_index_entry = nullptr;
262 auto totalPacketsSize = 0_bytes;
263
264 for (size_t i = 0; i < file_entry_count; i++) {
265 struct ctf_packet_index *file_index = (struct ctf_packet_index *) file_pos;
266 const auto packetSize = bt2c::DataLen::fromBits(be64toh(file_index->packet_size));
267
268 if (packetSize.hasExtraBits()) {
269 BT_CPPLOGW_SPEC(fileInfo.logger,
270 "Invalid packet size encountered in LTTng trace index file");
271 return bt2s::nullopt;
272 }
273
274 const auto offset = bt2c::DataLen::fromBytes(be64toh(file_index->offset));
275
276 if (i != 0 && offset < prev_index_entry->offsetInFile) {
277 BT_CPPLOGW_SPEC(
278 fileInfo.logger,
279 "Invalid, non-monotonic, packet offset encountered in LTTng trace index file: "
280 "previous offset={} bytes, current offset={} bytes",
281 prev_index_entry->offsetInFile.bytes(), offset.bytes());
282 return bt2s::nullopt;
283 }
284
285 ctf_fs_ds_index_entry index_entry {path, offset, packetSize};
286 index_entry.timestamp_begin = be64toh(file_index->timestamp_begin);
287 index_entry.timestamp_end = be64toh(file_index->timestamp_end);
288 if (index_entry.timestamp_end < index_entry.timestamp_begin) {
289 BT_CPPLOGW_SPEC(
290 fileInfo.logger,
291 "Invalid packet time bounds encountered in LTTng trace index file (begin > end): "
292 "timestamp_begin={}, timestamp_end={}",
293 index_entry.timestamp_begin, index_entry.timestamp_end);
294 return bt2s::nullopt;
295 }
296
297 /* Convert the packet's bound to nanoseconds since Epoch. */
298 int ret = convert_cycles_to_ns(*sc->defClkCls(), index_entry.timestamp_begin,
299 &index_entry.timestamp_begin_ns);
300 if (ret) {
301 BT_CPPLOGI_SPEC(
302 fileInfo.logger,
303 "Failed to convert raw timestamp to nanoseconds since Epoch during index parsing");
304 return bt2s::nullopt;
305 }
306 ret = convert_cycles_to_ns(*sc->defClkCls(), index_entry.timestamp_end,
307 &index_entry.timestamp_end_ns);
308 if (ret) {
309 BT_CPPLOGI_SPEC(
310 fileInfo.logger,
311 "Failed to convert raw timestamp to nanoseconds since Epoch during LTTng trace index parsing");
312 return bt2s::nullopt;
313 }
314
315 if (version_minor >= 1) {
316 index_entry.packet_seq_num = be64toh(file_index->packet_seq_num);
317 }
318
319 totalPacketsSize += packetSize;
320 file_pos += file_index_entry_size;
321
322 index.entries.emplace_back(index_entry);
323
324 prev_index_entry = &index.entries.back();
325 }
326
327 /* Validate that the index addresses the complete stream. */
328 if (fileInfo.size != totalPacketsSize) {
329 BT_CPPLOGW_SPEC(fileInfo.logger,
330 "Invalid LTTng trace index file; indexed size != stream file size: "
331 "stream-file-size-bytes={}, total-packets-size-bytes={}",
332 fileInfo.size.bytes(), totalPacketsSize.bytes());
333 return bt2s::nullopt;
334 }
335
336 return index;
337}
338
339static int init_index_entry(ctf_fs_ds_index_entry& entry, ctf::src::PktProps *props,
340 const ctf::src::DataStreamCls& dataStreamCls,
341 const bt2c::Logger& logger)
342{
343 if (props->snapshots.beginDefClk) {
344 entry.timestamp_begin = *props->snapshots.beginDefClk;
345
346 /* Convert the packet's bound to nanoseconds since Epoch. */
347 int ret = convert_cycles_to_ns(*dataStreamCls.defClkCls(), *props->snapshots.beginDefClk,
348 &entry.timestamp_begin_ns);
349 if (ret) {
350 BT_CPPLOGI_SPEC(logger, "Failed to convert raw timestamp to nanoseconds since Epoch.");
351 return ret;
352 }
353 } else {
354 entry.timestamp_begin = UINT64_C(-1);
355 entry.timestamp_begin_ns = UINT64_C(-1);
356 }
357
358 if (props->snapshots.endDefClk) {
359 entry.timestamp_end = *props->snapshots.endDefClk;
360
361 /* Convert the packet's bound to nanoseconds since Epoch. */
362 int ret = convert_cycles_to_ns(*dataStreamCls.defClkCls(), *props->snapshots.endDefClk,
363 &entry.timestamp_end_ns);
364 if (ret) {
365 BT_CPPLOGI_SPEC(logger, "Failed to convert raw timestamp to nanoseconds since Epoch.");
366 return ret;
367 }
368 } else {
369 entry.timestamp_end = UINT64_C(-1);
370 entry.timestamp_end_ns = UINT64_C(-1);
371 }
372
373 return 0;
374}
375
376static bt2s::optional<ctf_fs_ds_index>
377build_index_from_stream_file(const ctf_fs_ds_file_info& fileInfo,
378 const ctf::src::TraceCls& traceCls)
379{
380 const char *path = fileInfo.path.c_str();
381
382 BT_CPPLOGI_SPEC(fileInfo.logger, "Indexing stream file {}", path);
383
384 ctf_fs_ds_index index;
385 auto currentPacketOffset = 0_bytes;
386
387 while (true) {
388 if (currentPacketOffset > fileInfo.size) {
389 BT_CPPLOGE_SPEC(fileInfo.logger,
390 "Unexpected current packet's offset (larger than file).");
391 return bt2s::nullopt;
392 } else if (currentPacketOffset == fileInfo.size) {
393 /* No more data */
394 break;
395 }
396
397 /*
398 * Create a temporary index and medium to read the properties of the
399 * current packet. We don't know yet the size of the packet (that's
400 * one of the things we want to find out), so pretend it spans the rest
401 * of the file.
402 */
403 ctf_fs_ds_index_entry tempIndexEntry {path, currentPacketOffset,
404 fileInfo.size - currentPacketOffset};
405 ctf_fs_ds_index tempIndex;
406 tempIndex.entries.emplace_back(tempIndexEntry);
407 ctf::src::fs::Medium::UP medium =
408 bt2s::make_unique<ctf::src::fs::Medium>(tempIndex, fileInfo.logger);
409 ctf::src::PktProps props = ctf::src::readPktProps(traceCls, std::move(medium),
410 currentPacketOffset, fileInfo.logger);
411
412 /*
413 * Get the current packet size from the packet header, if set. Else,
414 * assume there is a single packet in the file, so take the file size
415 * as the packet size.
416 */
417 const auto currentPacketSize =
418 props.expectedTotalLen ? *props.expectedTotalLen : fileInfo.size;
419
420 BT_CPPLOGI_SPEC(fileInfo.logger,
421 "Packet: offset-bytes={}, len-bytes={}, begin-clk={}, end-clk={}",
422 currentPacketOffset.bytes(), currentPacketSize.bytes(),
423 props.snapshots.beginDefClk ? *props.snapshots.beginDefClk : -1,
424 props.snapshots.endDefClk ? *props.snapshots.endDefClk : -1);
425
426 if (currentPacketOffset + currentPacketSize > fileInfo.size) {
427 BT_CPPLOGW_SPEC(fileInfo.logger,
428 "Invalid packet size reported in file: stream=\"{}\", "
429 "packet-offset-bytes={}, packet-size-bytes={}, "
430 "file-size-bytes={}",
431 path, currentPacketOffset.bytes(), currentPacketSize.bytes(),
432 fileInfo.size.bytes());
433 return bt2s::nullopt;
434 }
435
436 ctf_fs_ds_index_entry index_entry {path, currentPacketOffset, currentPacketSize};
437
438 if (init_index_entry(index_entry, &props, *props.dataStreamCls, fileInfo.logger)) {
439 return bt2s::nullopt;
440 }
441
442 index.entries.emplace_back(index_entry);
443
444 currentPacketOffset += currentPacketSize;
445 BT_CPPLOGD_SPEC(fileInfo.logger,
446 "Seeking to next packet: current-packet-offset-bytes={}, "
447 "next-packet-offset-bytes={}",
448 (currentPacketOffset - currentPacketSize).bytes(),
449 currentPacketOffset.bytes());
450 }
451
452 return index;
453}
454
455ctf_fs_ds_file::UP ctf_fs_ds_file_create(const char *path, const bt2c::Logger& parentLogger)
456{
457 const auto offset_align = bt_mmap_get_offset_align_size(static_cast<int>(parentLogger.level()));
458 auto ds_file = bt2s::make_unique<ctf_fs_ds_file>(parentLogger, offset_align * 2048);
459
460 ds_file->file = bt2s::make_unique<ctf_fs_file>(ds_file->logger);
461 ds_file->file->path = path;
462 int ret = ctf_fs_file_open(ds_file->file.get(), "rb");
463 if (ret) {
464 return nullptr;
465 }
466
467 return ds_file;
468}
469
470namespace ctf {
471namespace src {
472namespace fs {
473
474Medium::Medium(const ctf_fs_ds_index& index, const bt2c::Logger& parentLogger) :
475 _mIndex(index), _mLogger {parentLogger, "PLUGIN/SRC.CTF.FS/DS-MEDIUM"}
476{
477 BT_ASSERT(!_mIndex.entries.empty());
478}
479
480ctf_fs_ds_index::EntriesT::const_iterator
481Medium::_mFindIndexEntryForOffset(bt2c::DataLen offsetInStream) const noexcept
482{
483 return std::lower_bound(
484 _mIndex.entries.begin(), _mIndex.entries.end(), offsetInStream,
485 [](const ctf_fs_ds_index_entry& entry, bt2c::DataLen offsetInStreamLambda) {
486 return (entry.offsetInStream + entry.packetSize - 1_bytes) < offsetInStreamLambda;
487 });
488}
489
490ctf::src::Buf Medium::buf(const bt2c::DataLen requestedOffsetInStream, const bt2c::DataLen minSize)
491{
492 BT_CPPLOGD("buf called: offset-bytes={}, min-size-bytes={}", requestedOffsetInStream.bytes(),
493 minSize.bytes());
494
495 /* The medium only gets asked about whole byte offsets and min sizes. */
496 BT_ASSERT_DBG(requestedOffsetInStream.extraBitCount() == 0);
497 BT_ASSERT_DBG(minSize.extraBitCount() == 0);
498
499 /*
500 * +-file 1-----+ +-file 2-----+------------+------------+
501 * | | | | | |
502 * | packet 1 | | packet 2 | packet 3 | packet 4 |
503 * | | | | | |
504 * +------------+ +------------+------v-----+------------+
505 * ^-----------------------------------^ requestedOffsetInStream (passed as parameter)
506 * ^----------------------------^ indexEntry.offsetInStream (known)
507 * ^------------^ indexEntry.offsetInFile (known)
508 * ^---------------^ fileStartInStream (computed)
509 * ^-------------------^ requestedOffsetInFile (computed)
510 *
511 * Then, assuming mmap maps this region:
512 * ^------------^
513 *
514 * ^-------------------^ startOfMappingInFile
515 * ^----------------^ requestedOffsetInMapping
516 * ^--------------------------------^ endOfMappingInFile
517 */
518 const ctf_fs_ds_index::EntriesT::const_iterator indexEntryIt =
519 this->_mFindIndexEntryForOffset(requestedOffsetInStream);
520 if (indexEntryIt == _mIndex.entries.end()) {
521 BT_CPPLOGD("no index entry containing this offset");
522 throw NoData();
523 }
524
525 const ctf_fs_ds_index_entry& indexEntry = *indexEntryIt;
526
527 _mCurrentDsFile = ctf_fs_ds_file_create(indexEntry.path, _mLogger);
528 if (!_mCurrentDsFile) {
529 BT_CPPLOGE_APPEND_CAUSE_AND_THROW(bt2::Error, "Failed to create ctf_fs_ds_file");
530 }
531
532 const auto fileStartInStream = indexEntry.offsetInStream - indexEntry.offsetInFile;
533 const auto requestedOffsetInFile = requestedOffsetInStream - fileStartInStream;
534
535 ds_file_status status = ds_file_mmap(_mCurrentDsFile.get(), requestedOffsetInFile.bytes());
536 if (status != DS_FILE_STATUS_OK) {
537 throw bt2::Error("Failed to mmap file");
538 }
539
540 const auto startOfMappingInFile =
541 bt2c::DataLen::fromBytes(_mCurrentDsFile->mmap_offset_in_file);
542 const auto requestedOffsetInMapping = requestedOffsetInFile - startOfMappingInFile;
543 const auto exclEndOfMappingInFile =
544 startOfMappingInFile + bt2c::DataLen::fromBytes(_mCurrentDsFile->mmap_len);
545
546 /*
547 * Find where to end the mapping. We can map the following entries as long as
548 *
549 * 1) there are following entries
550 * 2) they are located in the same file as our starting entry
551 * 3) they are (at least partially) within the mapping
552 */
553
554 ctf_fs_ds_index::EntriesT::const_iterator endIndexEntryIt = indexEntryIt;
555 while (true) {
556 ctf_fs_ds_index::EntriesT::const_iterator nextIndexEntryIt = endIndexEntryIt + 1;
557
558 if (nextIndexEntryIt == _mIndex.entries.end()) {
559 break;
560 }
561
562 if (nextIndexEntryIt->path != indexEntryIt->path) {
563 break;
564 }
565
566 if (nextIndexEntryIt->offsetInFile >= exclEndOfMappingInFile) {
567 break;
568 }
569
570 endIndexEntryIt = nextIndexEntryIt;
571 }
572
573 /*
574 * It's possible the mapping ends in the middle of our end entry. Choose
575 * the end of the mapping or the end of the end entry, whichever comes
576 * first, as the end of the returned buffer.
577 */
578 const auto exclEndOfEndEntryInFile =
579 endIndexEntryIt->offsetInFile + endIndexEntryIt->packetSize;
580 const auto bufEndInFile = std::min(exclEndOfMappingInFile, exclEndOfEndEntryInFile);
581 const auto bufLen = bufEndInFile - requestedOffsetInFile;
582 const uint8_t *bufStart =
583 (const uint8_t *) _mCurrentDsFile->mmap_addr + requestedOffsetInMapping.bytes();
584
585 if (bufLen < minSize) {
586 BT_CPPLOGE_APPEND_CAUSE_AND_THROW(
587 bt2::Error,
588 "Insufficient data in file to fulfill request: path=\"{}\", requested-offset-in-file-bytes={}, "
589 "remaining-data-len-in-file-bytes={}, min-size-bytes={}",
590 indexEntry.path, requestedOffsetInFile.bytes(), bufLen.bytes(), minSize.bytes());
591 }
592
593 ctf::src::Buf buf {bufStart, bufLen};
594
595 BT_CPPLOGD("CtfFsMedium::buf returns: buf-addr={}, buf-size-bytes={}\n", fmt::ptr(buf.addr()),
596 buf.size().bytes());
597
598 return buf;
599}
600
601} /* namespace fs */
602} /* namespace src */
603} /* namespace ctf */
604
605bt2s::optional<ctf_fs_ds_index> ctf_fs_ds_file_build_index(const ctf_fs_ds_file_info& fileInfo,
606 const ctf::src::TraceCls& traceCls)
607{
608 auto index = build_index_from_idx_file(fileInfo, traceCls);
609 if (index) {
610 return index;
611 }
612
613 BT_CPPLOGI_SPEC(fileInfo.logger, "Failed to build index from .index file; "
614 "falling back to stream indexing.");
615 return build_index_from_stream_file(fileInfo, traceCls);
616}
617
618ctf_fs_ds_file::~ctf_fs_ds_file()
619{
620 (void) ds_file_munmap(this);
621}
622
623void ctf_fs_ds_file_group::insert_ds_file_info_sorted(ctf_fs_ds_file_info::UP ds_file_info)
624{
625 /* Find the spot where to insert this ds_file_info. */
626 auto it = this->ds_file_infos.begin();
627
628 for (; it != this->ds_file_infos.end(); ++it) {
629 const ctf_fs_ds_file_info& other_ds_file_info = **it;
630
631 if (ds_file_info->begin_ns < other_ds_file_info.begin_ns) {
632 break;
633 }
634 }
635
636 this->ds_file_infos.insert(it, std::move(ds_file_info));
637}
This page took 0.027471 seconds and 5 git commands to generate.