Skip to content

[Python] Dispatch row-id mutations and isolate write executors - #10753

Merged
JingsongLi merged 6 commits into
apache:masterfrom
JingsongLi:codex/native-write-execution-coverage
Oct 22, 2026
Merged

JingsongLi merged 6 commits into
apache:masterfrom
JingsongLi:codex/native-write-execution-coverage

Conversation

@JingsongLi

@JingsongLi JingsongLi commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Keep the public write/update APIs focused on configuration, validation and delegation. Cover direct row-ID update, row-ID delete and shard-updater construction with the existing Native implementation, and use Rust's writer metadata for postpone bucket planning.

Changes

  • Select and cache an execution backend before direct TableUpdateByRowId, TableDeleteByRowId and ShardTableUpdator construction loads or rewrites target files. Rust already provides these mutation APIs.
  • Remove Pure schema/routing/file-rewrite/assignment private-method forwarding from the public writers, updates, upserts and row-ID classes. Python executors invoke their own private helpers. Row-ID update/delete executors own their captured index and staging state.
  • Preserve existing public method signatures, class paths, callbacks and public subclass/instance hooks, including write_arrow_batch overrides used by Arrow and Pandas input.
  • Once Python is selected, keep nested updater/deleter resources in Python, including all local MERGE actions. Avoid a second Native preparation after row-ID factory fallback. Execution failures are never replayed in another backend.
  • Route direct PostponeBucketPlanner metadata loading through dispatch. Native uses the Core write builder's resolve_bucket_plan() getter, preserving writer access without adding SELECT authorization. Read the Arrow columns positionally so a partition named total_buckets remains valid.
  • Preserve Ray's broadcast precomputed indexes/anchor ranges, their captured snapshots and the existing no-per-worker-manifest-rescan behavior. Those precomputed worker paths remain explicitly Python; this PR does not claim Native support for transporting that private index.
  • Keep public validation, shared Arrow/row inputs, bucket arithmetic, transport metadata and resource helpers outside execution. Update the execution-boundary documentation.
  • Expose WriteBuilder.with_commit_user() consistently on batch, stream and postpone builders. Use the public Rust with_commit_user() and with_blob_uri_reader_factory() configuration methods without compatibility aliases, and document commit-identity capture for operations created from a builder.

Dependency

The writer-owned resolve_bucket_plan getter and public binding configuration names require apache/paimon-rust#1200. Keep this PR draft until that dependency merges. Native CI continues building Rust main; no SDK-version probes or compatibility shims were added.

Tests

  • Execution-boundary affected-module + write-suite verification: 74 modules, 1766 passed and 3055 skipped. The distributed input module ran in a separate process: 6 passed. Total: 1772 passed, 3055 skipped across 75 modules.
  • PyArrow 16 focused compatibility/shard/backend-selection regressions: 93 passed.
  • Added real round trips for writers without public private-method hooks, selected-Python update/upsert/delete/shard/MERGE operations, fresh-process Native import isolation, failure-without-replay, single preparation, captured metadata reuse and bucket-plan transport.
  • Native integration cases exercise the three direct mutation constructors and verify committed results without initializing Python executors. These extension-dependent tests are skipped locally.
  • Changed-file Flake8, Python 3.6 grammar checks (72 files), and git diff --check passed.
  • Independent cross-reviews found and repaired public batch-hook dispatch, repeated Native preparation, Pure MERGE backend reselection and duplicate Arrow field-name handling. No remaining actionable issue was found in the final passes.
  • Additional public-API verification: 91 passed / 463 skipped with PyArrow 19; 74 passed / 41 skipped with PyArrow 16. Three real-table regressions cover batch and stream writer/update/committer identity capture, builder reconfiguration, and postpone snapshots. Changed-file Flake8, Python 3.6 grammar, and diff checks passed.
  • Getter-naming follow-up: Native calls and mocks use resolve_bucket_plan(); with_bucket_plan() remains the configuration API. Targeted postpone planning/routing/identity/write tests: 103 passed, 9 skipped; Flake8, Python 3.6 grammar and diff checks passed.
  • No Native extension was installed or rebuilt locally. CI runs the Native integration tests after the Rust dependency merges.

Direct writer construction and centralized dispatch

  • Direct TableWrite, BatchTableWrite, StreamTableWrite and PostponeFixedBucketBatchTableWrite construction now selects Native through the same preparation boundary as builders. The original public classes, constructor/method signatures and subclass/instance batch hooks remain intact.
  • Cache the selected execution implementation. All Python execution construction in the write layer is centralized in backend_dispatch; public modules retain only three TYPE_CHECKING imports. Remove unused update bridges and the obsolete Python shard factory wrapper.
  • Explicit Python writer factories bypass public constructors, so selected-Python MERGE, upsert, shard and diagnostic paths cannot select Native again. Preserve Arrow/Pandas batch hooks even after an explicit pre-write switch from Native to Python.
  • Retain batch preparation's one-attempt boundary, signed stream commit identifiers, pre-write diagnostic properties and failure propagation without replaying writes.
  • Fix direct postpone writers to reuse the captured Python bucket planner after a diagnostic switch, including distributed write options and overwrite. The regression was verified failing before the fix and passing afterward.
  • Update the write guide and execution-boundary documentation.

