Repository navigation
branch-4.1:[feat](paimon) support paimon-rust reader on BE - #66227
Conversation
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
b07fa00 to
b1aa749
Compare
9d13ef7 to
69e66d9
Compare
Gabriel39
left a comment
There was a problem hiding this comment.
Rechecked these findings against the updated head (69e66d9). The relevant implementation is unchanged. These comments focus on issues introduced by the Rust reader path; existing FE LIKE handling and ordinary timestamp-literal truncation are not counted as separate new regressions. This is a static review of the call chain and the pinned Rust dependency; I have not run this PR's build or end-to-end tests.
|
Reviewed head
Directory placement: Please move This follow-up is based on static call-chain and dependency-source review. I have not run this PR's build or end-to-end tests. |
|
run buildall |
|
/review |
There was a problem hiding this comment.
Static review of exact head 1762b2a4a93dae6f7867aa1c30c7436040d396c2. I am requesting changes for 11 verified defects.
Critical checkpoints:
- Correctness and predicate semantics: three P1 issues can suppress an earlier error or wrongly prune rows through NaN and casted-IN semantic mismatches. Other numeric, LIKE, NULL-safe, timestamp, and residual paths were rechecked; existing comments for column-to-column NULL-safe equality and fractional timestamps were not duplicated.
- Security and storage configuration: three P1 issues expose credentials, drop configured S3 authentication modes, or make standard OSS catalogs fail to open. Provider option precedence, table-cache identity, and additional scheme dispatch were checked without another distinct finding.
- Lifecycle, resources, and performance: Arrow C ownership, handle teardown, EOF/error/abort paths, split reuse, projection, partition/default fill, and metadata COUNT behavior were verified. One P1 issue leaves Scanner V2's adaptive row cap disconnected from the physical Rust stream.
- Compatibility and table semantics: ordinary schema evolution, snapshot/branch/relation-option, merge-on-read, deletion-vector, and same-version V1/V2 fallback paths were checked. A P1 issue routes incremental scans through the ordinary reader, and a P2 issue lacks a rolling-upgrade backend capability gate.
- Third-party/build reproducibility: static link and generated-header integration were inspected. A P1 issue trusts an unchecked ambient aarch64 crate, and a P2 issue uses unpinned online tool installation despite offline mode.
- Tests and completion: the changed unit/regression coverage was reviewed, but builds and tests were not run because this review task explicitly prohibits them. Two fresh full passes and an independent risk pass converged with
NO_NEW_VALUABLE_FINDINGS; all 26 changed files and every candidate status were swept.
No additional user-provided review focus was supplied. Existing resolved threads for NULL-safe equality, fractional timestamp filters, session timezone materialization, and same-version Scanner V1 fallback were treated as duplicate fences.
FE UT Coverage ReportIncrement line coverage |
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
a392214 to
96ad0ff
Compare
|
run buildall |
|
/review |
There was a problem hiding this comment.
Static review of exact head 96ad0ffdfd24e52185054047b36d0ce5116e67ff. I am requesting changes for five additional verified defects.
Critical checkpoints:
- Compatibility and table semantics: two P1 issues route supported fallback-read and unrestricted query-authorized scans to a Rust path that deterministically fails at split/table open. Incremental, branch/snapshot, schema-history, system-table, storage-provider, and rolling-upgrade paths were rechecked against the current threads; no additional distinct issue was substantiated.
- Third-party/build reproducibility: two P2 issues make the aarch64 build non-retryable after a post-update failure and leave the documented exact Rust-toolchain invariant unenforced across the two linked static libraries. Existing cbindgen/offline and crate-provenance threads were treated as duplicate fences.
- Regression coverage: one P2 issue compares unordered or partially ordered row sets positionally, so equivalent JNI and Rust results can flake.
- Predicate correctness, lifecycle, security, and resources: these paths were rechecked. Two real predicate defects (LIKE parsing and casted binary literals) were excluded from this PR-specific set because the authoritative base FE/JNI path already produces the same observable false-pruning; existing live findings were not duplicated.
- Completion and validation: two review rounds, three independent Round 2 passes, and a final sweep covered all 26 authoritative changed paths and converged with
NO_NEW_VALUABLE_FINDINGS. This is static evidence only; builds and tests were prohibited and were not run.
No additional user-provided review focus was supplied.
FE UT Coverage ReportIncrement line coverage |
|
/review |
|
run buildall |
Cloud UT Coverage ReportIncrement line coverage Increment coverage report
|
There was a problem hiding this comment.
Static review found seven distinct issues that should be resolved before merge: six correctness/capability failures in the new Rust Paimon path and one Rust third-party rebuild/recovery defect.
Critical checkpoints covered:
- FE selection, protocol, and capability gating: deletion-vector merge modes and ORC TIMESTAMP_LTZ remain incorrectly Rust-eligible.
- BE predicate semantics: LIKE wildcard/escape handling and casted binary RHS values can create false-negative pushdown.
- Schema evolution: the Rust C read-builder re-resolves the FE-pinned snapshot and can discard a schema-only ALTER.
- Storage/auth: enabled COS/OBS/GCS/Azure schemes are routed to parsers whose credential key families are never supplied.
- FFI ownership, split lifecycle, scanner dispatch, wire compatibility, and residual filtering were traced; no additional distinct issue survived convergence.
- Third-party reproducibility/recovery: the shared toolchain stamp is committed before a successful artifact and has no supported rotation path.
- Tests were reviewed for differential and capability coverage; the inline comments identify the missing cases.
Existing inline threads and replies were treated as duplicate fences and were not repeated. No additional user focus was provided. This was a static-only review as required; I did not run builds or tests.
FE UT Coverage ReportIncrement line coverage |
BE UT Coverage ReportIncrement line coverage Increment coverage report
|
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
|
/review |
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: Preserve the Paimon Rust reader FileScannerV2 coverage from branch-4.1 after forward-porting the implementation to master. Verify complete Rust split payloads, reject missing schema metadata, and keep PAIMON_CPP splits on the V1 fallback. ### Release note None ### Check List (For Author) - Test: Unit Test - Test code added; execution requires a BE unit-test build - `./build-support/check-format.sh` - `./build-support/check-build-hygiene.sh` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The branch-4.1 tests exercised Paimon Rust reader routing through the legacy fe-core PaimonScanNode, which no longer exists on master. Recreate that coverage at master's connector boundary and generic backend-capability intersection, including mixed-version backends, session gates, storage credentials, HDFS options, nested projections, external files, and ORC local-zone timestamps. ### Release note None ### Check List (For Author) - Test: Unit Test - `./run-fe-ut.sh --run org.apache.doris.datasource.scan.PluginDrivenScanNodeBackendCapabilityTest,org.apache.doris.connector.paimon.PaimonRustReaderSelectorTest` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The Paimon Rust predicate converter must keep null-aware runtime filters residual, but master does not expose the RuntimeFilterExpr null-aware flag that branch-4.1 receives from the Lance runtime-filter work. Expose the existing immutable state so the converter can preserve NULL probe rows instead of incorrectly pushing the unwrapped IN predicate. ### Release note None ### Check List (For Author) - Test: BE compilation - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The Paimon Rust reader batch-size unit test derived its fixture path from `__FILE__`. The master BE build rewrites source paths, so the test resolved the fixture relative to the build tree and read an empty split file. Use the repository-root-relative test data path expected by `run-be-ut.sh` so the real Rust reader fixture is loaded reliably. ### Release note None ### Check List (For Author) - Test: Unit Test - `./run-be-ut.sh --run --filter='PaimonRustTableReaderTest.*:PaimonRustPredicateConverterTest.*:PaimonReaderTest.*:FileScannerV2Test.PaimonRustSplitUsesV2Scanner' -j 12` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#66227 Problem Summary: The master connector framework did not propagate name-based nested projections when no stable nested field IDs were available. Paimon could therefore select the Rust reader for a projected nested value and BE decoded the projected Arrow struct as the full Doris struct. Master also differs from branch-4.1 in credential selection, branch resolution, and TIMESTAMP_LTZ mapping. Propagate nested projection state to connector handles, make Paimon fall back to JNI for nested projections, and align the regression fixtures with master semantics. ### Release note None ### Check List (For Author) - Test: Unit Test, FE build, and Regression test - PaimonRustReaderSelectorTest - PluginDrivenScanNodeProjectionTest - test_paimon_rust_reader_compatibility - test_paimon_rust_reader_eq_for_null - Behavior changed: No. The Rust reader remains disabled by default and unsupported nested projections fall back to JNI. - Does this need documentation: No
Ports the internal PK-vector search (ann.patch, bleem ce52f81) onto the community paimon 2.1 java client and the paimon-rust baac87c eager Top-K C API, and wires it through the FileScannerV2 rust table reader. FE - New PushDownVectorTopNIntoPaimonScan rewrite: TopN[dis] -> Project [dis := dist_fn(vec, q)] -> [Filter] -> PaimonScan becomes an index-only ANN scan producing the reader-generated __paimon_search_score_to_dis column; every dist_fn occurrence is replaced by that slot. Gated on enable_paimon_rust_reader AND enable_file_scanner_v2 (the V1 scanner rejects PAIMON_RUST). AnnTopNInfo carries query vector / column / folded limit / TVectorMetric through the scan plumbing. - PaimonScanNode plans one BucketVectorSearchSplit per (partition, bucket) via newBatchVectorSearchBuilder and serializes it with Paimon's DataOutputSerializer (the community client no longer ships BucketVectorSearchSplitSerializer). The logical search request reuses the community TExternalSearchRequest (field 39 of TFileScanRangeParams); Paimon-only tuning travels in the new TPaimonVectorSearchOptions (field 5), filtered to field-/algorithm-scoped keys because primaryKeyVectorIndexOptions seeds itself with the whole table property bag (thrift-fatal nulls, credentials, redundancy). - PaimonUtil maps Paimon VECTOR to ARRAY<FLOAT> so the distance functions type-check; the JNI connector reads VECTOR columns via getVector. BE - PaimonRustTableReader gains a vector mode: the scan range carries a TPaimonVectorPayload (TPaimonFileDesc field 20) and the reader runs the eager Top-K chain paimon_bucket_vector_search_split_deserialize -> new_scan -> new_read -> plan_from_bucket_splits -> vector_read_read, then converts paimon-rust's __paimon_search_score into the metric-native distance in place while filling the block (L2: sqrt(1/score - 1) with a catastrophic-cancellation clamp and negative sentinels for corrupt scores; inner_product: identity). Deliberately not ported from the internal patch: Alluxio path rewriting (no community equivalent), the parquet nested lazy-read page-skip optimization, and the internal-only shade/pom version bumps. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 06e99cb) Port notes (rebased onto the merged PR apache#66227, which grew further after the ann branch forked at 8272fae): - PlanNodes.thrift: TFileScanRange field 39 is taken upstream by parquet_timestamp_semantics_version (40 by contains_native_parquet), so external_search_request is renumbered to field 41 on this branch. - PaimonScanNode: keep the upstream gate chain (restTokenTable, externalFileSplit, deduplicateIgnoreDelete, rustUnsupportedMergeOption, scan.mode default check, all-backend isPaimonRustReaderSupported, PaimonRustReaderCapabilities). A vector split bypasses only the per-split PaimonRustReaderCapabilities check: its whitelist describes the batch reader (single-file PK buckets, zero delete rows), while a vector bucket legitimately spans multiple files and applies deletion vectors inside the search itself; all table/session-level gates still apply and a vector split that fails them throws loudly as before. - paimon_rust_table_reader_test.cpp: keep both the upstream AdaptiveBatchSizeBoundsWideStringReads fixture test and the ported vector / score-transform tests. Conflicts: be/test/format_v2/table/paimon_rust_table_reader_test.cpp fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/source/PaimonScanNode.java fe/fe-core/src/test/java/org/apache/doris/datasource/paimon/PaimonUtilTest.java gensrc/thrift/PlanNodes.thrift
Issue Number: None Related PR: apache#66227 Related PR: apache#68320 Problem Summary: Several unreleased master Thrift additions reused wire ids that branch-4.1 already assigned to Paimon and Iceberg fields, and master assigned different numeric values to the external table sink partition enum. Keep the branch-4.1 meanings at their established ids, move master-only fields to new trailing ids, and retain the deprecated branch routing fields ahead of the generic master routing representation. Also reserve the Paimon Rust reader capability fields at their branch ids so its later forward-port does not recreate the conflicts. None - Test: No compilation or unit tests per current validation plan - build-support/clang-format.sh - build-support/check-format.sh - git diff --check - Behavior changed: No user-visible behavior; unreleased master wire ids are aligned with branch-4.1. - Does this need documentation: No
Issue Number: None Related PR: apache#66227 Related PR: apache#68320 Problem Summary: Several unreleased master Thrift additions reused wire ids that branch-4.1 already assigned to Paimon and Iceberg fields, and master assigned different numeric values to the external table sink partition enum. Keep the branch-4.1 meanings at their established ids, move master-only fields to new trailing ids, and retain the deprecated branch routing fields ahead of the generic master routing representation. Also reserve the Paimon Rust reader capability fields at their branch ids so its later forward-port does not recreate the conflicts. None - Test: No compilation or unit tests per current validation plan - build-support/clang-format.sh - build-support/check-format.sh - git diff --check - Behavior changed: No user-visible behavior; unreleased master wire ids are aligned with branch-4.1. - Does this need documentation: No
) ### What problem does this PR solve? Issue Number: #65086 Related PR: #65868 Related PR: #66227 Related PR: #68320 Problem Summary: Master and branch-4.1 assigned incompatible meanings or numeric values to several external-table Thrift fields. In particular, `TReportExecStatusParams` field 34 carried opaque connector commit data on master but typed Paimon commit messages on branch-4.1. The external table sink partition enum and several Paimon, Iceberg, routing, query-option, and backend-capability fields also used different wire ids. This change keeps the branch-4.1 field meanings and enum values at their established ids, moves unreleased master-only fields to new trailing ids, and keeps Paimon and Iceberg commit data on independent fields. It also preserves the master transaction flow, final-report ownership transfer, Thrift message budget, acknowledgement, and cleanup behavior. ### Release note None ### Check List (For Author) - Test - [ ] Regression test - [ ] Unit Test - [x] Manual test (add detailed scripts or steps below) - `./build.sh --fe -j 12` - `ENABLE_PCH=OFF ./build.sh --be -j 12` - FE, BE, BE Java extensions, and CDC client build successfully. - BE `doris_be` links successfully and passes the GLIBC 2.17 compatibility check. - `build-support/check-format.sh` - `build-support/check-build-hygiene.sh` - `git diff --check origin/master..HEAD` - [ ] No need to test or manual test. Explain why: - [ ] This is a refactor/code format and no logic has been changed. - [ ] Previous test can cover this change. - [ ] No code files have been changed. - [ ] Other reason - Behavior changed: - [x] No. The change aligns wire compatibility for unreleased master fields. - [ ] Yes. - Does this need documentation? - [x] No. - [ ] Yes. ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label
) Related PR: apache#65883 (for master , current closed) **this pr add paimon rust reader both in scanner v1 and v2. the scanner v1 code is just for legacy, will be removed later.** Problem Summary: Adds a third BE-side reader for Paimon FORMAT_JNI splits, backed by the `paimon-rust` C bindings (`libpaimon_c.a`, statically linked). Rust Reader is gated by the session variable `enable_paimon_rust_reader` (default `false`). Compared with the existing readers: - **vs paimon-jni**: no JVM round-trip on the hot path — the split is deserialized in-process and rows arrive via the Arrow C Data Interface, which shortens the scanner critical section and removes JNI copy cost. **Architecture** FE (`PaimonScanNode`): when `enable_paimon_rust_reader` is on and the split is a `DataSplit`, encode it with paimon's native binary serialization (`PaimonUtil.encodeDataSplitToString`), stamp the range with `TPaimonReaderType.PAIMON_RUST`, and attach `db_name` / `table_name` / `paimon_table` so BE can open the table through a catalog. BE (`FileScanner::_get_next_reader`): dispatches on `reader_type`. On `PAIMON_RUST` it instantiates `PaimonRustReader`, which: 1. `paimon_catalog_create({warehouse, metastore=filesystem, ...})` - warehouse is derived from the table root path by stripping `/<db>.db/<table>` (paimon FS convention). 2. `paimon_identifier_new(db, tbl)` → `paimon_catalog_get_table` 3. `paimon_table_new_read_builder` → projection (case-insensitive) → optional filter from `PaimonRustPredicateConverter` (translates Doris push-down conjuncts into paimon-rust predicates, best-effort so any non-representable conjunct is silently dropped and re-applied by the engine). 4. `paimon_plan_from_split_bytes(split_bytes)` — one BE scanner reads exactly its FE-planned split (no re-planning). 5. `paimon_table_read_to_arrow` → streamed arrow record batches → block. Partition columns are back-filled in `on_after_read_block` from FE-provided `columns_from_path*`, mirroring `PaimonCppReader`. OSS/S3 hadoop-style credential keys (`fs.oss.*` / `fs.s3a.*`) are remapped to `AWS_ACCESS_KEY` / `AWS_ENDPOINT` / ... so paimon-rust's FileIO can authenticate. **Thirdparty** - Introduces `paimon-rust-2fb5e49` (built with Rust 1.91.0, feature `paimon/storage-hdfs`, `--locked`). - Auto-installs `cbindgen` and regenerates the C header from the Rust extern "C" surface via a locally-written `cbindgen.toml` (`language=C, include_guard=PAIMON_C_H, pragma_once=true, cpp_compat=true`), so the shipped `paimon.h` always matches the built `.a`. ### Release note Add `enable_paimon_rust_reader` session variable. When enabled, Paimon non-native reads on BE use the paimon-rust reader instead of paimon-jni / paimon-cpp. ### Check List (For Author) - Test - [x] Unit Test - [x] Manual test (add detailed scripts or steps below) 1. `CREATE CATALOG paimon_fs PROPERTIES ("type"="paimon", "paimon.catalog.type"="filesystem", "warehouse"="file:///media/ssd1/test_paimon/warehouse/");` when using "warehouse"="hdfs://.../warehouse/", add HADOOP_CONF_DIR=xx in be.conf 2. `SET enable_paimon_rust_reader=true; SET force_jni_scanner=1` 3. `SELECT` from a partitioned/DV paimon table; results must match `enable_paimon_rust_reader=false and force_jni_scanner=0`. 4. `SELECT count(*)` — should hit table-level row count push-down. 5. `WHERE a=1 AND b>2` — BE INFO log should show `paimon-rust predicate pushdown: applied`. - [x] Regression test - [ ] No need to test or manual test. - Behavior changed: - [x] No. Guarded by `enable_paimon_rust_reader` (default `false`); when off, all paths are unchanged. - Does this need documentation? - [ ] No. - [x] Yes. <!-- Add doris-website PR link here for the new session variable --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label --------- Co-authored-by: dengfangyuan <dengfangyuan@kuaishou.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Gabriel <gabrielleebuaa@gmail.com>
Issue Number: apache#65086 Related PR: apache#66227 Related PR: apache#68562 Problem Summary: Adapt the branch-4.1 Paimon Rust reader to master's connector architecture and current APIs. Convert Paimon table locations to strings at the connector boundary, use JUnit 5 for the backend capability test, and align the reverse type-mapping contract and tests with the precision-preserving implementation required by the Rust reader. None - Test: Unit Test - `./run-fe-ut.sh --run org.apache.doris.system.BackendPaimonRustCapabilityTest,org.apache.doris.connector.paimon.PaimonTypeMappingToPaimonTest` - `./build.sh --fe --clean` - `./build-support/check-format.sh` - `./build-support/check-build-hygiene.sh` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: Preserve the Paimon Rust reader FileScannerV2 coverage from branch-4.1 after forward-porting the implementation to master. Verify complete Rust split payloads, reject missing schema metadata, and keep PAIMON_CPP splits on the V1 fallback. ### Release note None ### Check List (For Author) - Test: Unit Test - Test code added; execution requires a BE unit-test build - `./build-support/check-format.sh` - `./build-support/check-build-hygiene.sh` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The branch-4.1 tests exercised Paimon Rust reader routing through the legacy fe-core PaimonScanNode, which no longer exists on master. Recreate that coverage at master's connector boundary and generic backend-capability intersection, including mixed-version backends, session gates, storage credentials, HDFS options, nested projections, external files, and ORC local-zone timestamps. ### Release note None ### Check List (For Author) - Test: Unit Test - `./run-fe-ut.sh --run org.apache.doris.datasource.scan.PluginDrivenScanNodeBackendCapabilityTest,org.apache.doris.connector.paimon.PaimonRustReaderSelectorTest` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The Paimon Rust predicate converter must keep null-aware runtime filters residual, but master does not expose the RuntimeFilterExpr null-aware flag that branch-4.1 receives from the Lance runtime-filter work. Expose the existing immutable state so the converter can preserve NULL probe rows instead of incorrectly pushing the unwrapped IN predicate. ### Release note None ### Check List (For Author) - Test: BE compilation - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The Paimon Rust reader batch-size unit test derived its fixture path from `__FILE__`. The master BE build rewrites source paths, so the test resolved the fixture relative to the build tree and read an empty split file. Use the repository-root-relative test data path expected by `run-be-ut.sh` so the real Rust reader fixture is loaded reliably. ### Release note None ### Check List (For Author) - Test: Unit Test - `./run-be-ut.sh --run --filter='PaimonRustTableReaderTest.*:PaimonRustPredicateConverterTest.*:PaimonReaderTest.*:FileScannerV2Test.PaimonRustSplitUsesV2Scanner' -j 12` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#66227 Problem Summary: The master connector framework did not propagate name-based nested projections when no stable nested field IDs were available. Paimon could therefore select the Rust reader for a projected nested value and BE decoded the projected Arrow struct as the full Doris struct. Master also differs from branch-4.1 in credential selection, branch resolution, and TIMESTAMP_LTZ mapping. Propagate nested projection state to connector handles, make Paimon fall back to JNI for nested projections, and align the regression fixtures with master semantics. ### Release note None ### Check List (For Author) - Test: Unit Test, FE build, and Regression test - PaimonRustReaderSelectorTest - PluginDrivenScanNodeProjectionTest - test_paimon_rust_reader_compatibility - test_paimon_rust_reader_eq_for_null - Behavior changed: No. The Rust reader remains disabled by default and unsupported nested projections fall back to JNI. - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227, apache#68320, apache#68837 Problem Summary: The Paimon Rust reader could admit current-schema nanosecond timestamps outside Arrow nanosecond range, ignore the force_jni_scanner escape hatch, and keep returning Doris blocks at the initial row cap after adaptive sizing changed it. Route precision 7-9 timestamps through JNI, honor force_jni_scanner, and slice retained Arrow batches according to the latest Doris row cap. The rolling-upgrade Thrift field conflict is now handled by prerequisite PR apache#68837 and is intentionally not duplicated here. ### Release note Paimon Rust reads now honor timestamp, force-JNI, and adaptive block-size safeguards. ### Check List (For Author) - Test: Unit Test - Before rebase: targeted FE unit tests, FE checkstyle, affected BE object compilation, BE format, build hygiene, and clang-tidy - After rebase: conflict and diff checks only; full compilation intentionally skipped - External regression test not run locally - Behavior changed: Yes, unsafe or explicitly forced Paimon Rust scans now fall back to JNI - Does this need documentation: No
) Related PR: apache#65883 (for master , current closed) **this pr add paimon rust reader both in scanner v1 and v2. the scanner v1 code is just for legacy, will be removed later.** Problem Summary: Adds a third BE-side reader for Paimon FORMAT_JNI splits, backed by the `paimon-rust` C bindings (`libpaimon_c.a`, statically linked). Rust Reader is gated by the session variable `enable_paimon_rust_reader` (default `false`). Compared with the existing readers: - **vs paimon-jni**: no JVM round-trip on the hot path — the split is deserialized in-process and rows arrive via the Arrow C Data Interface, which shortens the scanner critical section and removes JNI copy cost. **Architecture** FE (`PaimonScanNode`): when `enable_paimon_rust_reader` is on and the split is a `DataSplit`, encode it with paimon's native binary serialization (`PaimonUtil.encodeDataSplitToString`), stamp the range with `TPaimonReaderType.PAIMON_RUST`, and attach `db_name` / `table_name` / `paimon_table` so BE can open the table through a catalog. BE (`FileScanner::_get_next_reader`): dispatches on `reader_type`. On `PAIMON_RUST` it instantiates `PaimonRustReader`, which: 1. `paimon_catalog_create({warehouse, metastore=filesystem, ...})` - warehouse is derived from the table root path by stripping `/<db>.db/<table>` (paimon FS convention). 2. `paimon_identifier_new(db, tbl)` → `paimon_catalog_get_table` 3. `paimon_table_new_read_builder` → projection (case-insensitive) → optional filter from `PaimonRustPredicateConverter` (translates Doris push-down conjuncts into paimon-rust predicates, best-effort so any non-representable conjunct is silently dropped and re-applied by the engine). 4. `paimon_plan_from_split_bytes(split_bytes)` — one BE scanner reads exactly its FE-planned split (no re-planning). 5. `paimon_table_read_to_arrow` → streamed arrow record batches → block. Partition columns are back-filled in `on_after_read_block` from FE-provided `columns_from_path*`, mirroring `PaimonCppReader`. OSS/S3 hadoop-style credential keys (`fs.oss.*` / `fs.s3a.*`) are remapped to `AWS_ACCESS_KEY` / `AWS_ENDPOINT` / ... so paimon-rust's FileIO can authenticate. **Thirdparty** - Introduces `paimon-rust-2fb5e49` (built with Rust 1.91.0, feature `paimon/storage-hdfs`, `--locked`). - Auto-installs `cbindgen` and regenerates the C header from the Rust extern "C" surface via a locally-written `cbindgen.toml` (`language=C, include_guard=PAIMON_C_H, pragma_once=true, cpp_compat=true`), so the shipped `paimon.h` always matches the built `.a`. ### Release note Add `enable_paimon_rust_reader` session variable. When enabled, Paimon non-native reads on BE use the paimon-rust reader instead of paimon-jni / paimon-cpp. ### Check List (For Author) - Test - [x] Unit Test - [x] Manual test (add detailed scripts or steps below) 1. `CREATE CATALOG paimon_fs PROPERTIES ("type"="paimon", "paimon.catalog.type"="filesystem", "warehouse"="file:///media/ssd1/test_paimon/warehouse/");` when using "warehouse"="hdfs://.../warehouse/", add HADOOP_CONF_DIR=xx in be.conf 2. `SET enable_paimon_rust_reader=true; SET force_jni_scanner=1` 3. `SELECT` from a partitioned/DV paimon table; results must match `enable_paimon_rust_reader=false and force_jni_scanner=0`. 4. `SELECT count(*)` — should hit table-level row count push-down. 5. `WHERE a=1 AND b>2` — BE INFO log should show `paimon-rust predicate pushdown: applied`. - [x] Regression test - [ ] No need to test or manual test. - Behavior changed: - [x] No. Guarded by `enable_paimon_rust_reader` (default `false`); when off, all paths are unchanged. - Does this need documentation? - [ ] No. - [x] Yes. <!-- Add doris-website PR link here for the new session variable --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label --------- Co-authored-by: dengfangyuan <dengfangyuan@kuaishou.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Gabriel <gabrielleebuaa@gmail.com>
Issue Number: apache#65086 Related PR: apache#66227 Related PR: apache#68562 Problem Summary: Adapt the branch-4.1 Paimon Rust reader to master's connector architecture and current APIs. Convert Paimon table locations to strings at the connector boundary, use JUnit 5 for the backend capability test, and align the reverse type-mapping contract and tests with the precision-preserving implementation required by the Rust reader. None - Test: Unit Test - `./run-fe-ut.sh --run org.apache.doris.system.BackendPaimonRustCapabilityTest,org.apache.doris.connector.paimon.PaimonTypeMappingToPaimonTest` - `./build.sh --fe --clean` - `./build-support/check-format.sh` - `./build-support/check-build-hygiene.sh` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: Preserve the Paimon Rust reader FileScannerV2 coverage from branch-4.1 after forward-porting the implementation to master. Verify complete Rust split payloads, reject missing schema metadata, and keep PAIMON_CPP splits on the V1 fallback. ### Release note None ### Check List (For Author) - Test: Unit Test - Test code added; execution requires a BE unit-test build - `./build-support/check-format.sh` - `./build-support/check-build-hygiene.sh` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The branch-4.1 tests exercised Paimon Rust reader routing through the legacy fe-core PaimonScanNode, which no longer exists on master. Recreate that coverage at master's connector boundary and generic backend-capability intersection, including mixed-version backends, session gates, storage credentials, HDFS options, nested projections, external files, and ORC local-zone timestamps. ### Release note None ### Check List (For Author) - Test: Unit Test - `./run-fe-ut.sh --run org.apache.doris.datasource.scan.PluginDrivenScanNodeBackendCapabilityTest,org.apache.doris.connector.paimon.PaimonRustReaderSelectorTest` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The Paimon Rust predicate converter must keep null-aware runtime filters residual, but master does not expose the RuntimeFilterExpr null-aware flag that branch-4.1 receives from the Lance runtime-filter work. Expose the existing immutable state so the converter can preserve NULL probe rows instead of incorrectly pushing the unwrapped IN predicate. ### Release note None ### Check List (For Author) - Test: BE compilation - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227 Problem Summary: The Paimon Rust reader batch-size unit test derived its fixture path from `__FILE__`. The master BE build rewrites source paths, so the test resolved the fixture relative to the build tree and read an empty split file. Use the repository-root-relative test data path expected by `run-be-ut.sh` so the real Rust reader fixture is loaded reliably. ### Release note None ### Check List (For Author) - Test: Unit Test - `./run-be-ut.sh --run --filter='PaimonRustTableReaderTest.*:PaimonRustPredicateConverterTest.*:PaimonReaderTest.*:FileScannerV2Test.PaimonRustSplitUsesV2Scanner' -j 12` - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#66227 Problem Summary: The master connector framework did not propagate name-based nested projections when no stable nested field IDs were available. Paimon could therefore select the Rust reader for a projected nested value and BE decoded the projected Arrow struct as the full Doris struct. Master also differs from branch-4.1 in credential selection, branch resolution, and TIMESTAMP_LTZ mapping. Propagate nested projection state to connector handles, make Paimon fall back to JNI for nested projections, and align the regression fixtures with master semantics. ### Release note None ### Check List (For Author) - Test: Unit Test, FE build, and Regression test - PaimonRustReaderSelectorTest - PluginDrivenScanNodeProjectionTest - test_paimon_rust_reader_compatibility - test_paimon_rust_reader_eq_for_null - Behavior changed: No. The Rust reader remains disabled by default and unsupported nested projections fall back to JNI. - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227, apache#68320, apache#68837 Problem Summary: The Paimon Rust reader could admit current-schema nanosecond timestamps outside Arrow nanosecond range, ignore the force_jni_scanner escape hatch, and keep returning Doris blocks at the initial row cap after adaptive sizing changed it. Route precision 7-9 timestamps through JNI, honor force_jni_scanner, and slice retained Arrow batches according to the latest Doris row cap. The rolling-upgrade Thrift field conflict is now handled by prerequisite PR apache#68837 and is intentionally not duplicated here. ### Release note Paimon Rust reads now honor timestamp, force-JNI, and adaptive block-size safeguards. ### Check List (For Author) - Test: Unit Test - Before rebase: targeted FE unit tests, FE checkstyle, affected BE object compilation, BE format, build hygiene, and clang-tidy - After rebase: conflict and diff checks only; full compilation intentionally skipped - External regression test not run locally - Behavior changed: Yes, unsafe or explicitly forced Paimon Rust scans now fall back to JNI - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#65086 Related PR: apache#66227, apache#68320, apache#68837 Problem Summary: Paimon Rust reads could pass a sliced Arrow RecordBatch with a non-zero array offset into Doris SerDes, causing adaptive wide-string reads to fail. Explicit Rust-reader tests could also continue through native planning or force JNI while expecting Rust profiles. Read the requested row range directly from the original Arrow batch, give an explicitly enabled compatible Rust reader priority over native planning while preserving force-JNI and metadata-column behavior, and align the affected regression suites with those routing semantics. ### Release note Fix Paimon Rust reader adaptive batches and explicit reader selection. ### Check List (For Author) - Test: Unit Test - PaimonRustTableReaderTest.AdaptiveBatchSizeBoundsWideStringReads - External regression tests not run locally - Behavior changed: Yes, explicitly enabled compatible Paimon Rust reads take priority over native planning; force JNI and metadata-column scans retain their existing behavior - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#66227 Problem Summary: The previous commit made the two completion-state helpers of `Profile` synchronized on the Profile monitor, as branch-4.1 apache#66227 does. That inverts the lock order with `ProfileManager`: `ProfileManager.getProfile()` renders a profile under the manager's read lock, and `getProfileByLevel()` then waits for the Profile monitor, while `Profile.updateSummary()` holds the monitor and calls `ProfileManager.pushProfile()`, which waits for the manager's write lock (`clearExecutionProfiles()` and `removeProfile()` do the same). Viewing a running profile at the moment its query finishes could therefore hang the query and every later profile operation. The helpers now synchronize on a dedicated lock instead. Under it they only take the execution profile's report lock and the summary's info-string lock, and neither of those is held while waiting for the Profile monitor or a manager lock, so the storage and display updates stay serialized without a cycle. ### Release note None ### Check List (For Author) - Test: Unit Test - `ProfileCompletionStateTest#renderingDoesNotWaitForProfileMonitor` renders a profile while the test holds the Profile monitor; with the synchronized helpers it times out. `ProfileCompletionStateTest` and `ProfileManagerTest` pass (36 tests). - Behavior changed: No - Does this need documentation: No Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
What problem does this PR solve?
Related PR: #65883 (for master , current closed)
this pr add paimon rust reader both in scanner v1 and v2.
the scanner v1 code is just for legacy, will be removed later.
Problem Summary:
Adds a third BE-side reader for Paimon FORMAT_JNI splits, backed by the
paimon-rustC bindings (libpaimon_c.a, statically linked). Rust Reader is gated by the session variableenable_paimon_rust_reader(defaultfalse).Compared with the existing readers:
deserialized in-process and rows arrive via the Arrow C Data Interface,
which shortens the scanner critical section and removes JNI copy cost.
Architecture
FE (
PaimonScanNode): whenenable_paimon_rust_readeris on and the splitis a
DataSplit, encode it with paimon's native binary serialization(
PaimonUtil.encodeDataSplitToString), stamp the range withTPaimonReaderType.PAIMON_RUST, and attachdb_name/table_name/paimon_tableso BE can open the table through a catalog.BE (
FileScanner::_get_next_reader): dispatches onreader_type. OnPAIMON_RUSTit instantiatesPaimonRustReader, which:paimon_catalog_create({warehouse, metastore=filesystem, ...})/<db>.db/<table>(paimon FS convention).paimon_identifier_new(db, tbl)→paimon_catalog_get_tablepaimon_table_new_read_builder→ projection (case-insensitive) →optional filter from
PaimonRustPredicateConverter(translates Dorispush-down conjuncts into paimon-rust predicates, best-effort so any
non-representable conjunct is silently dropped and re-applied by the
engine).
paimon_plan_from_split_bytes(split_bytes)— one BE scanner readsexactly its FE-planned split (no re-planning).
paimon_table_read_to_arrow→ streamed arrow record batches → block.Partition columns are back-filled in
on_after_read_blockfromFE-provided
columns_from_path*, mirroringPaimonCppReader. OSS/S3hadoop-style credential keys (
fs.oss.*/fs.s3a.*) are remapped toAWS_ACCESS_KEY/AWS_ENDPOINT/ ... so paimon-rust's FileIO canauthenticate.
Thirdparty
paimon-rust-2fb5e49(built with Rust 1.91.0, featurepaimon/storage-hdfs,--locked).cbindgenand regenerates the C header from the Rustextern "C" surface via a locally-written
cbindgen.toml(
language=C, include_guard=PAIMON_C_H, pragma_once=true, cpp_compat=true),so the shipped
paimon.halways matches the built.a.Release note
Add
enable_paimon_rust_readersession variable. When enabled, Paimonnon-native reads on BE use the paimon-rust reader instead of paimon-jni /
paimon-cpp.
Check List (For Author)
Test
CREATE CATALOG paimon_fs PROPERTIES ("type"="paimon", "paimon.catalog.type"="filesystem", "warehouse"="file:///media/ssd1/test_paimon/warehouse/");when using "warehouse"="hdfs://.../warehouse/", add HADOOP_CONF_DIR=xx in be.confSET enable_paimon_rust_reader=true; SET force_jni_scanner=1SELECTfrom a partitioned/DV paimon table; results must matchenable_paimon_rust_reader=false and force_jni_scanner=0.SELECT count(*)— should hit table-level row count push-down.WHERE a=1 AND b>2— BE INFO log should showpaimon-rust predicate pushdown: applied.Behavior changed:
enable_paimon_rust_reader(defaultfalse); when off, all paths are unchanged.Does this need documentation?
Check List (For Reviewer who merge this PR)