wgtmac commented on code in PR #777:
URL: https://github.com/apache/iceberg-cpp/pull/777#discussion_r3497708429


##########
src/iceberg/data/deletion_vector_writer.cc:
##########
@@ -0,0 +1,238 @@
+/*
+ * 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 "iceberg/data/deletion_vector_writer.h"
+
+#include <format>
+#include <map>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "iceberg/file_io.h"
+#include "iceberg/manifest/manifest_entry.h"
+#include "iceberg/metadata_columns.h"
+#include "iceberg/partition_spec.h"
+#include "iceberg/puffin/file_metadata.h"
+#include "iceberg/puffin/puffin_writer.h"
+#include "iceberg/util/content_file_util.h"
+#include "iceberg/util/macros.h"
+#include "iceberg/version.h"
+
+namespace iceberg {
+
+namespace {
+constexpr std::string_view kReferencedDataFile = "referenced-data-file";
+constexpr std::string_view kCardinality = "cardinality";
+}  // namespace
+
+class DeletionVectorWriter::Impl {
+ public:
+  explicit Impl(DeletionVectorWriterOptions options) : 
options_(std::move(options)) {}
+
+  // Accumulated positions and metadata for a single referenced data file.
+  struct Deletes {
+    PositionDeleteIndex positions;
+    std::shared_ptr<PartitionSpec> spec;
+    PartitionValues partition;
+  };
+
+  Deletes& DeletesFor(std::string_view referenced_data_file,
+                      std::shared_ptr<PartitionSpec> spec, PartitionValues 
partition) {
+    auto [it, inserted] = 
deletes_by_path_.try_emplace(std::string(referenced_data_file));
+    if (inserted) {
+      it->second.spec = std::move(spec);
+      it->second.partition = std::move(partition);
+    }
+    return it->second;
+  }
+
+  Status Delete(std::string_view referenced_data_file, int64_t pos,
+                std::shared_ptr<PartitionSpec> spec, PartitionValues 
partition) {
+    ICEBERG_CHECK(!closed_, "Cannot delete after the writer is closed");
+    ICEBERG_PRECHECK(!referenced_data_file.empty(),
+                     "Deletion vector requires a non-empty referenced data 
file");
+    DeletesFor(referenced_data_file, std::move(spec), std::move(partition))

Review Comment:
   Please validate `pos` before adding it to the index. 
`PositionDeleteIndex::Delete` still silently ignores out-of-range values, while 
Java fails in `RoaringPositionBitmap.set`. As-is, `Delete(..., -1, ...)` 
returns OK and writes a DV without that delete.



##########
src/iceberg/data/deletion_vector_writer.h:
##########
@@ -0,0 +1,114 @@
+/*
+ * 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/data/deletion_vector_writer.h
+/// Writer that emits deletion vectors as `deletion-vector-v1` blobs in a 
Puffin file.
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+#include <vector>
+
+#include "iceberg/deletes/position_delete_index.h"
+#include "iceberg/iceberg_data_export.h"
+#include "iceberg/result.h"
+#include "iceberg/row/partition_values.h"
+#include "iceberg/type_fwd.h"
+
+namespace iceberg {
+
+/// \brief The result of writing deletion vectors.
+struct ICEBERG_DATA_EXPORT DeleteWriteResult {
+  /// Deletion vector files produced, one per referenced data file.
+  std::vector<std::shared_ptr<DataFile>> delete_files;
+  /// Data files referenced by the produced deletion vectors.
+  std::vector<std::string> referenced_data_files;
+  /// Previously written, file-scoped delete files that were merged and should 
be
+  /// removed from table state.
+  std::vector<std::shared_ptr<DataFile>> rewritten_delete_files;
+};
+
+/// \brief Previously written deletes for a data file, used to merge before
+/// writing a new deletion vector.
+struct ICEBERG_DATA_EXPORT PreviousDeletes {

Review Comment:
   Please keep source delete files on `PositionDeleteIndex`, like Java 
`deleteFiles()`, and let the previous-delete hook return the index directly. 
This wrapper keeps the writer API different from `BaseDVFileWriter`.



##########
src/iceberg/deletes/position_delete_index.h:
##########
@@ -66,7 +67,20 @@ class ICEBERG_DATA_EXPORT PositionDeleteIndex {
   /// \param other The index to merge (union operation)
   void Merge(const PositionDeleteIndex& other);
 
+  /// \brief Serialize the index into a `deletion-vector-v1` blob.
+  ///
+  /// The positions are run-length encoded, then framed per the Puffin spec:
+  /// https://iceberg.apache.org/puffin-spec/#deletion-vector-v1-blob-type
+  Result<std::vector<uint8_t>> Serialize();
+
+  /// \brief Deserialize a `deletion-vector-v1` blob into an index.
+  ///
+  /// Validates the length prefix, magic sequence, and CRC-32 checksum.
+  static Result<PositionDeleteIndex> Deserialize(std::span<const uint8_t> 
blob);

Review Comment:
   Please pass delete-file metadata to `Deserialize`, like Java 
`PositionDeleteIndex.deserialize(bytes, deleteFile)`. Deserialization should 
validate `content_size_in_bytes` and `record_count`, so public callers cannot 
bypass those DV checks.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to