SteNicholas commented on code in PR #494:
URL: https://github.com/apache/paimon-cpp/pull/494#discussion_r4444493512


##########
src/paimon/core/manifest/index_manifest_file_handler_test.cpp:
##########
@@ -344,8 +345,43 @@ TEST_F(IndexManifestFileHandlerTest, 
GlobalDvCombinerReplacesIndexFileInBucketUn
     ASSERT_EQ(written_file_names, (std::set<std::string>{"dv-0-newer", 
"dv-1"}));
 }
 
+TEST_F(IndexManifestFileHandlerTest, DynamicBucketDvUsesBucketedCombiner) {
+    ASSERT_OK_AND_ASSIGN(auto index_manifest_file, 
CreateManifestFile(BucketMode::HASH_DYNAMIC));
+
+    auto partition = BinaryRow::EmptyRow();
+    std::vector<IndexManifestEntry> previous_entries = {
+        MakeDvEntry(FileKind::Add(), partition, /*bucket=*/0, "dv-0", 
{"data-0.orc"}, 1),
+        MakeDvEntry(FileKind::Add(), partition, /*bucket=*/1, "dv-1", 
{"data-1.orc"}, 1)};
+    ASSERT_OK_AND_ASSIGN(std::string previous_manifest,
+                         IndexManifestFileHandler::Write(
+                             /*previous_index_manifest=*/std::nullopt, 
previous_entries,
+                             BucketMode::HASH_DYNAMIC, 
index_manifest_file.get()));
+
+    // a dynamic bucket table rewrites the whole index file of a bucket, so 
the added entry
+    // replaces dv-0 by (partition, bucket) although it is not deleted by name
+    std::vector<IndexManifestEntry> new_entries = {MakeDvEntry(
+        FileKind::Add(), partition, /*bucket=*/0, "dv-0-new", {"data-0.orc", 
"data-2.orc"}, 2)};
+    ASSERT_OK_AND_ASSIGN(
+        std::string current_manifest,
+        IndexManifestFileHandler::Write(previous_manifest, new_entries, 
BucketMode::HASH_DYNAMIC,

Review Comment:
   [P3] Could this regression test exercise 
`IndexManifestFile::WriteIndexFiles()`? Calling the handler directly with 
`BucketMode::HASH_DYNAMIC` verifies combiner selection, but bypasses the 
`Create()` → `bucket_mode_` → `WriteIndexFiles()` propagation changed by this 
PR. The test would still pass if the manifest stored or forwarded the wrong 
mode. Using the manifest entry point for the initial write and replacement 
would cover that path too. For the bucket-unaware negative case, a separately 
configured manifest and `ASSERT_NOK_WITH_MSG` would also ensure rejection 
happens for the intended duplicate-data-file reason.



##########
src/paimon/core/manifest/index_manifest_file_handler.cpp:
##########
@@ -255,17 +255,14 @@ IndexManifestFileHandler::SeparateIndexEntries(
 
 Result<std::unique_ptr<IndexManifestFileHandler::IndexManifestFileCombiner>>
 IndexManifestFileHandler::GetIndexManifestFileCombine(const std::string& 
index_type,
-                                                      int32_t bucket_mode) {
+                                                      BucketMode bucket_mode) {
     if (index_type != DeletionVectorsIndexFile::DELETION_VECTORS_INDEX && 
index_type != "HASH") {
         return std::make_unique<GlobalFileNameCombiner>();
     }
-    // `bucket_mode` is the configured bucket, not a resolved BucketMode, 
standing in for Paimon
-    // Java's BucketMode.BUCKET_UNAWARE check. The two agree on every table 
that can exist:
-    // SchemaValidation rejects the other unaware bucket, 0, and 
BucketIdCalculator refuses to
-    // write the primary key table on which -1 means HASH_DYNAMIC instead. 
Lifting either
-    // restriction means passing the resolved BucketMode here, or a dynamic 
bucket table would
-    // combine its per-bucket deletion vectors by index file name.
-    if (index_type == DeletionVectorsIndexFile::DELETION_VECTORS_INDEX && 
bucket_mode == -1) {
+    // A dynamic bucket primary key table also has bucket=-1, but keeps one 
deletion vector index
+    // per bucket, so only BUCKET_UNAWARE combines deletion vectors by data 
file name.

Review Comment:
   [P3] Could the comment distinguish the merge key from the consistency check? 
`GlobalDeletionVectorCombiner` merges entries by **index file name** and uses 
**data file names** to reject duplicate deletion-vector coverage. Saying it 
combines by data file name obscures those different roles. Also, "per 
(partition, bucket)" would describe the bucketed identity more precisely than 
"per bucket".



##########
src/paimon/core/index/index_file_handler_test.cpp:
##########
@@ -81,7 +81,9 @@ class IndexFileHandlerTest : public testing::Test {
                                IndexManifestFile::Create(
                                    core_options.GetFileSystem(), 
core_options.GetManifestFormat(),
                                    core_options.GetManifestCompression(), 
path_factory,
-                                   core_options.GetBucket(), memory_pool_, 
core_options));
+                                   core_options.GetBucket() == -1 ? 
BucketMode::BUCKET_UNAWARE

Review Comment:
   [P3] Could we use `ResolveBucketMode(core_options.GetBucket(), 
table_schema)` here as well? This helper already loads `table_schema`, but the 
new ternary retains the old assumption that `bucket == -1` always means 
`BUCKET_UNAWARE`; it would misclassify a dynamic-bucket primary-key fixture. 
The current read-only tests do not expose the difference, but reusing the 
resolver would keep this helper consistent with production callers.



-- 
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]

Reply via email to