| /* | |
| * 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/file_io.h | |
| /// \brief Define the FileIO abstraction and file stream interfaces. | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <memory> | |
| #include <optional> | |
| #include <span> | |
| #include <string> | |
| #include <string_view> | |
| #include <utility> | |
| #include <vector> | |
| #include "iceberg/iceberg_export.h" | |
| #include "iceberg/result.h" | |
| #include "iceberg/storage_credential.h" | |
| namespace iceberg { | |
| class SupportsStorageCredentials; | |
| /// \brief Seekable byte stream for reading file contents. | |
| class ICEBERG_EXPORT SeekableInputStream { | |
| public: | |
| virtual ~SeekableInputStream() = default; | |
| /// \brief Return the current read position. | |
| virtual Result<int64_t> Position() const = 0; | |
| /// \brief Seek to an absolute byte position. | |
| virtual Status Seek(int64_t position) = 0; | |
| /// \brief Read up to out.size() bytes from the current position. | |
| virtual Result<int64_t> Read(std::span<std::byte> out) = 0; | |
| /// \brief Read exactly out.size() bytes from an absolute position. | |
| /// | |
| /// Fails if fewer than out.size() bytes are available. The current stream position | |
| /// after this call is unspecified; callers should Seek before subsequent | |
| /// position-dependent reads. | |
| virtual Status ReadFully(int64_t position, std::span<std::byte> out) = 0; | |
| /// \brief Close the stream. Implementations should allow repeated Close calls. | |
| virtual Status Close() = 0; | |
| }; | |
| /// \brief Positioned byte stream for writing file contents. | |
| class ICEBERG_EXPORT PositionOutputStream { | |
| public: | |
| virtual ~PositionOutputStream() = default; | |
| /// \brief Return the current write position. | |
| virtual Result<int64_t> Position() const = 0; | |
| /// \brief Return the current stored length of the output. | |
| /// | |
| /// This can differ from the current position for encrypting streams, and for other | |
| /// non-length-preserving streams. | |
| virtual Result<int64_t> StoredLength() const { return Position(); } | |
| /// \brief Write all bytes in data at the current position. | |
| virtual Status Write(std::span<const std::byte> data) = 0; | |
| /// \brief Flush buffered data to the underlying store. | |
| virtual Status Flush() = 0; | |
| /// \brief Close the stream. Implementations should allow repeated Close calls. | |
| virtual Status Close() = 0; | |
| }; | |
| /// \brief Handle for opening a readable file. | |
| class ICEBERG_EXPORT InputFile { | |
| public: | |
| virtual ~InputFile() = default; | |
| /// \brief File location represented by this handle. | |
| virtual std::string_view location() const = 0; | |
| /// \brief Return the total file size in bytes. | |
| virtual Result<int64_t> Size() const = 0; | |
| /// \brief Open a new independent input stream. | |
| virtual Result<std::unique_ptr<SeekableInputStream>> Open() = 0; | |
| }; | |
| /// \brief Handle for creating a writable file. | |
| class ICEBERG_EXPORT OutputFile { | |
| public: | |
| virtual ~OutputFile() = default; | |
| /// \brief File location represented by this handle. | |
| virtual std::string_view location() const = 0; | |
| /// \brief Create a new output stream and fail if the file already exists. | |
| virtual Result<std::unique_ptr<PositionOutputStream>> Create() = 0; | |
| /// \brief Create a new output stream, replacing any existing file. | |
| virtual Result<std::unique_ptr<PositionOutputStream>> CreateOrOverwrite() = 0; | |
| }; | |
| /// \brief Pluggable module for reading, writing, and deleting files. | |
| /// | |
| /// This module handles metadata and data file bytes for table IO. | |
| /// | |
| /// Note that these functions are not atomic. For example, if a write fails, | |
| /// the file may be partially written. Implementations should be careful to | |
| /// avoid corrupting metadata files. | |
| class ICEBERG_EXPORT FileIO { | |
| public: | |
| FileIO() = default; | |
| virtual ~FileIO() = default; | |
| /// \brief Create an input file handle for the given location. | |
| virtual Result<std::unique_ptr<InputFile>> NewInputFile(std::string file_location); | |
| /// \brief Create an input file handle for the given location with a known length. | |
| /// | |
| /// The length is a caller-provided content length hint. Implementations may use it to | |
| /// avoid an extra metadata lookup. | |
| virtual Result<std::unique_ptr<InputFile>> NewInputFile(std::string file_location, | |
| size_t length); | |
| /// \brief Create an output file handle for the given location. | |
| virtual Result<std::unique_ptr<OutputFile>> NewOutputFile(std::string file_location); | |
| /// \brief Read the content of the file at the given location. | |
| /// | |
| /// \param file_location The location of the file to read. | |
| /// \param length The number of bytes to read. Some object storage need to specify | |
| /// the length to read, e.g. S3 `GetObject` has a Range parameter. | |
| /// \return The content of the file if the read succeeded, an error code if the read | |
| /// failed. | |
| virtual Result<std::string> ReadFile(const std::string& file_location, | |
| std::optional<size_t> length); | |
| /// \brief Write the given content to the file at the given location. | |
| /// | |
| /// \param file_location The location of the file to write. | |
| /// \param content The content to write to the file. | |
| /// \return void if the write succeeded, an error code if the write failed. | |
| virtual Status WriteFile(const std::string& file_location, std::string_view content); | |
| /// \brief Delete a file at the given location. | |
| /// | |
| /// \param file_location The location of the file to delete. | |
| /// \return void if the delete succeeded, an error code if the delete failed. | |
| virtual Status DeleteFile(const std::string& file_location) { | |
| return NotImplemented("DeleteFile not implemented"); | |
| } | |
| /// \brief Delete files at the given locations. | |
| /// | |
| /// Implementations that can delete multiple files efficiently should override this | |
| /// method. The default implementation deletes files sequentially using DeleteFile | |
| /// and returns the first error encountered. | |
| /// | |
| /// \param file_locations The locations of the files to delete. | |
| /// \return void if all deletes succeed, or an error code if any delete fails. | |
| virtual Status DeleteFiles(const std::vector<std::string>& file_locations); | |
| /// \brief Return storage-credential support when implemented by this FileIO. | |
| virtual SupportsStorageCredentials* AsSupportsStorageCredentials() { return nullptr; } | |
| }; | |
| /// \brief Mix-in for FileIO implementations that route object paths to | |
| /// per-prefix file systems built from vended storage credentials, letting the | |
| /// catalog stay decoupled from concrete storage implementations. | |
| class ICEBERG_EXPORT SupportsStorageCredentials { | |
| public: | |
| virtual ~SupportsStorageCredentials() = default; | |
| /// \brief Install vended storage credentials. | |
| virtual Status SetStorageCredentials( | |
| const std::vector<StorageCredential>& storage_credentials) = 0; | |
| /// \brief Return the storage credentials this FileIO holds. | |
| /// | |
| /// By value because a concurrent install may replace them. An implementation | |
| /// that delegates may report what was installed on it. | |
| virtual std::vector<StorageCredential> credentials() const = 0; | |
| /// \brief Install initial credentials and their refresh source before first use. | |
| /// | |
| /// The default implementation supports static credentials only. | |
| virtual Status InitializeStorageCredentials( | |
| const std::vector<StorageCredential>& storage_credentials, | |
| std::shared_ptr<StorageCredentialProvider> provider) { | |
| if (provider) { | |
| return NotSupported("Credential refresh is not supported"); | |
| } | |
| return SetStorageCredentials(storage_credentials); | |
| } | |
| }; | |
| } // namespace iceberg |