| /* |
| * 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. |
| */ |
| |
| #include <algorithm> |
| #include <chrono> |
| #include <limits> |
| #include <mutex> |
| #include <optional> |
| #include <vector> |
| |
| #include <arrow/buffer.h> |
| #include <arrow/filesystem/localfs.h> |
| #include <arrow/filesystem/mockfs.h> |
| #include <arrow/io/interfaces.h> |
| #include <arrow/result.h> |
| #include <arrow/status.h> |
| #include <arrow/util/uri.h> |
| |
| #include "iceberg/arrow/arrow_io_internal.h" |
| #include "iceberg/arrow/arrow_io_util.h" |
| #include "iceberg/arrow/arrow_status_internal.h" |
| #include "iceberg/util/macros.h" |
| |
| namespace iceberg::arrow { |
| |
| namespace { |
| |
| Result<int64_t> ToInt64Length(size_t length) { |
| if (length > static_cast<size_t>(std::numeric_limits<int64_t>::max())) { |
| return InvalidArgument("File length {} exceeds int64_t max", length); |
| } |
| return static_cast<int64_t>(length); |
| } |
| |
| ::arrow::Status ToArrowStatus(const Error& error) { |
| switch (error.kind) { |
| case ErrorKind::kInvalid: |
| case ErrorKind::kInvalidArgument: |
| return ::arrow::Status::Invalid(error.message); |
| case ErrorKind::kNotImplemented: |
| case ErrorKind::kNotSupported: |
| return ::arrow::Status::NotImplemented(error.message); |
| default: |
| return ::arrow::Status::IOError(error.message); |
| } |
| } |
| |
| ::arrow::Result<int64_t> BytesToReadAt(int64_t position, int64_t nbytes, int64_t size) { |
| if (position < 0 || nbytes < 0) { |
| return ::arrow::Status::Invalid("ReadAt position and length must be non-negative"); |
| } |
| if (position > size) { |
| return ::arrow::Status::IOError("Read out of bounds (offset = ", position, |
| ", size = ", nbytes, ") in file of size ", size); |
| } |
| return std::min(nbytes, size - position); |
| } |
| |
| /// Adapts the generic Iceberg input stream API to Arrow's RandomAccessFile API. |
| /// |
| /// Avro and Parquet readers in the bundle layer consume Arrow IO streams. This |
| /// fallback keeps those readers usable with non-Arrow FileIO implementations without |
| /// exposing Arrow filesystem details through the generic FileIO interface. |
| class InputStreamAdapter : public ::arrow::io::RandomAccessFile { |
| public: |
| InputStreamAdapter(std::unique_ptr<SeekableInputStream> input, int64_t size) |
| : input_(std::move(input)), size_(size) { |
| RandomAccessFile::set_mode(::arrow::io::FileMode::READ); |
| } |
| |
| ::arrow::Status Close() override { |
| std::lock_guard lock(mutex_); |
| if (closed_) { |
| return ::arrow::Status::OK(); |
| } |
| auto status = input_->Close(); |
| if (!status.has_value()) { |
| return ToArrowStatus(status.error()); |
| } |
| closed_ = true; |
| return ::arrow::Status::OK(); |
| } |
| |
| ::arrow::Result<int64_t> Tell() const override { |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| auto position = input_->Position(); |
| if (!position.has_value()) { |
| return ToArrowStatus(position.error()); |
| } |
| if (position.value() < 0) { |
| return ::arrow::Status::IOError("FileIO input stream returned negative position"); |
| } |
| return position.value(); |
| } |
| |
| bool closed() const override { |
| std::lock_guard lock(mutex_); |
| return closed_; |
| } |
| |
| ::arrow::Status Seek(int64_t position) override { |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| auto status = input_->Seek(position); |
| if (!status.has_value()) { |
| return ToArrowStatus(status.error()); |
| } |
| return ::arrow::Status::OK(); |
| } |
| |
| ::arrow::Result<int64_t> Read(int64_t nbytes, void* out) override { |
| if (nbytes < 0) { |
| return ::arrow::Status::Invalid("Cannot read a negative number of bytes"); |
| } |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| if (nbytes == 0) { |
| return 0; |
| } |
| auto data = reinterpret_cast<std::byte*>(out); |
| auto result = input_->Read(std::span(data, static_cast<size_t>(nbytes))); |
| if (!result.has_value()) { |
| return ToArrowStatus(result.error()); |
| } |
| if (result.value() < 0 || result.value() > nbytes) { |
| return ::arrow::Status::IOError("FileIO input stream returned invalid byte count"); |
| } |
| return result.value(); |
| } |
| |
| ::arrow::Result<std::shared_ptr<::arrow::Buffer>> Read(int64_t nbytes) override { |
| if (nbytes < 0) { |
| return ::arrow::Status::Invalid("Cannot read a negative number of bytes"); |
| } |
| ARROW_ASSIGN_OR_RAISE(auto buffer, ::arrow::AllocateResizableBuffer(nbytes)); |
| ARROW_ASSIGN_OR_RAISE(auto bytes_read, Read(nbytes, buffer->mutable_data())); |
| ARROW_RETURN_NOT_OK(buffer->Resize(bytes_read, /*shrink_to_fit=*/false)); |
| return std::shared_ptr<::arrow::Buffer>(std::move(buffer)); |
| } |
| |
| ::arrow::Result<int64_t> GetSize() override { return size_; } |
| |
| ::arrow::Result<int64_t> ReadAt(int64_t position, int64_t nbytes, void* out) override { |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| ARROW_ASSIGN_OR_RAISE(auto bytes_to_read, BytesToReadAt(position, nbytes, size_)); |
| if (bytes_to_read == 0) { |
| return 0; |
| } |
| auto data = reinterpret_cast<std::byte*>(out); |
| auto status = |
| input_->ReadFully(position, std::span(data, static_cast<size_t>(bytes_to_read))); |
| if (!status.has_value()) { |
| return ToArrowStatus(status.error()); |
| } |
| return bytes_to_read; |
| } |
| |
| ::arrow::Result<std::shared_ptr<::arrow::Buffer>> ReadAt(int64_t position, |
| int64_t nbytes) override { |
| { |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| } |
| ARROW_ASSIGN_OR_RAISE(auto bytes_to_read, BytesToReadAt(position, nbytes, size_)); |
| ARROW_ASSIGN_OR_RAISE(auto buffer, ::arrow::AllocateResizableBuffer(bytes_to_read)); |
| if (bytes_to_read == 0) { |
| return std::shared_ptr<::arrow::Buffer>(std::move(buffer)); |
| } |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| auto status = input_->ReadFully( |
| position, std::span(reinterpret_cast<std::byte*>(buffer->mutable_data()), |
| static_cast<size_t>(bytes_to_read))); |
| if (!status.has_value()) { |
| return ToArrowStatus(status.error()); |
| } |
| return std::shared_ptr<::arrow::Buffer>(std::move(buffer)); |
| } |
| |
| private: |
| ::arrow::Status CheckOpenLocked() const { |
| if (closed_) { |
| return ::arrow::Status::IOError("Operation on closed FileIO input stream"); |
| } |
| return ::arrow::Status::OK(); |
| } |
| |
| std::unique_ptr<SeekableInputStream> input_; |
| int64_t size_; |
| bool closed_ = false; |
| mutable std::mutex mutex_; |
| }; |
| |
| /// Adapts the generic Iceberg output stream API to Arrow's OutputStream API. |
| /// |
| /// Avro and Parquet writers in the bundle layer consume Arrow IO streams. This |
| /// fallback keeps those writers usable with non-Arrow FileIO implementations without |
| /// requiring them to downcast to ArrowFileSystemFileIO. |
| class OutputStreamAdapter : public ::arrow::io::OutputStream { |
| public: |
| explicit OutputStreamAdapter(std::unique_ptr<PositionOutputStream> output) |
| : output_(std::move(output)) { |
| OutputStream::set_mode(::arrow::io::FileMode::WRITE); |
| } |
| |
| ::arrow::Status Close() override { |
| std::lock_guard lock(mutex_); |
| if (closed_) { |
| return ::arrow::Status::OK(); |
| } |
| auto status = output_->Close(); |
| if (!status.has_value()) { |
| return ToArrowStatus(status.error()); |
| } |
| closed_ = true; |
| return ::arrow::Status::OK(); |
| } |
| |
| ::arrow::Result<int64_t> Tell() const override { |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| auto position = output_->Position(); |
| if (!position.has_value()) { |
| return ToArrowStatus(position.error()); |
| } |
| if (position.value() < 0) { |
| return ::arrow::Status::IOError("FileIO output stream returned negative position"); |
| } |
| return position.value(); |
| } |
| |
| bool closed() const override { |
| std::lock_guard lock(mutex_); |
| return closed_; |
| } |
| |
| ::arrow::Status Write(const void* data, int64_t nbytes) override { |
| if (nbytes < 0) { |
| return ::arrow::Status::Invalid("Cannot write a negative number of bytes"); |
| } |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| if (nbytes == 0) { |
| return ::arrow::Status::OK(); |
| } |
| auto status = output_->Write( |
| std::span(reinterpret_cast<const std::byte*>(data), static_cast<size_t>(nbytes))); |
| if (!status.has_value()) { |
| return ToArrowStatus(status.error()); |
| } |
| return ::arrow::Status::OK(); |
| } |
| |
| ::arrow::Status Flush() override { |
| std::lock_guard lock(mutex_); |
| ARROW_RETURN_NOT_OK(CheckOpenLocked()); |
| auto status = output_->Flush(); |
| if (!status.has_value()) { |
| return ToArrowStatus(status.error()); |
| } |
| return ::arrow::Status::OK(); |
| } |
| |
| private: |
| ::arrow::Status CheckOpenLocked() const { |
| if (closed_) { |
| return ::arrow::Status::IOError("Operation on closed FileIO output stream"); |
| } |
| return ::arrow::Status::OK(); |
| } |
| |
| std::unique_ptr<PositionOutputStream> output_; |
| bool closed_ = false; |
| mutable std::mutex mutex_; |
| }; |
| |
| class ArrowSeekableInputStream : public SeekableInputStream { |
| public: |
| explicit ArrowSeekableInputStream(std::shared_ptr<::arrow::io::RandomAccessFile> input) |
| : input_(std::move(input)) {} |
| |
| Result<int64_t> Position() const override { |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto position, input_->Tell()); |
| return position; |
| } |
| |
| Status Seek(int64_t position) override { |
| ICEBERG_ARROW_RETURN_NOT_OK(input_->Seek(position)); |
| return {}; |
| } |
| |
| Result<int64_t> Read(std::span<std::byte> out) override { |
| ICEBERG_ASSIGN_OR_RAISE(auto size, ToInt64Length(out.size())); |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto bytes_read, input_->Read(size, out.data())); |
| if (bytes_read < 0 || bytes_read > size) { |
| return IOError("Arrow input stream returned invalid byte count"); |
| } |
| return bytes_read; |
| } |
| |
| Status ReadFully(int64_t position, std::span<std::byte> out) override { |
| if (position < 0) { |
| return InvalidArgument("Cannot read from negative position {}", position); |
| } |
| ICEBERG_ASSIGN_OR_RAISE(auto size, ToInt64Length(out.size())); |
| if (size == 0) { |
| return {}; |
| } |
| if (position > std::numeric_limits<int64_t>::max() - size) { |
| return InvalidArgument( |
| "Read range starting at {} with length {} exceeds int64_t max", position, size); |
| } |
| |
| Status read_status = {}; |
| int64_t bytes_read = 0; |
| while (bytes_read < size) { |
| auto* data = out.data() + bytes_read; |
| auto remaining = size - bytes_read; |
| auto read_result = input_->ReadAt(position + bytes_read, remaining, data); |
| if (!read_result.ok()) { |
| read_status = |
| std::unexpected<Error>{{.kind = ToErrorKind(read_result.status()), |
| .message = read_result.status().ToString()}}; |
| break; |
| } |
| auto read = read_result.ValueOrDie(); |
| if (read < 0 || read > remaining) { |
| read_status = IOError("Arrow input stream returned invalid byte count"); |
| break; |
| } |
| if (read == 0) { |
| read_status = |
| IOError("Unexpected EOF reading at offset {}", position + bytes_read); |
| break; |
| } |
| bytes_read += read; |
| } |
| return read_status; |
| } |
| |
| Status Close() override { |
| if (input_->closed()) { |
| return {}; |
| } |
| ICEBERG_ARROW_RETURN_NOT_OK(input_->Close()); |
| return {}; |
| } |
| |
| private: |
| std::shared_ptr<::arrow::io::RandomAccessFile> input_; |
| }; |
| |
| class ArrowPositionOutputStream : public PositionOutputStream { |
| public: |
| explicit ArrowPositionOutputStream(std::shared_ptr<::arrow::io::OutputStream> output) |
| : output_(std::move(output)) {} |
| |
| Result<int64_t> Position() const override { |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto position, output_->Tell()); |
| return position; |
| } |
| |
| Result<int64_t> StoredLength() const override { |
| if (!output_->closed()) { |
| return Position(); |
| } |
| return closed_position_; |
| } |
| |
| Status Write(std::span<const std::byte> data) override { |
| ICEBERG_ASSIGN_OR_RAISE(auto size, ToInt64Length(data.size())); |
| ICEBERG_ARROW_RETURN_NOT_OK(output_->Write(data.data(), size)); |
| return {}; |
| } |
| |
| Status Flush() override { |
| ICEBERG_ARROW_RETURN_NOT_OK(output_->Flush()); |
| return {}; |
| } |
| |
| Status Close() override { |
| if (output_->closed()) { |
| return {}; |
| } |
| ICEBERG_ASSIGN_OR_RAISE(auto position, Position()); |
| ICEBERG_ARROW_RETURN_NOT_OK(output_->Close()); |
| closed_position_ = position; |
| return {}; |
| } |
| |
| private: |
| std::shared_ptr<::arrow::io::OutputStream> output_; |
| int64_t closed_position_ = 0; |
| }; |
| |
| class ArrowInputFile : public InputFile { |
| public: |
| ArrowInputFile(std::shared_ptr<::arrow::fs::FileSystem> fs, std::string location, |
| std::string path, std::optional<int64_t> file_size) |
| : fs_(std::move(fs)), |
| location_(std::move(location)), |
| path_(std::move(path)), |
| file_size_(file_size) {} |
| |
| std::string_view location() const override { return location_; } |
| |
| Result<int64_t> Size() const override { |
| if (file_size_.has_value()) { |
| return *file_size_; |
| } |
| ::arrow::fs::FileInfo file_info(path_, ::arrow::fs::FileType::File); |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto input, fs_->OpenInputFile(file_info)); |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto size, input->GetSize()); |
| return size; |
| } |
| |
| Result<std::unique_ptr<SeekableInputStream>> Open() override { |
| ::arrow::fs::FileInfo file_info(path_, ::arrow::fs::FileType::File); |
| if (file_size_.has_value()) { |
| file_info.set_size(*file_size_); |
| } |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto input, fs_->OpenInputFile(file_info)); |
| return std::make_unique<ArrowSeekableInputStream>(std::move(input)); |
| } |
| |
| private: |
| std::shared_ptr<::arrow::fs::FileSystem> fs_; |
| std::string location_; |
| std::string path_; |
| std::optional<int64_t> file_size_; |
| }; |
| |
| class ArrowOutputFile : public OutputFile { |
| public: |
| ArrowOutputFile(std::shared_ptr<::arrow::fs::FileSystem> fs, std::string location, |
| std::string path) |
| : fs_(std::move(fs)), location_(std::move(location)), path_(std::move(path)) {} |
| |
| std::string_view location() const override { return location_; } |
| |
| Result<std::unique_ptr<PositionOutputStream>> Create() override { |
| return Create(/*overwrite=*/false); |
| } |
| |
| Result<std::unique_ptr<PositionOutputStream>> CreateOrOverwrite() override { |
| return Create(/*overwrite=*/true); |
| } |
| |
| private: |
| Result<std::unique_ptr<PositionOutputStream>> Create(bool overwrite) { |
| if (!overwrite) { |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto info, fs_->GetFileInfo(path_)); |
| if (info.type() != ::arrow::fs::FileType::NotFound) { |
| return AlreadyExists("File already exists: {}", location_); |
| } |
| } |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto output, fs_->OpenOutputStream(path_)); |
| return std::make_unique<ArrowPositionOutputStream>(std::move(output)); |
| } |
| |
| std::shared_ptr<::arrow::fs::FileSystem> fs_; |
| std::string location_; |
| std::string path_; |
| }; |
| |
| } // namespace |
| |
| Result<std::string> ArrowFileSystemFileIO::ResolvePath(const std::string& file_location) { |
| const auto pos = file_location.find("://"); |
| if (pos == std::string::npos) { |
| return file_location; |
| } |
| |
| auto path = arrow_fs_->PathFromUri(file_location); |
| if (path.ok()) { |
| return std::move(path).ValueOrDie(); |
| } |
| |
| // Foreign alias (s3a/s3n): validate via Arrow's parser, then percent-decode the |
| // scheme-less key (substring keeps a Windows drive letter's ':' that host() drops). |
| if (auto parsed = ::arrow::util::Uri::FromString(file_location); !parsed.ok()) { |
| const auto& status = parsed.status(); |
| return std::unexpected<Error>{ |
| {.kind = ToErrorKind(status), .message = status.ToString()}}; |
| } |
| std::string bucket_key = file_location.substr(pos + 3); |
| bucket_key = bucket_key.substr(0, bucket_key.find_first_of("?#")); |
| return ::arrow::util::UriUnescape(bucket_key); |
| } |
| |
| Result<std::shared_ptr<::arrow::io::RandomAccessFile>> OpenArrowInputStream( |
| const std::shared_ptr<FileIO>& io, const std::string& path, |
| std::optional<size_t> length) { |
| ICEBERG_PRECHECK(io != nullptr, "FileIO cannot be null"); |
| |
| if (auto arrow_io = std::dynamic_pointer_cast<ArrowFileSystemFileIO>(io)) { |
| ICEBERG_ASSIGN_OR_RAISE(auto resolved_path, arrow_io->ResolvePath(path)); |
| ::arrow::fs::FileInfo file_info(resolved_path, ::arrow::fs::FileType::File); |
| if (length.has_value()) { |
| ICEBERG_ASSIGN_OR_RAISE(auto size, ToInt64Length(*length)); |
| file_info.set_size(size); |
| } |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto input, |
| arrow_io->arrow_fs_->OpenInputFile(file_info)); |
| return input; |
| } |
| |
| int64_t size; |
| std::unique_ptr<InputFile> input_file; |
| if (length.has_value()) { |
| ICEBERG_ASSIGN_OR_RAISE(input_file, io->NewInputFile(path, *length)); |
| } else { |
| ICEBERG_ASSIGN_OR_RAISE(input_file, io->NewInputFile(path)); |
| } |
| ICEBERG_ASSIGN_OR_RAISE(size, input_file->Size()); |
| if (size < 0) { |
| return Invalid("Invalid negative file size {} for {}", size, path); |
| } |
| ICEBERG_ASSIGN_OR_RAISE(auto input, input_file->Open()); |
| return std::make_shared<InputStreamAdapter>(std::move(input), size); |
| } |
| |
| Result<std::shared_ptr<::arrow::io::OutputStream>> OpenArrowOutputStream( |
| const std::shared_ptr<FileIO>& io, const std::string& path, bool overwrite) { |
| ICEBERG_PRECHECK(io != nullptr, "FileIO cannot be null"); |
| |
| if (auto arrow_io = std::dynamic_pointer_cast<ArrowFileSystemFileIO>(io)) { |
| ICEBERG_ASSIGN_OR_RAISE(auto resolved_path, arrow_io->ResolvePath(path)); |
| if (!overwrite) { |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto info, |
| arrow_io->arrow_fs_->GetFileInfo(resolved_path)); |
| if (info.type() != ::arrow::fs::FileType::NotFound) { |
| return AlreadyExists("File already exists: {}", path); |
| } |
| } |
| ICEBERG_ARROW_ASSIGN_OR_RETURN(auto output, |
| arrow_io->arrow_fs_->OpenOutputStream(resolved_path)); |
| return output; |
| } |
| |
| ICEBERG_ASSIGN_OR_RAISE(auto output_file, io->NewOutputFile(path)); |
| std::unique_ptr<PositionOutputStream> output; |
| if (overwrite) { |
| ICEBERG_ASSIGN_OR_RAISE(output, output_file->CreateOrOverwrite()); |
| } else { |
| ICEBERG_ASSIGN_OR_RAISE(output, output_file->Create()); |
| } |
| return std::make_shared<OutputStreamAdapter>(std::move(output)); |
| } |
| |
| Result<std::unique_ptr<InputFile>> ArrowFileSystemFileIO::NewInputFile( |
| std::string file_location) { |
| ICEBERG_ASSIGN_OR_RAISE(auto path, ResolvePath(file_location)); |
| return std::make_unique<ArrowInputFile>(arrow_fs_, std::move(file_location), |
| std::move(path), std::nullopt); |
| } |
| |
| Result<std::unique_ptr<InputFile>> ArrowFileSystemFileIO::NewInputFile( |
| std::string file_location, size_t length) { |
| ICEBERG_ASSIGN_OR_RAISE(auto size, ToInt64Length(length)); |
| ICEBERG_ASSIGN_OR_RAISE(auto path, ResolvePath(file_location)); |
| return std::make_unique<ArrowInputFile>(arrow_fs_, std::move(file_location), |
| std::move(path), size); |
| } |
| |
| Result<std::unique_ptr<OutputFile>> ArrowFileSystemFileIO::NewOutputFile( |
| std::string file_location) { |
| ICEBERG_ASSIGN_OR_RAISE(auto path, ResolvePath(file_location)); |
| return std::make_unique<ArrowOutputFile>(arrow_fs_, std::move(file_location), |
| std::move(path)); |
| } |
| |
| /// \brief Delete a file at the given location. |
| Status ArrowFileSystemFileIO::DeleteFile(const std::string& file_location) { |
| ICEBERG_ASSIGN_OR_RAISE(auto path, ResolvePath(file_location)); |
| ICEBERG_ARROW_RETURN_NOT_OK(arrow_fs_->DeleteFile(path)); |
| return {}; |
| } |
| |
| Status ArrowFileSystemFileIO::DeleteFiles( |
| const std::vector<std::string>& file_locations) { |
| std::vector<std::string> paths; |
| paths.reserve(file_locations.size()); |
| for (const auto& file_location : file_locations) { |
| ICEBERG_ASSIGN_OR_RAISE(auto path, ResolvePath(file_location)); |
| paths.push_back(std::move(path)); |
| } |
| ICEBERG_ARROW_RETURN_NOT_OK(arrow_fs_->DeleteFiles(paths)); |
| return {}; |
| } |
| |
| std::unique_ptr<FileIO> ArrowFileSystemFileIO::MakeMockFileIO() { |
| return std::make_unique<ArrowFileSystemFileIO>( |
| std::make_shared<::arrow::fs::internal::MockFileSystem>( |
| std::chrono::system_clock::now())); |
| } |
| |
| std::unique_ptr<FileIO> ArrowFileSystemFileIO::MakeLocalFileIO() { |
| return std::make_unique<ArrowFileSystemFileIO>( |
| std::make_shared<::arrow::fs::LocalFileSystem>()); |
| } |
| |
| std::unique_ptr<FileIO> MakeMockFileIO() { |
| return ArrowFileSystemFileIO::MakeMockFileIO(); |
| } |
| |
| std::unique_ptr<FileIO> MakeLocalFileIO() { |
| return ArrowFileSystemFileIO::MakeLocalFileIO(); |
| } |
| |
| } // namespace iceberg::arrow |