Verification for the direct-construction follow-up

  • 77 affected/write test modules: 1818 passed, 3055 skipped. The distributed input module ran separately: 6 passed. Total: 1824 passed, 3055 skipped across 78 modules.
  • PyArrow 16 compatibility regressions: 141 passed, 1 skipped.
  • Added 45 direct-writer cases and four factory/state regressions. Four fresh-process cases prohibit all execution.python imports while constructing, writing, preparing and closing the real thin Native adapters with fake Core handles.
  • Independent review confirmed unchanged public signatures and found the postpone planner reselection issue; the second pass found no further actionable issue.
  • Changed-file Flake8, Python 3.6 grammar (18 files), and git diff --check passed. No Native extension was installed or rebuilt. Extension-dependent integration tests remain skipped locally and require CI after the Rust dependency merges.

Direct writer API review follow-up

  • Remove arbitrary public TableWrite attribute forwarding, which exposed the Native batch executor's prepare_commit() on the base writer only in Native mode. Keep explicit configuration metadata and documented property delegation instead.
  • Keep batch_committed on BatchTableWrite and its subclasses; neither the base writer nor StreamTableWrite exposes batch-only state.
  • Add eight backend-independent public API regressions covering the four direct writer classes, configuration metadata, prepare_commit signatures and batch-state visibility. Confirm the regressions fail before the fixes.
  • Repeated independent reviews covered direct construction, subclass hooks, Native/Python switching, failure propagation, preparation lifecycle, public signatures, Ray/Postpone dispatch and Native import isolation. No further actionable regression was found.
  • Re-run 77 affected/write modules: 1826 passed, 3055 skipped; separate distributed input tests: 6 passed. Total: 1832 passed, 3055 skipped across 78 modules. PyArrow 16 focused verification: 173 passed, 4 skipped. Changed-file Flake8, Python 3.6 grammar and git diff --check passed.
  • No Native extension was installed or rebuilt. Fresh-process tests prohibit Python execution imports while exercising the real Native adapters with fake Core handles; extension-dependent integration tests remain for CI.

Master CI regression fixes

  • Retain bucket routing keys for every positive fixed bucket count, including one bucket. Route before projecting physical write columns, matching Java. Add 16 real batch/stream round trips across row, Arrow batch/table and Pandas inputs; verify the routing key is not physically written.
  • Authorize shard operations and direct row-ID update/delete constructors before preparing either backend or reading target snapshots. Propagate explicit Python TableNoPermissionException without selecting Python execution. Keep ForkSafetyError cause/context identity detection ahead of permission handling.
  • Add REST authorization regressions for denied, row-filtered and masked grants, plus permission refusal during Native preparation. Assert no fallback executor, snapshot read or staged file; update isolated constructor test metadata to model unrestricted tables explicitly.
  • Remove an obsolete E2E debug print accessing row_ranges. Update Native append full-text, PK full-text errors, Blob consumer reconfiguration and LeRobot assertions to test current supported behavior and the public reader contract.
  • Handle legal empty streaming plans in tests. Resolve the actual system IANA zone when TZ is unset instead of assuming UTC; do not guess from ambiguous CST/GMT abbreviations or change process timezone/production casts. The reported 31 temporal failures reproduce independently on a Shanghai host, so suite-order pollution is not required to explain them.
  • Update fork-safety tests to observe executor construction rather than removed public implementation helpers. Preserve direct/cause/context errors, no-fallback/no-replay checks, safe ordinary-error fallback and direct row-ID constructors; add permission-wrapper ForkSafety priority regressions.

Verification for this follow-up:

  • Final affected/write suite: 1926 passed, 3055 skipped across 78 modules.
  • Original single-bucket regression plus new round trips: Python 3.8 / Arrow 17 and Python 3.11 / Arrow 22 each 20 passed, 4 skipped; Python 3.13 / Arrow 19 original cases 4 passed, 4 skipped (new 16 round trips are included in the affected/write suite).
  • Real Native stream/temporal reads with TZ unset on a Shanghai host: 82 passed, with 117 Native plans and 114 Native reads. Native append/PK full-text and LeRobot public-reader checks passed; the real Native stream Blob consumer reconfiguration also passed.
  • Authorization/refusal matrix: 32 passed. Independent production-diff review and 38 authorization/routing/ForkSafety checks passed. Changed-file Flake8, Python 3.6 grammar (16 files) and git diff --check passed.
  • Local Native batch writing cannot be fully verified with the installed pre-[flink] Supports Kafka with canal CDC format ingestion #1200 SDK: its batch builder lacks the public with_commit_user method. The strict Native batch Blob test still fails that dependency assertion locally. No SDK compatibility shim, extension rebuild or installation was added; this PR remains draft on Rust [flink] Supports Kafka with canal CDC format ingestion #1200. Java/Python E2E was not rerun for the removed debug print. No complete Native suite or remote CI-green result is claimed.

@leaves12138 leaves12138 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@JingsongLi
JingsongLi marked this pull request as ready for review October 22, 2026 14:31
@JingsongLi
JingsongLi merged commit 7ee8443 into apache:master Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants