-
Notifications
You must be signed in to change notification settings - Fork 119
Expand file tree
/
Copy pathmanifest_entry.h
More file actions
432 lines (382 loc) · 17.9 KB
/
Copy pathmanifest_entry.h
File metadata and controls
432 lines (382 loc) · 17.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#pragma once
/// \file iceberg/manifest/manifest_entry.h
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "iceberg/file_format.h"
#include "iceberg/iceberg_export.h"
#include "iceberg/result.h"
#include "iceberg/row/partition_values.h"
#include "iceberg/schema_field.h"
#include "iceberg/type.h"
namespace iceberg {
enum class ManifestStatus {
kExisting = 0,
kAdded = 1,
kDeleted = 2,
};
/// \brief Get the relative manifest status type from int
ICEBERG_EXPORT constexpr Result<ManifestStatus> ManifestStatusFromInt(
int32_t status) noexcept {
switch (status) {
case 0:
return ManifestStatus::kExisting;
case 1:
return ManifestStatus::kAdded;
case 2:
return ManifestStatus::kDeleted;
default:
return InvalidArgument("Invalid manifest status: {}", status);
}
}
/// \brief DataFile carries data file path, partition tuple, metrics, ...
struct ICEBERG_EXPORT DataFile {
/// \brief Content of a data file
enum class Content {
kData = 0,
kPositionDeletes = 1,
kEqualityDeletes = 2,
};
/// Field id: 134
/// Type of content stored by the data file: data, equality deletes, or position
/// deletes (all v1 files are data files)
Content content = Content::kData;
/// Field id: 100
/// Full URI for the file with FS scheme
std::string file_path;
/// Field id: 101
/// File format type, avro, orc, parquet, or puffin
FileFormatType file_format = FileFormatType::kParquet;
/// Field id: 102
/// Partition data tuple, schema based on the partition spec output using partition
/// field ids
PartitionValues partition;
/// Field id: 103
/// Number of records in this file, or the cardinality of a deletion vector
int64_t record_count = 0;
/// Field id: 104
/// Total file size in bytes
int64_t file_size_in_bytes = 0;
/// Field id: 108
/// Key field id: 117
/// Value field id: 118
/// Map from column id to the total size on disk of all regions that store the column.
/// Does not include bytes necessary to read other columns, like footers. Leave null for
/// row-oriented formats (Avro)
std::map<int32_t, int64_t> column_sizes;
/// Field id: 109
/// Key field id: 119
/// Value field id: 120
/// Map from column id to number of values in the column (including null and NaN values)
std::map<int32_t, int64_t> value_counts;
/// Field id: 110
/// Key field id: 121
/// Value field id: 122
/// Map from column id to number of null values in the column
std::map<int32_t, int64_t> null_value_counts;
/// Field id: 137
/// Key field id: 138
/// Value field id: 139
/// Map from column id to number of NaN values in the column
std::map<int32_t, int64_t> nan_value_counts;
/// Field id: 125
/// Key field id: 126
/// Value field id: 127
/// Map from column id to lower bound in the column serialized as binary.
/// Each value must be less than or equal to all non-null, non-NaN values in the column
/// for the file.
std::map<int32_t, std::vector<uint8_t>> lower_bounds;
/// Field id: 128
/// Key field id: 129
/// Value field id: 130
/// Map from column id to upper bound in the column serialized as binary.
/// Each value must be greater than or equal to all non-null, non-NaN values in the
/// column for the file.
std::map<int32_t, std::vector<uint8_t>> upper_bounds;
/// Field id: 131
/// Implementation-specific key metadata for encryption
std::vector<uint8_t> key_metadata;
/// Field id: 132
/// Element Field id: 133
/// Split offsets for the data file. For example, all row group offsets in a Parquet
/// file. Must be sorted ascending.
std::vector<int64_t> split_offsets;
/// Field id: 135
/// Element Field id: 136
/// Field ids used to determine row equality in equality delete files. Required when
/// content=2 and should be null otherwise. Fields with ids listed in this column must
/// be present in the delete file.
std::vector<int32_t> equality_ids;
/// Field id: 140
/// ID representing sort order for this file
///
/// If sort order ID is missing or unknown, then the order is assumed to be unsorted.
/// Only data files and equality delete files should be written with a non-null order
/// id. Position deletes are required to be sorted by file and position, not a table
/// order, and should set sort order id to null. Readers must ignore sort order id for
/// position delete files.
std::optional<int32_t> sort_order_id;
/// Field id: 142
/// The _row_id for the first row in the data file.
///
/// Reference:
/// - [First Row ID
/// Inheritance](https://github.com/apache/iceberg/blob/main/format/spec.md#first-row-id-inheritance)
std::optional<int64_t> first_row_id;
/// Field id: 143
/// Fully qualified location (URI with FS scheme) of a data file that all deletes
/// reference.
///
/// Position delete metadata can use referenced_data_file when all deletes tracked by
/// the entry are in a single data file. Setting the referenced file is required for
/// deletion vectors.
std::optional<std::string> referenced_data_file;
/// Field id: 144
/// The offset in the file where the content starts.
///
/// The content_offset and content_size_in_bytes fields are used to reference a specific
/// blob for direct access to a deletion vector. For deletion vectors, these values are
/// required and must exactly match the offset and length stored in the Puffin footer
/// for the deletion vector blob.
std::optional<int64_t> content_offset;
/// Field id: 145
/// The length of a referenced content stored in the file; required if content_offset is
/// present
std::optional<int64_t> content_size_in_bytes;
/// \brief Partition spec id for this data file.
/// \note This field is for internal use only and will not be persisted to manifest
/// entry.
std::optional<int32_t> partition_spec_id;
static constexpr int32_t kContentFieldId = 134;
inline static const SchemaField kContent = SchemaField::MakeOptional(
kContentFieldId, "content", int32(),
"Contents of the file: 0=data, 1=position deletes, 2=equality deletes");
static constexpr int32_t kFilePathFieldId = 100;
inline static const SchemaField kFilePath = SchemaField::MakeRequired(
kFilePathFieldId, "file_path", string(), "Location URI with FS scheme");
static constexpr int32_t kFileFormatFieldId = 101;
inline static const SchemaField kFileFormat =
SchemaField::MakeRequired(kFileFormatFieldId, "file_format", string(),
"File format name: avro, orc, or parquet");
static constexpr int32_t kSpecIdFieldId = 141;
inline static const SchemaField kSpecId =
SchemaField::MakeOptional(kSpecIdFieldId, "spec_id", int32(), "Partition spec ID");
static constexpr int32_t kPartitionFieldId = 102;
inline static const std::string kPartitionField = "partition";
inline static const std::string kPartitionDoc =
"Partition data tuple, schema based on the partition spec";
static constexpr int32_t kRecordCountFieldId = 103;
inline static const SchemaField kRecordCount = SchemaField::MakeRequired(
kRecordCountFieldId, "record_count", int64(), "Number of records in the file");
static constexpr int32_t kFileSizeFieldId = 104;
inline static const SchemaField kFileSize = SchemaField::MakeRequired(
kFileSizeFieldId, "file_size_in_bytes", int64(), "Total file size in bytes");
static constexpr int32_t kColumnSizesFieldId = 108;
inline static const SchemaField kColumnSizes = SchemaField::MakeOptional(
kColumnSizesFieldId, "column_sizes",
map(SchemaField::MakeRequired(117, std::string(MapType::kKeyName), int32()),
SchemaField::MakeRequired(118, std::string(MapType::kValueName), int64())),
"Map of column id to total size on disk");
static constexpr int32_t kValueCountsFieldId = 109;
inline static const SchemaField kValueCounts = SchemaField::MakeOptional(
kValueCountsFieldId, "value_counts",
map(SchemaField::MakeRequired(119, std::string(MapType::kKeyName), int32()),
SchemaField::MakeRequired(120, std::string(MapType::kValueName), int64())),
"Map of column id to total count, including null and NaN");
static constexpr int32_t kNullValueCountsFieldId = 110;
inline static const SchemaField kNullValueCounts = SchemaField::MakeOptional(
kNullValueCountsFieldId, "null_value_counts",
map(SchemaField::MakeRequired(121, std::string(MapType::kKeyName), int32()),
SchemaField::MakeRequired(122, std::string(MapType::kValueName), int64())),
"Map of column id to null value count");
static constexpr int32_t kNanValueCountsFieldId = 137;
inline static const SchemaField kNanValueCounts = SchemaField::MakeOptional(
kNanValueCountsFieldId, "nan_value_counts",
map(SchemaField::MakeRequired(138, std::string(MapType::kKeyName), int32()),
SchemaField::MakeRequired(139, std::string(MapType::kValueName), int64())),
"Map of column id to number of NaN values in the column");
static constexpr int32_t kLowerBoundsFieldId = 125;
inline static const SchemaField kLowerBounds = SchemaField::MakeOptional(
kLowerBoundsFieldId, "lower_bounds",
map(SchemaField::MakeRequired(126, std::string(MapType::kKeyName), int32()),
SchemaField::MakeRequired(127, std::string(MapType::kValueName), binary())),
"Map of column id to lower bound");
static constexpr int32_t kUpperBoundsFieldId = 128;
inline static const SchemaField kUpperBounds = SchemaField::MakeOptional(
kUpperBoundsFieldId, "upper_bounds",
map(SchemaField::MakeRequired(129, std::string(MapType::kKeyName), int32()),
SchemaField::MakeRequired(130, std::string(MapType::kValueName), binary())),
"Map of column id to upper bound");
static constexpr int32_t kKeyMetadataFieldId = 131;
inline static const SchemaField kKeyMetadata = SchemaField::MakeOptional(
kKeyMetadataFieldId, "key_metadata", binary(), "Encryption key metadata blob");
static constexpr int32_t kSplitOffsetsFieldId = 132;
inline static const SchemaField kSplitOffsets = SchemaField::MakeOptional(
kSplitOffsetsFieldId, "split_offsets",
list(SchemaField::MakeRequired(133, std::string(ListType::kElementName), int64())),
"Splittable offsets");
static constexpr int32_t kEqualityIdsFieldId = 135;
inline static const SchemaField kEqualityIds = SchemaField::MakeOptional(
kEqualityIdsFieldId, "equality_ids",
list(SchemaField::MakeRequired(136, std::string(ListType::kElementName), int32())),
"Equality comparison field IDs");
static constexpr int32_t kSortOrderIdFieldId = 140;
inline static const SchemaField kSortOrderId = SchemaField::MakeOptional(
kSortOrderIdFieldId, "sort_order_id", int32(), "Sort order ID");
static constexpr int32_t kFirstRowIdFieldId = 142;
inline static const SchemaField kFirstRowId =
SchemaField::MakeOptional(kFirstRowIdFieldId, "first_row_id", int64(),
"Starting row ID to assign to new rows");
static constexpr int32_t kReferencedDataFileFieldId = 143;
inline static const SchemaField kReferencedDataFile = SchemaField::MakeOptional(
kReferencedDataFileFieldId, "referenced_data_file", string(),
"Fully qualified location (URI with FS scheme) of a data file that all deletes "
"reference");
static constexpr int32_t kContentOffsetFieldId = 144;
inline static const SchemaField kContentOffset =
SchemaField::MakeOptional(kContentOffsetFieldId, "content_offset", int64(),
"The offset in the file where the content starts");
static constexpr int32_t kContentSizeFieldId = 145;
inline static const SchemaField kContentSize =
SchemaField::MakeOptional(kContentSizeFieldId, "content_size_in_bytes", int64(),
"The length of referenced content stored in the file");
bool operator==(const DataFile& other) const = default;
/// \brief Get the schema of the data file with the given partition type.
static std::shared_ptr<StructType> Type(std::shared_ptr<StructType> partition_type);
/// \brief Check if this data file is a deletion vector.
bool IsDeletionVector() const {
return content == Content::kPositionDeletes && file_format == FileFormatType::kPuffin;
}
};
/// \brief A manifest is an immutable Avro file that lists data files or delete files,
/// along with each file's partition data tuple, metrics, and tracking information.
/// \brief The schema of a manifest file
struct ICEBERG_EXPORT ManifestEntry {
/// Field id: 0
/// Used to track additions and deletions. Deletes are informational only and not used
/// in scans.
ManifestStatus status = ManifestStatus::kAdded;
/// Field id: 1
/// Snapshot id where the file was added, or deleted if status is 2. Inherited when
/// null.
std::optional<int64_t> snapshot_id;
/// Field id: 3
/// Data sequence number of the file.
///
/// Independently of the entry status, it represents the sequence number to which the
/// file should apply. Note the data sequence number may differ from the sequence number
/// of the snapshot in which the underlying file was added. New snapshots can add files
/// that belong to older sequence numbers (e.g. compaction). The data sequence number
/// also does not change when the file is marked as deleted.
///
/// \note It can return nullopt if the data sequence number is unknown. This may happen
/// while reading a v2 manifest that did not persist the data sequence number for
/// manifest entries with status DELETED (older Iceberg versions).
std::optional<int64_t> sequence_number;
/// Field id: 4
/// The file sequence number.
///
/// The file sequence number represents the sequence number of the snapshot in which the
/// underlying file was added. The file sequence number is always assigned at commit and
/// cannot be provided explicitly, unlike the data sequence number. The file sequence
/// number does not change upon assigning and must be preserved in existing and deleted
/// entries.
///
/// \note It can return nullopt if the file sequence number is unknown. This may happen
/// while reading a v2 manifest that did not persist the file sequence number for
/// manifest entries with status EXISTING or DELETED (older Iceberg versions).
std::optional<int64_t> file_sequence_number;
/// Field id: 2
/// File path, partition tuple, metrics, ...
std::shared_ptr<DataFile> data_file;
static constexpr int32_t kStatusFieldId = 0;
inline static const SchemaField kStatus =
SchemaField::MakeRequired(kStatusFieldId, "status", int32());
static constexpr int32_t kSnapshotIdFieldId = 1;
inline static const SchemaField kSnapshotId =
SchemaField::MakeOptional(kSnapshotIdFieldId, "snapshot_id", int64());
static constexpr int32_t kDataFileFieldId = 2;
inline static const std::string kDataFileField = "data_file";
static constexpr int32_t kSequenceNumberFieldId = 3;
inline static const SchemaField kSequenceNumber =
SchemaField::MakeOptional(kSequenceNumberFieldId, "sequence_number", int64());
static constexpr int32_t kFileSequenceNumberFieldId = 4;
inline static const SchemaField kFileSequenceNumber = SchemaField::MakeOptional(
kFileSequenceNumberFieldId, "file_sequence_number", int64());
/// \brief Check if this manifest entry is deleted.
constexpr bool IsAlive() const {
return status == ManifestStatus::kAdded || status == ManifestStatus::kExisting;
}
ManifestEntry AsAdded() const {
ManifestEntry copy = *this;
copy.status = ManifestStatus::kAdded;
if (copy.data_file != nullptr && copy.data_file->first_row_id.has_value()) {
copy.data_file = std::make_unique<DataFile>(*copy.data_file);
copy.data_file->first_row_id = std::nullopt;
}
return copy;
}
ManifestEntry AsExisting() const {
ManifestEntry copy = *this;
copy.status = ManifestStatus::kExisting;
return copy;
}
ManifestEntry AsDeleted() const {
ManifestEntry copy = *this;
copy.status = ManifestStatus::kDeleted;
return copy;
}
bool operator==(const ManifestEntry& other) const;
static std::shared_ptr<StructType> TypeFromPartitionType(
std::shared_ptr<StructType> partition_type);
static std::shared_ptr<StructType> TypeFromDataFileType(
std::shared_ptr<StructType> datafile_type);
};
/// \brief Get the relative datafile content type name
ICEBERG_EXPORT constexpr std::string_view ToString(DataFile::Content type) noexcept {
switch (type) {
case DataFile::Content::kData:
return "data";
case DataFile::Content::kPositionDeletes:
return "position_deletes";
case DataFile::Content::kEqualityDeletes:
return "equality_deletes";
}
std::unreachable();
}
/// \brief Get the relative data file content type from int
ICEBERG_EXPORT constexpr Result<DataFile::Content> DataFileContentFromInt(
int32_t content) noexcept {
switch (content) {
case 0:
return DataFile::Content::kData;
case 1:
return DataFile::Content::kPositionDeletes;
case 2:
return DataFile::Content::kEqualityDeletes;
default:
return InvalidArgument("Invalid data file content: {}", content);
}
}
} // namespace iceberg