| /* | |
| * 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_writer.h | |
| /// Writer interface for file formats like Parquet, Avro and ORC. | |
| #include <functional> | |
| #include <memory> | |
| #include <optional> | |
| #include <vector> | |
| #include "iceberg/arrow_c_data.h" | |
| #include "iceberg/file_format.h" | |
| #include "iceberg/metrics.h" | |
| #include "iceberg/metrics_config.h" | |
| #include "iceberg/result.h" | |
| #include "iceberg/type_fwd.h" | |
| #include "iceberg/util/config.h" | |
| namespace iceberg { | |
| class ICEBERG_EXPORT WriterProperties : public ConfigBase<WriterProperties> { | |
| public: | |
| template <typename T> | |
| using Entry = const ConfigBase<WriterProperties>::Entry<T>; | |
| /// \brief The name of the Avro root node schema to write. | |
| inline static Entry<std::string> kAvroSchemaName{"write.avro.schema-name", ""}; | |
| /// \brief The buffer size used by Avro output stream. | |
| inline static Entry<int64_t> kAvroBufferSize{"write.avro.buffer-size", 1024 * 1024}; | |
| /// \brief The sync interval used by Avro writer. | |
| inline static Entry<int64_t> kAvroSyncInterval{"write.avro.sync-interval", 16 * 1024}; | |
| /// \brief Whether to skip GenericDatum and use direct encoder for Avro writing. | |
| /// When true, uses direct encoder (faster). When false, uses GenericDatum. | |
| inline static Entry<bool> kAvroSkipDatum{"write.avro.skip-datum", true}; | |
| inline static Entry<std::string> kAvroCompression{"write.avro.compression-codec", | |
| "gzip"}; | |
| inline static Entry<std::string> kAvroCompressionLevel{"write.avro.compression-level", | |
| ""}; | |
| inline static Entry<std::string> kParquetCompression{"write.parquet.compression-codec", | |
| "zstd"}; | |
| inline static Entry<std::string> kParquetCompressionLevel{ | |
| "write.parquet.compression-level", ""}; | |
| /// \brief Maximum number of rows in each Parquet row group. | |
| inline static Entry<int64_t> kParquetMaxRowGroupRows{"write.parquet.max-row-group-rows", | |
| 1024 * 1024}; | |
| /// TODO(gangwu): add table properties with write.avro|parquet|orc.* | |
| /// \brief Create a WriterProperties instance from a map of key-value pairs. | |
| static WriterProperties FromMap( | |
| const std::unordered_map<std::string, std::string>& properties); | |
| }; | |
| /// \brief Options for creating a writer. | |
| struct ICEBERG_EXPORT WriterOptions { | |
| /// \brief The path to the file to write. | |
| std::string path; | |
| /// \brief The schema of the data to write. | |
| std::shared_ptr<Schema> schema; | |
| /// \brief FileIO instance to create the file. | |
| std::shared_ptr<class FileIO> io; | |
| /// \brief Metadata to write to the file. | |
| std::unordered_map<std::string, std::string> metadata; | |
| /// \brief Metrics configuration. | |
| std::shared_ptr<MetricsConfig> metrics_config = MetricsConfig::Default(); | |
| /// \brief Format-specific or implementation-specific properties. | |
| WriterProperties properties; | |
| }; | |
| /// \brief Base writer class to write data from different file formats. | |
| class ICEBERG_EXPORT Writer { | |
| public: | |
| virtual ~Writer() = default; | |
| Writer() = default; | |
| Writer(const Writer&) = delete; | |
| Writer& operator=(const Writer&) = delete; | |
| /// \brief Open the writer. | |
| virtual Status Open(const WriterOptions& options) = 0; | |
| /// \brief Close the writer. | |
| virtual Status Close() = 0; | |
| /// \brief Write arrow data to the file. | |
| /// | |
| /// \return Status of write results. | |
| /// \note Ownership of the data is transferred to the writer. | |
| virtual Status Write(ArrowArray* data) = 0; | |
| /// \brief Get the file statistics. | |
| /// Only valid after the file is closed. | |
| virtual Result<Metrics> metrics() = 0; | |
| /// \brief Get the file length. | |
| /// This can be called while the writer is still open or after the file is closed. | |
| virtual Result<int64_t> length() = 0; | |
| /// \brief Returns a list of recommended split locations, if applicable, empty | |
| /// otherwise. When available, this information is used for planning scan tasks whose | |
| /// boundaries are determined by these offsets. The returned list must be sorted in | |
| /// ascending order. Only valid after the file is closed. | |
| virtual std::vector<int64_t> split_offsets() = 0; | |
| }; | |
| /// \brief Factory function to create a writer of a specific file format. | |
| using WriterFactory = std::function<Result<std::unique_ptr<Writer>>()>; | |
| /// \brief Registry of writer factories for different file formats. | |
| struct ICEBERG_EXPORT WriterFactoryRegistry { | |
| /// \brief Register a factory function for a specific file format. | |
| WriterFactoryRegistry(FileFormatType format_type, WriterFactory factory); | |
| /// \brief Get the factory function for a specific file format. | |
| static WriterFactory& GetFactory(FileFormatType format_type); | |
| /// \brief Open a writer for a specific file format. | |
| static Result<std::unique_ptr<Writer>> Open(FileFormatType format_type, | |
| const WriterOptions& options); | |
| }; | |
| } // namespace iceberg |