Skip to content

Commit 86a1f03

Browse files
committed
feat(io): add bulk delete API to FileIO.
1 parent 0ca52ba commit 86a1f03

4 files changed

Lines changed: 93 additions & 1 deletion

File tree

src/iceberg/file_io.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,27 @@ class ICEBERG_EXPORT FileIO {
151151
///
152152
/// \param file_location The location of the file to delete.
153153
/// \return void if the delete succeeded, an error code if the delete failed.
154-
virtual Status DeleteFile(const std::string& file_location) {
154+
virtual Status DeleteFile(const std::string&) {
155155
return NotImplemented("DeleteFile not implemented");
156156
}
157+
158+
/// \brief Delete files at the given locations.
159+
///
160+
/// Implementations that can delete multiple files efficiently should override this
161+
/// method. The default implementation deletes files sequentially using DeleteFile
162+
/// and returns the first error encountered.
163+
///
164+
/// \param file_locations The locations of the files to delete.
165+
/// \return void if all deletes succeeded, an error code if any delete failed.
166+
virtual Status DeleteFiles(std::span<const std::string> file_locations) {
167+
for (const auto& file_location : file_locations) {
168+
auto status = DeleteFile(file_location);
169+
if (!status.has_value()) {
170+
return status;
171+
}
172+
}
173+
return {};
174+
}
157175
};
158176

159177
} // namespace iceberg

src/iceberg/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ add_iceberg_test(util_test
124124
data_file_set_test.cc
125125
decimal_test.cc
126126
endian_test.cc
127+
file_io_test.cc
127128
formatter_test.cc
128129
lazy_test.cc
129130
location_util_test.cc

src/iceberg/test/file_io_test.cc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/file_io.h"
21+
22+
#include <string>
23+
#include <utility>
24+
#include <vector>
25+
26+
#include <gtest/gtest.h>
27+
28+
#include "iceberg/test/matchers.h"
29+
30+
namespace iceberg {
31+
namespace {
32+
33+
class RecordingFileIO : public FileIO {
34+
public:
35+
explicit RecordingFileIO(std::string failure_path = "")
36+
: failure_path_(std::move(failure_path)) {}
37+
38+
Status DeleteFile(const std::string& file_location) override {
39+
deleted_paths.push_back(file_location);
40+
if (file_location == failure_path_) {
41+
return IOError("failed to delete {}", file_location);
42+
}
43+
return {};
44+
}
45+
46+
std::vector<std::string> deleted_paths;
47+
48+
private:
49+
std::string failure_path_;
50+
};
51+
52+
TEST(FileIOTest, DeleteFilesFallsBackToDeleteFileForEachPath) {
53+
RecordingFileIO file_io;
54+
std::vector<std::string> paths = {"file-a.avro", "file-b.avro"};
55+
56+
EXPECT_THAT(file_io.DeleteFiles(paths), IsOk());
57+
EXPECT_THAT(file_io.deleted_paths, ::testing::ElementsAre("file-a.avro", "file-b.avro"));
58+
}
59+
60+
TEST(FileIOTest, DeleteFilesReturnsFirstDeleteFileError) {
61+
RecordingFileIO file_io("file-b.avro");
62+
std::vector<std::string> paths = {"file-a.avro", "file-b.avro", "file-c.avro"};
63+
64+
auto status = file_io.DeleteFiles(paths);
65+
66+
EXPECT_THAT(status, IsError(ErrorKind::kIOError));
67+
EXPECT_THAT(status, HasErrorMessage("failed to delete file-b.avro"));
68+
EXPECT_THAT(file_io.deleted_paths, ::testing::ElementsAre("file-a.avro", "file-b.avro"));
69+
}
70+
71+
} // namespace
72+
} // namespace iceberg

src/iceberg/test/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ iceberg_tests = {
8888
'data_file_set_test.cc',
8989
'decimal_test.cc',
9090
'endian_test.cc',
91+
'file_io_test.cc',
9192
'formatter_test.cc',
9293
'lazy_test.cc',
9394
'location_util_test.cc',

0 commit comments

Comments
 (0)