VRS
A file format for sensor data.
Loading...
Searching...
No Matches
IndexRecord.h
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <deque>
20#include <set>
21
22#include <vrs/Compressor.h>
23#include <vrs/DiskFile.h>
24#include <vrs/FileFormat.h>
25#include <vrs/ForwardDefinitions.h>
26#include <vrs/NewChunkHandler.h>
27#include <vrs/Record.h>
28#include <vrs/VrsExport.h>
29
30namespace vrs {
31
32using std::deque;
33using std::set;
34using std::unique_ptr;
35using std::vector;
36
37class ProgressLogger;
38
39struct DiskRecordIndexStruct;
40
42namespace IndexRecord {
43
44enum {
49};
50
51#pragma pack(push, 1)
52
54struct VRS_API DiskStreamId {
55 DiskStreamId() : typeId(static_cast<int32_t>(RecordableTypeId::Undefined)), instanceId(0) {}
56 explicit DiskStreamId(StreamId streamId)
57 : typeId(static_cast<int32_t>(streamId.getTypeId())), instanceId(streamId.getInstanceId()) {}
58
59 int32_t typeId;
60 uint16_t instanceId;
61
62 inline RecordableTypeId getTypeId() const {
63 return FileFormat::readRecordableTypeId(typeId);
64 }
65
66 inline uint16_t getInstanceId() const {
67 return static_cast<uint16_t>(instanceId);
68 }
69
70 inline StreamId getStreamId() const {
71 return {getTypeId(), getInstanceId()};
72 }
73};
74
76struct VRS_API DiskRecordInfo {
77 DiskRecordInfo() = default;
79 double timestampIn,
80 uint32_t recordSizeIn,
81 StreamId streamIdIn,
82 Record::Type recordTypeIn)
83 : timestamp(timestampIn),
84 recordSize(recordSizeIn),
85 recordType(static_cast<uint8_t>(recordTypeIn)),
86 streamId(streamIdIn) {}
87 DiskRecordInfo(StreamId streamIdIn, Record* record)
88 : timestamp(record->getTimestamp()),
89 recordSize(static_cast<uint32_t>(record->getSize())),
90 recordType(static_cast<uint8_t>(record->getRecordType())),
91 streamId(streamIdIn) {}
92
93 double timestamp{};
94 uint32_t recordSize{};
95 uint8_t recordType{};
96 DiskStreamId streamId{};
97
98 inline Record::Type getRecordType() const {
99 return static_cast<Record::Type>(recordType);
100 }
101
102 inline StreamId getStreamId() const {
103 return streamId.getStreamId();
104 }
105};
106
107#pragma pack(pop)
108
110struct VRS_API RecordInfo {
111 RecordInfo() = default;
113 double timestampIn,
114 int64_t fileOffsetIn,
115 StreamId streamIdIn,
116 Record::Type recordTypeIn)
117 : timestamp(timestampIn),
118 fileOffset(fileOffsetIn),
119 streamId(streamIdIn),
120 recordType(recordTypeIn) {}
121
122 double timestamp{};
123 int64_t fileOffset{};
124 StreamId streamId{};
125 Record::Type recordType{};
126
127 bool operator<(const RecordInfo& rhs) const {
128 return this->timestamp < rhs.timestamp ||
129 (this->timestamp <= rhs.timestamp &&
130 (this->streamId < rhs.streamId ||
131 (this->streamId == rhs.streamId && this->fileOffset < rhs.fileOffset)));
132 }
133
134 bool operator==(const RecordInfo& rhs) const {
135 return this->timestamp == rhs.timestamp && this->fileOffset == rhs.fileOffset &&
136 this->streamId == rhs.streamId && this->recordType == rhs.recordType;
137 }
138};
139
141class VRS_API Writer {
142 public:
143 explicit Writer(FileFormat::FileHeader& fileHeader) : fileHeader_{fileHeader} {}
144
145 void reset() {
146 streamIds_.clear();
147 writtenRecords_.clear();
148 writtenBytesCount_ = 0;
149 writtenIndexCount_ = 0;
150 splitHeadFile_.reset();
151 }
152
153 DiskFile& initSplitHead() {
154 splitHeadFile_ = std::make_unique<DiskFile>();
155 return *splitHeadFile_;
156 }
157
158 const std::unique_ptr<DiskFile>& getSplitHead() const {
159 return splitHeadFile_;
160 }
161
162 void addStream(StreamId id) {
163 streamIds_.insert(id);
164 }
165
166 int addRecord(double timestamp, uint32_t size, StreamId id, Record::Type recordType);
167
168 int preallocateClassicIndexRecord(
169 WriteFileHandler& file,
170 const deque<DiskRecordInfo>& preliminaryIndex,
171 uint32_t& outLastRecordSize);
172 void useClassicIndexRecord() {
173 preallocatedIndexRecordSize_ = 0;
174 }
175 int finalizeClassicIndexRecord(
176 WriteFileHandler& file,
177 int64_t endOfRecordsOffset,
178 uint32_t& outLastRecordSize);
179
180 int createSplitIndexRecord(uint32_t& outLastRecordSize);
181 int finalizeSplitIndexRecord(const unique_ptr<NewChunkHandler>& chunkHandler);
182
183 protected:
184 int appendToSplitIndexRecord();
185 int completeSplitIndexRecord();
186
187 private:
188 std::unique_ptr<DiskFile> splitHeadFile_; // When the file head is split from the user records
189 FileFormat::FileHeader& fileHeader_;
190 FileFormat::RecordHeader splitIndexRecordHeader_;
191 uint32_t preallocatedIndexRecordSize_{};
192 Compressor compressor_;
193 set<StreamId> streamIds_;
194 deque<IndexRecord::DiskRecordInfo> writtenRecords_;
195 size_t writtenBytesCount_{}; // how many bytes have been written in a partial index
196 size_t writtenIndexCount_{}; // how many index entries have been written in the partial index
197};
198
200class VRS_API Reader {
201 public:
202 Reader(
203 FileHandler& file,
204 FileFormat::FileHeader& fileHeader,
205 ProgressLogger* progressLogger,
206 set<StreamId>& outStreamIds,
207 vector<RecordInfo>& outIndex);
208
209 bool isIndexComplete() const {
210 return indexComplete_;
211 }
212
213 int readRecord(int64_t firstUserRecordOffset, int64_t& outUsedFileSize);
214
219 int rebuildIndex(bool writeFixedIndex);
220
221 private:
222 int readRecord(
223 int64_t indexRecordOffset,
224 int64_t firstUserRecordOffset,
225 int64_t& outUsedFileSize);
226 int readClassicIndexRecord(
227 size_t indexRecordPayloadSize,
228 size_t uncompressedSize,
229 int64_t firstUserRecordOffset,
230 int64_t& outUsedFileSize);
231 int readSplitIndexRecord(size_t indexByteSize, size_t uncompressedSize, int64_t& outUsedFileSize);
232 int readDiskInfo(vector<DiskRecordInfo>& outRecords);
233 // Index reading helpers extracted to keep CCN within threshold.
234 bool determineSplitIndexLayout(
235 size_t& inOutIndexByteSize,
236 int64_t& outUsedFileSize,
237 bool& outNoRecords);
238 int readSplitIndexData(
239 size_t indexByteSize,
240 size_t uncompressedSize,
241 vector<DiskRecordInfo>& outRecords,
242 bool noRecords);
243 bool processSplitIndexRecords(const vector<DiskRecordInfo>& records, int64_t& outUsedFileSize);
244 int determineClassicIndexLayout(
245 size_t indexRecordPayloadSize,
246 uint32_t& outRecordCount,
247 size_t& outIndexSize);
248 int readClassicIndexData(
249 size_t indexSize,
250 size_t uncompressedSize,
251 uint32_t recordCount,
252 vector<DiskRecordInfo>& outRecords);
253 bool processClassicIndexRecords(
254 const vector<DiskRecordInfo>& records,
255 int64_t fileOffset,
256 int64_t& outUsedFileSize);
257
258 private:
259 FileHandler& file_;
260 const int64_t totalFileSize_;
261 FileFormat::FileHeader& fileHeader_;
262 ProgressLogger* progressLogger_;
263 set<StreamId>& streamIds_;
264 vector<RecordInfo>& index_;
265 unique_ptr<deque<IndexRecord::DiskRecordInfo>> diskIndex_; // only when rewriting the index
266 bool indexComplete_{};
267 bool hasSplitHeadChunk_{};
268 int32_t sortErrorCount_{};
269 int32_t droppedRecordCount_{};
270};
271
273struct VRS_API RecordSignature {
274 StreamId streamId;
275 Record::Type recordType;
276
277 bool operator<(const RecordSignature& rhs) const {
278 return this->recordType < rhs.recordType ||
279 (this->recordType == rhs.recordType && this->streamId < rhs.streamId);
280 }
281};
282
283} // namespace IndexRecord
284
285} // namespace vrs
Helper class to compress data using lz4 or zstd presets.
Definition Compressor.h:83
FileHandler implementation for disk files, with chunked file support.
Definition DiskFile.h:34
Class to abstract VRS file system operations, to enable support for alternate storage methods,...
Definition FileHandler.h:75
Helper class to read VRS index records.
Definition IndexRecord.h:200
Helper class to write VRS index records.
Definition IndexRecord.h:141
ProgressLogger class to be notified of some process' progress.
Definition ProgressLogger.h:33
Essential VRS class holding a record's details and payload in memory during creation.
Definition Record.h:82
Type getRecordType() const
Get the record's record type.
Definition Record.h:150
Type
Definition Record.h:91
double getTimestamp() const
Get the record's timestamp.
Definition Record.h:136
size_t getSize() const
Get the record's payload size, uncompressed.
Definition Record.h:145
VRS stream identifier class.
Definition StreamId.h:251
The WriteFileHandler interface adds write operations to the FileHandler interface.
Definition WriteFileHandler.h:43
@ kSplitIndexFormatVersion
Definition IndexRecord.h:48
@ kClassicIndexFormatVersion
Definition IndexRecord.h:45
Definition Compressor.cpp:113
RecordableTypeId
VRS stream type or class identifier enum.
Definition StreamId.h:51
Every file starts with this header, which may grow but not shrink!
Definition FileFormat.h:61
Every record starts with this header, and is followed by a raw data blob, which semantic is private t...
Definition FileFormat.h:112
Helper class to store details about a single VRS record on disk.
Definition IndexRecord.h:76
Helper class to store StreamID objects on disk.
Definition IndexRecord.h:54
Helper class to hold the details about a single VRS record in memory.
Definition IndexRecord.h:110
double timestamp
timestamp of the record
Definition IndexRecord.h:122
StreamId streamId
creator of the record
Definition IndexRecord.h:124
int64_t fileOffset
absolute byte offset of the record in the whole file
Definition IndexRecord.h:123
This is used to count records to different kinds.
Definition IndexRecord.h:273