Skip to content

Commit cfb7854

Browse files
committed
minor fixes and refine comments
1 parent 5e56025 commit cfb7854

8 files changed

Lines changed: 112 additions & 51 deletions

src/iceberg/test/merge_append_test.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,13 @@ class MergeAppendTestBase : public UpdateTestBase {
269269
// both the main branch and a named branch without per-call boilerplate.
270270
Result<std::shared_ptr<MergeAppend>> NewBranchMergeAppend() {
271271
ICEBERG_ASSIGN_OR_RAISE(auto append, table_->NewMergeAppend());
272-
append->SetTargetBranch(branch());
272+
append->ToBranch(branch());
273273
return append;
274274
}
275275

276276
Result<std::shared_ptr<FastAppend>> NewBranchFastAppend() {
277277
ICEBERG_ASSIGN_OR_RAISE(auto append, table_->NewFastAppend());
278-
append->SetTargetBranch(branch());
278+
append->ToBranch(branch());
279279
return append;
280280
}
281281

@@ -1127,7 +1127,7 @@ TEST_P(MergeAppendTest, Failure) {
11271127

11281128
ICEBERG_UNWRAP_OR_FAIL(auto txn, table_->NewTransaction());
11291129
ICEBERG_UNWRAP_OR_FAIL(auto append, txn->NewMergeAppend());
1130-
append->SetTargetBranch(branch());
1130+
append->ToBranch(branch());
11311131
append->AppendFile(file_b_);
11321132
EXPECT_THAT(append->Commit(), IsOk());
11331133

@@ -1166,7 +1166,7 @@ TEST_P(MergeAppendTest, AppendManifestCleanup) {
11661166

11671167
ICEBERG_UNWRAP_OR_FAIL(auto txn, table_->NewTransaction());
11681168
ICEBERG_UNWRAP_OR_FAIL(auto append, txn->NewMergeAppend());
1169-
append->SetTargetBranch(branch());
1169+
append->ToBranch(branch());
11701170
append->AppendManifest(manifest);
11711171
EXPECT_THAT(append->Commit(), IsOk());
11721172

@@ -1215,7 +1215,7 @@ TEST_P(MergeAppendTest, Recovery) {
12151215

12161216
ICEBERG_UNWRAP_OR_FAIL(auto txn, table_->NewTransaction());
12171217
ICEBERG_UNWRAP_OR_FAIL(auto append, txn->NewMergeAppend());
1218-
append->SetTargetBranch(branch());
1218+
append->ToBranch(branch());
12191219
append->AppendFile(file_b_);
12201220
EXPECT_THAT(append->Commit(), IsOk());
12211221

@@ -1336,7 +1336,7 @@ TEST_P(MergeAppendTest, AppendManifestFailureWithSnapshotIdInheritance) {
13361336
TEST_P(MergeAppendTest, TransactionNewMergeAppendCommits) {
13371337
ICEBERG_UNWRAP_OR_FAIL(auto txn, table_->NewTransaction());
13381338
ICEBERG_UNWRAP_OR_FAIL(auto append, txn->NewMergeAppend());
1339-
append->SetTargetBranch(branch());
1339+
append->ToBranch(branch());
13401340
append->AppendFile(file_a_);
13411341
EXPECT_THAT(append->Commit(), IsOk());
13421342
ICEBERG_UNWRAP_OR_FAIL(auto committed_table, txn->Commit());

src/iceberg/test/overwrite_files_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ TEST_F(OverwriteFilesTest, TargetBranch) {
243243
CommitFileA();
244244

245245
ICEBERG_UNWRAP_OR_FAIL(auto op, NewOverwrite());
246-
op->SetTargetBranch("audit");
246+
op->ToBranch("audit");
247247
op->AddFile(file_b_);
248248
EXPECT_THAT(op->Commit(), IsOk());
249249

src/iceberg/test/rewrite_files_test.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,44 @@ TEST_P(RewriteFilesFormatVersionTest, DeleteDataFileCopiesCallerFile) {
307307
EXPECT_THAT(result, HasErrorMessage("Missing required files to delete"));
308308
}
309309

310+
TEST_P(RewriteFilesFormatVersionTest, AddDataFileRejectsDeleteFileContent) {
311+
CommitFileA();
312+
313+
ICEBERG_UNWRAP_OR_FAIL(auto rw, NewRewriteFiles());
314+
rw->DeleteDataFile(file_a_);
315+
rw->AddDataFile(delete_file_a_);
316+
auto result = rw->Commit();
317+
EXPECT_THAT(result, IsError(ErrorKind::kValidationFailed));
318+
EXPECT_THAT(result, HasErrorMessage("Invalid data file to add"));
319+
}
320+
321+
TEST_P(RewriteFilesFormatVersionTest, RewriteDeleteFilesCopiesCallerFiles) {
322+
AssumeFormatVersionAtLeast(2);
323+
CommitFileA();
324+
325+
{
326+
ICEBERG_UNWRAP_OR_FAIL(auto row_delta, table_->NewRowDelta());
327+
row_delta->AddDeletes(delete_file_a_);
328+
EXPECT_THAT(row_delta->Commit(), IsOk());
329+
EXPECT_THAT(table_->Refresh(), IsOk());
330+
}
331+
332+
ICEBERG_UNWRAP_OR_FAIL(auto after_delta_snapshot, table_->current_snapshot());
333+
auto old_delete = std::make_shared<DataFile>(*delete_file_a_);
334+
auto new_delete = std::make_shared<DataFile>(*rewritten_delete_file_a_);
335+
336+
ICEBERG_UNWRAP_OR_FAIL(auto rw, NewRewriteFiles());
337+
rw->ValidateFromSnapshot(after_delta_snapshot->snapshot_id);
338+
rw->DeleteDeleteFile(old_delete);
339+
rw->AddDeleteFile(new_delete);
340+
341+
old_delete->file_path = table_location_ + "/data/delete_a_mutated.parquet";
342+
new_delete->content = DataFile::Content::kData;
343+
344+
EXPECT_THAT(rw->Commit(), IsOk());
345+
EXPECT_THAT(table_->Refresh(), IsOk());
346+
}
347+
310348
// Rewrite one of several data files, verifying only the target is affected.
311349
TEST_P(RewriteFilesFormatVersionTest, AddAndDeletePartialRewrite) {
312350
CommitFileA();

src/iceberg/update/merging_snapshot_update.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,10 @@ Status MergingSnapshotUpdate::AddDeleteFile(std::shared_ptr<DataFile> file,
540540
return InvalidArgument("Delete file must have a partition spec ID");
541541
}
542542
ICEBERG_RETURN_UNEXPECTED(base().PartitionSpecById(file->partition_spec_id.value()));
543+
544+
auto staged_file = std::make_shared<DataFile>(*file);
543545
has_new_delete_files_ = true;
544-
PendingDeleteFile pending_file{.file = std::move(file),
546+
PendingDeleteFile pending_file{.file = std::move(staged_file),
545547
.data_sequence_number = std::move(data_sequence_number)};
546548
if (ContentFileUtil::IsDV(*pending_file.file)) {
547549
ICEBERG_PRECHECK(pending_file.file->referenced_data_file.has_value(),
@@ -559,14 +561,16 @@ Status MergingSnapshotUpdate::DeleteDataFile(std::shared_ptr<DataFile> file) {
559561
if (!file) {
560562
return InvalidArgument("Cannot delete a null data file");
561563
}
562-
return data_filter_manager_->DeleteFile(std::move(file));
564+
auto staged_file = std::make_shared<DataFile>(*file);
565+
return data_filter_manager_->DeleteFile(std::move(staged_file));
563566
}
564567

565568
Status MergingSnapshotUpdate::DeleteDeleteFile(std::shared_ptr<DataFile> file) {
566569
if (!file) {
567570
return InvalidArgument("Cannot delete a null delete file");
568571
}
569-
return delete_filter_manager_->DeleteFile(std::move(file));
572+
auto staged_file = std::make_shared<DataFile>(*file);
573+
return delete_filter_manager_->DeleteFile(std::move(staged_file));
570574
}
571575

572576
Status MergingSnapshotUpdate::DeleteByPath(std::string_view path) {

src/iceberg/update/rewrite_files.cc

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,31 +48,49 @@ Result<std::unique_ptr<RewriteFiles>> RewriteFiles::Make(
4848
}
4949

5050
RewriteFiles& RewriteFiles::DeleteDataFile(const std::shared_ptr<DataFile>& data_file) {
51-
auto staged_file =
52-
data_file == nullptr ? nullptr : std::make_shared<DataFile>(*data_file);
53-
ICEBERG_BUILDER_RETURN_IF_ERROR(MergingSnapshotUpdate::DeleteDataFile(staged_file));
54-
replaced_data_files_.insert(std::move(staged_file));
51+
ICEBERG_BUILDER_CHECK(data_file != nullptr, "Invalid data file: null");
52+
ICEBERG_BUILDER_CHECK(data_file->content == DataFile::Content::kData,
53+
"Invalid data file to delete: {} has delete-file content",
54+
data_file->file_path);
55+
ICEBERG_BUILDER_RETURN_IF_ERROR(MergingSnapshotUpdate::DeleteDataFile(data_file));
56+
replaced_data_files_.insert(std::make_shared<DataFile>(*data_file));
5557
return *this;
5658
}
5759

5860
RewriteFiles& RewriteFiles::DeleteDeleteFile(
5961
const std::shared_ptr<DataFile>& delete_file) {
62+
ICEBERG_BUILDER_CHECK(delete_file != nullptr, "Invalid delete file: null");
63+
ICEBERG_BUILDER_CHECK(delete_file->content != DataFile::Content::kData,
64+
"Invalid delete file to delete: {} has data-file content",
65+
delete_file->file_path);
6066
ICEBERG_BUILDER_RETURN_IF_ERROR(MergingSnapshotUpdate::DeleteDeleteFile(delete_file));
6167
return *this;
6268
}
6369

6470
RewriteFiles& RewriteFiles::AddDataFile(const std::shared_ptr<DataFile>& file) {
71+
ICEBERG_BUILDER_CHECK(file != nullptr, "Invalid data file: null");
72+
ICEBERG_BUILDER_CHECK(file->content == DataFile::Content::kData,
73+
"Invalid data file to add: {} has delete-file content",
74+
file->file_path);
6575
ICEBERG_BUILDER_RETURN_IF_ERROR(MergingSnapshotUpdate::AddDataFile(file));
6676
return *this;
6777
}
6878

6979
RewriteFiles& RewriteFiles::AddDeleteFile(const std::shared_ptr<DataFile>& delete_file) {
80+
ICEBERG_BUILDER_CHECK(delete_file != nullptr, "Invalid delete file: null");
81+
ICEBERG_BUILDER_CHECK(delete_file->content != DataFile::Content::kData,
82+
"Invalid delete file to add: {} has data-file content",
83+
delete_file->file_path);
7084
ICEBERG_BUILDER_RETURN_IF_ERROR(MergingSnapshotUpdate::AddDeleteFile(delete_file));
7185
return *this;
7286
}
7387

7488
RewriteFiles& RewriteFiles::AddDeleteFile(const std::shared_ptr<DataFile>& delete_file,
7589
int64_t data_sequence_number) {
90+
ICEBERG_BUILDER_CHECK(delete_file != nullptr, "Invalid delete file: null");
91+
ICEBERG_BUILDER_CHECK(delete_file->content != DataFile::Content::kData,
92+
"Invalid delete file to add: {} has data-file content",
93+
delete_file->file_path);
7694
ICEBERG_BUILDER_RETURN_IF_ERROR(
7795
MergingSnapshotUpdate::AddDeleteFile(delete_file, data_sequence_number));
7896
return *this;
@@ -120,11 +138,6 @@ RewriteFiles& RewriteFiles::ValidateFromSnapshot(int64_t snapshot_id) {
120138
return *this;
121139
}
122140

123-
RewriteFiles& RewriteFiles::ToBranch(const std::string& branch) {
124-
SetTargetBranch(branch);
125-
return *this;
126-
}
127-
128141
std::string RewriteFiles::operation() { return DataOperation::kReplace; }
129142

130143
void RewriteFiles::ValidateReplacedAndAddedFiles() {
@@ -153,18 +166,12 @@ void RewriteFiles::ValidateReplacedAndAddedFiles() {
153166

154167
Status RewriteFiles::Validate(const TableMetadata& current_metadata,
155168
const std::shared_ptr<Snapshot>& snapshot) {
156-
// Step 1: Validate the replaced and added files invariants
157-
ValidateReplacedAndAddedFiles();
158169
ICEBERG_RETURN_UNEXPECTED(CheckErrors());
170+
ValidateReplacedAndAddedFiles();
159171

160-
// Step 2: If there are replaced data files, validate no new row-level deletes
161-
// for those data files have been added concurrently
162172
if (!replaced_data_files_.empty()) {
163-
// The instance method automatically determines ignore_equality_deletes
164-
// based on whether SetDataSequenceNumber was called:
165-
// - If data sequence number was set, equality deletes at higher sequence
166-
// numbers still correctly apply to the new files → ignore them.
167-
// - If no sequence number was set, ALL new deletes are conflicts.
173+
// If there are replaced data files, there cannot be any new row-level deletes
174+
// for those data files.
168175
auto io = ctx_->table->io();
169176
ICEBERG_RETURN_UNEXPECTED(MergingSnapshotUpdate::ValidateNoNewDeletesForDataFiles(
170177
current_metadata, starting_snapshot_id_, replaced_data_files_, snapshot,

src/iceberg/update/rewrite_files.h

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ namespace iceberg {
3737

3838
/// \brief API for replacing files in a table.
3939
///
40-
/// This operation accumulates file additions and deletions, produces a new
41-
/// Snapshot of the changes, and commits that snapshot as the current.
40+
/// This API accumulates file additions and deletions, produces a new Snapshot
41+
/// of the changes, and commits that snapshot as the current.
4242
///
4343
/// When committing, these changes will be applied to the latest table snapshot.
4444
/// Commit conflicts will be resolved by applying the changes to the new latest
4545
/// snapshot and reattempting the commit. If any of the deleted files are no
46-
/// longer in the latest snapshot when reattempting, the commit will throw a
47-
/// ValidationException.
46+
/// longer in the latest snapshot when reattempting, the commit will fail
47+
/// validation.
4848
///
4949
/// Note that the new state of the table after each rewrite must be logically
5050
/// equivalent to the original table state.
@@ -63,7 +63,9 @@ class ICEBERG_EXPORT RewriteFiles : public MergingSnapshotUpdate {
6363
/// \brief Remove a data file from the current table state.
6464
///
6565
/// This rewrite operation may change the size or layout of the data files.
66-
/// The set of live data records must never change.
66+
/// When applicable, it is also recommended to discard already deleted records
67+
/// while rewriting data files. However, the set of live data records must
68+
/// never change.
6769
///
6870
/// \param data_file a rewritten data file
6971
/// \return this for method chaining
@@ -72,32 +74,47 @@ class ICEBERG_EXPORT RewriteFiles : public MergingSnapshotUpdate {
7274
/// \brief Remove a delete file from the table state.
7375
///
7476
/// This rewrite operation may change the size or layout of the delete files.
75-
/// The set of applicable delete records must never change.
77+
/// When applicable, it is also recommended to discard delete records for files
78+
/// that are no longer part of the table state. However, the set of applicable
79+
/// delete records must never change.
7680
///
7781
/// \param delete_file a rewritten delete file
7882
/// \return this for method chaining
7983
RewriteFiles& DeleteDeleteFile(const std::shared_ptr<DataFile>& delete_file);
8084

81-
/// \brief Add a new data file or delete file.
85+
/// \brief Add a new data file.
8286
///
83-
/// This rewrite operation may change the size or layout of the files.
84-
/// The set of live data records must never change.
87+
/// This rewrite operation may change the size or layout of the data files.
88+
/// When applicable, it is also recommended to discard already deleted records
89+
/// while rewriting data files. However, the set of live data records must
90+
/// never change.
8591
///
86-
/// \param file a new file (data or delete)
92+
/// \param file a new data file
8793
/// \return this for method chaining
8894
RewriteFiles& AddDataFile(const std::shared_ptr<DataFile>& file);
8995

9096
/// \brief Add a new delete file.
9197
///
98+
/// This rewrite operation may change the size or layout of the delete files.
99+
/// When applicable, it is also recommended to discard delete records for files
100+
/// that are no longer part of the table state. However, the set of applicable
101+
/// delete records must never change.
102+
///
92103
/// \param delete_file a new delete file
93104
/// \return this for method chaining
94105
RewriteFiles& AddDeleteFile(const std::shared_ptr<DataFile>& delete_file);
95106

96107
/// \brief Add a new delete file with the given data sequence number.
97108
///
109+
/// This rewrite operation may change the size or layout of the delete files.
110+
/// When applicable, it is also recommended to discard delete records for files
111+
/// that are no longer part of the table state. However, the set of applicable
112+
/// delete records must never change.
113+
///
98114
/// To ensure equivalence in the set of applicable delete records, the
99115
/// sequence number of the delete file must be the max sequence number of
100-
/// the delete files that it is replacing.
116+
/// the delete files that it is replacing. Rewriting equality deletes that
117+
/// belong to different sequence numbers is not allowed.
101118
///
102119
/// \param delete_file a new delete file
103120
/// \param data_sequence_number data sequence number to append on the file
@@ -108,8 +125,8 @@ class ICEBERG_EXPORT RewriteFiles : public MergingSnapshotUpdate {
108125
/// \brief Configure the data sequence number for this rewrite operation.
109126
///
110127
/// This data sequence number will be used for all new data files that are
111-
/// added in this rewrite. This is helpful to avoid commit conflicts between
112-
/// data compaction and adding equality deletes.
128+
/// added in this rewrite. This method is helpful to avoid commit conflicts
129+
/// between data compaction and adding equality deletes.
113130
///
114131
/// \param sequence_number a data sequence number
115132
/// \return this for method chaining
@@ -119,8 +136,9 @@ class ICEBERG_EXPORT RewriteFiles : public MergingSnapshotUpdate {
119136
/// that contains the same data. The sequence number provided will be used for
120137
/// all the data files added.
121138
///
122-
/// \param files_to_delete files that will be replaced (deleted)
123-
/// \param files_to_add files that will be added
139+
/// \param files_to_delete files that will be replaced (deleted), cannot be
140+
/// null or empty
141+
/// \param files_to_add files that will be added, cannot be null or empty
124142
/// \param sequence_number sequence number to use for all data files added
125143
/// \return this for method chaining
126144
RewriteFiles& RewriteDataFiles(
@@ -152,12 +170,6 @@ class ICEBERG_EXPORT RewriteFiles : public MergingSnapshotUpdate {
152170
/// \return this for method chaining
153171
RewriteFiles& ValidateFromSnapshot(int64_t snapshot_id);
154172

155-
/// \brief Perform operations on a particular branch.
156-
///
157-
/// \param branch name of a SnapshotRef of type branch
158-
/// \return this for method chaining
159-
RewriteFiles& ToBranch(const std::string& branch);
160-
161173
std::string operation() override;
162174

163175
protected:

src/iceberg/update/snapshot_manager.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ SnapshotManager& SnapshotManager::CreateBranch(const std::string& name) {
9393
}
9494
ICEBERG_BUILDER_CHECK(!base.refs.contains(name), "Ref {} already exists", name);
9595
ICEBERG_BUILDER_ASSIGN_OR_RETURN(auto fast_append, transaction_->NewFastAppend());
96-
ICEBERG_BUILDER_RETURN_IF_ERROR(fast_append->SetTargetBranch(name).Commit());
96+
ICEBERG_BUILDER_RETURN_IF_ERROR(fast_append->ToBranch(name).Commit());
9797
return *this;
9898
}
9999

src/iceberg/update/snapshot_update.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class ICEBERG_EXPORT SnapshotUpdate : public PendingUpdate {
9696
///
9797
/// \param branch The name of a SnapshotRef of type branch.
9898
/// \return This update for method chaining.
99-
auto& SetTargetBranch(this auto& self, const std::string& branch) {
99+
auto& ToBranch(this auto& self, const std::string& branch) {
100100
if (branch.empty()) [[unlikely]] {
101101
return self.AddError(ErrorKind::kInvalidArgument, "Branch name cannot be empty");
102102
}

0 commit comments

Comments
 (0)