wangyong9999 commented on code in PR #245:
URL: https://github.com/apache/paimon-cpp/pull/245#discussion_r3850615971


##########
src/paimon/core/schema/schema_validation.cpp:
##########
@@ -341,6 +403,71 @@ Status SchemaValidation::ValidateForDeletionVectors(const 
CoreOptions& options)
         "no deletion of old data in this merge engine.");
 }
 
+Status SchemaValidation::ValidatePrimaryKeyBTreeIndexes(const TableSchema& 
schema,
+                                                        const CoreOptions& 
options) {
+    std::vector<std::string> index_columns = 
PrimaryKeyBTreeIndexColumns(schema.Options());
+    if (index_columns.empty()) {
+        return Status::OK();
+    }
+
+    PAIMON_ASSIGN_OR_RAISE(PrimaryKeyIndexDefinitions definitions,
+                           PrimaryKeyIndexDefinitions::Create(schema));
+    if (!options.DeletionVectorsEnabled()) {
+        return Status::Invalid(
+            "Primary-key BTree indexes require deletion-vectors.enabled = 
true.");
+    }
+    if (schema.PrimaryKeys().empty()) {
+        return Status::Invalid("Primary-key BTree indexes require a 
primary-key table.");
+    }
+    if (options.GetBucket() <= 0 && !IsPostponeBucketTable(schema, 
options.GetBucket())) {
+        return Status::Invalid(
+            fmt::format("Primary-key BTree indexes require fixed or postpone 
bucket mode "
+                        "(bucket > 0 or bucket = -2), but bucket is {}.",
+                        options.GetBucket()));
+    }
+    PAIMON_ASSIGN_OR_RAISE(
+        bool deletion_vectors_merge_on_read,
+        OptionsUtils::GetValueFromMap<bool>(schema.Options(), 
kDeletionVectorsMergeOnRead, false));
+    if (deletion_vectors_merge_on_read) {
+        return Status::Invalid(
+            "Primary-key BTree indexes require deletion-vectors.merge-on-read 
= false.");
+    }
+    PAIMON_ASSIGN_OR_RAISE(
+        bool pk_clustering_override,
+        OptionsUtils::GetValueFromMap<bool>(schema.Options(), 
kPkClusteringOverride, false));
+    if (pk_clustering_override) {
+        return Status::Invalid("Primary-key BTree indexes do not support 
pk-clustering-override.");
+    }
+
+    for (const std::string& column : index_columns) {
+        auto field_iter =
+            std::find_if(schema.Fields().begin(), schema.Fields().end(),
+                         [&column](const DataField& field) { return 
field.Name() == column; });
+        if (field_iter == schema.Fields().end()) {
+            return Status::Invalid(fmt::format("{} entry '{}' must reference 
an existing column.",
+                                               
Options::PK_BTREE_INDEX_COLUMNS, column));
+        }
+        if (!IsSupportedBTreeIndexType(field_iter->Type())) {
+            return Status::Invalid(fmt::format("{} entry '{}' has unsupported 
type {}.",
+                                               
Options::PK_BTREE_INDEX_COLUMNS, column,
+                                               
field_iter->Type()->ToString()));
+        }
+
+        auto definition_iter = std::find_if(
+            definitions.Definitions().begin(), definitions.Definitions().end(),
+            [&column](const PrimaryKeyIndexDefinition& definition) {
+                return definition.GetFamily() == 
PrimaryKeyIndexDefinition::Family::BTREE &&
+                       definition.Column() == column;
+            });
+        if (definition_iter == definitions.Definitions().end()) {
+            return Status::Invalid(
+                fmt::format("Failed to resolve primary-key BTree index column 
'{}'.", column));

Review Comment:
   Unreachable: `PrimaryKeyIndexDefinitions::Create` builds BTREE definitions 
by iterating `schema.Fields()` and testing membership in the btree column list, 
so any column that passed the "must reference an existing column" check a few 
lines above necessarily has a definition here.
   
   Also, `kPkClusteringOverride` duplicates the same literal already defined in 
`file_store_commit_impl.cpp:98`.



##########
src/paimon/core/mergetree/in_memory_sort_buffer.h:
##########
@@ -57,7 +57,8 @@ class InMemorySortBuffer : public SortBuffer {
                        const std::vector<std::string>& 
user_defined_sequence_fields,
                        bool sequence_fields_ascending,
                        const std::shared_ptr<FieldsComparator>& key_comparator,
-                       uint64_t write_buffer_size, const 
std::shared_ptr<MemoryPool>& pool);
+                       uint64_t write_buffer_size, const 
std::shared_ptr<MemoryPool>& pool,
+                       const std::shared_ptr<FieldsComparator>& 
sort_comparator = nullptr);

Review Comment:
   Defaulting to nullptr leaves the main write path on the divergence this 
parameter exists to fix: `WriteBuffer` sorts its in-memory runs with Arrow 
`SortIndices`, while `ExternalSortBuffer` merges the spilled runs with 
`FieldsComparator`. The two orderings must agree or a spilled flush produces a 
run that is not globally sorted.
   
   The `CompareFloatingPoint` change in this PR makes them definitively 
opposite for NaN — Arrow places NaN with nulls under `NullPlacement::AtStart`, 
`FieldsComparator` now places NaN last — so a float/double sort field 
containing NaN merges incorrectly once spilling kicks in.
   
   Separately, that change also makes `-0.0 < +0.0` where the old comparator 
returned 0, which changes key equality for every existing table with a 
float/double key or sequence field. Worth splitting out, or at least calling 
out in the description.



##########
src/paimon/core/operation/file_system_write_restore.h:
##########
@@ -84,9 +84,19 @@ class FileSystemWriteRestore : public WriteRestore {
                     partition, bucket));
         }
 
+        std::vector<std::shared_ptr<IndexFileMeta>> primary_key_index_payloads;
+        if (scan_primary_key_indexes) {
+            if (index_file_handler_ == nullptr) {
+                return Status::Invalid("Primary-key index restore requires an 
index file handler.");
+            }
+            PAIMON_ASSIGN_OR_RAISE(
+                primary_key_index_payloads,
+                index_file_handler_->Scan(snapshot.value(), "btree", 
partition, bucket));

Review Comment:
   Third copy of this literal — `BtreeDefs::kIdentifier` and `kBTreeIndexType` 
(primary_key_index_definitions.cpp:38) already exist, and the value has to stay 
in sync with `PrimaryKeyIndexDefinition::IndexType()` or the restore scan 
silently returns nothing and every level gets rebuilt on each commit. A generic 
`WriteRestore` hard-coding one index family is also the wrong layer; the index 
type could come from the maintainer factory, which already supplies the 
`IndexFileHandler`.
   
   While here: `scan_primary_key_indexes = false` is a default argument on a 
virtual function (declared on both the pure virtual in `write_restore.h` and 
this override). Defaults bind statically, so a future override with a different 
default silently changes behavior depending on the static type. Better to make 
it required and update the two call sites.



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