fix(core): prevent catalog races in concurrent same-context transforms - #2495
Conversation
apply_wren_on_ctx now builds derived session states on a per-call
private copy of the base context's catalog list, so concurrent
transform_sql_with_ctx calls on a shared context no longer observe each
other's half-built wren catalog ("table not found" / "already exists" /
cross-schema writes). Top-level catalog membership becomes an
apply-time snapshot while copied providers' internals stay live-shared,
so callers must finish registering physical catalogs before
transforming. Removing wren-core-py's call_lock is a follow-up gated on
this landing.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughWren context application now clones top-level catalog membership into a private catalog list, shares existing catalog providers, validates catalog-list identity, and adds concurrent contract tests for isolation and visibility semantics. ChangesCatalog isolation
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant apply_wren_on_ctx
participant CatalogProviderList
participant SessionStateBuilder
participant SessionState
apply_wren_on_ctx->>CatalogProviderList: clone top-level catalogs
CatalogProviderList-->>apply_wren_on_ctx: private catalog-list Arc
apply_wren_on_ctx->>SessionStateBuilder: configure catalog list
SessionStateBuilder-->>SessionState: build derived state
apply_wren_on_ctx->>SessionState: validate Arc identity
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
core/wren-core/core/src/mdl/context.rs (1)
57-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument the registration precondition on
apply_wren_on_ctx.The correctness-critical requirement to finish top-level physical catalog registration is currently documented only on a private helper. Add it to the public function’s rustdoc so callers see the snapshot contract.
Also applies to: 110-113
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/wren-core/core/src/mdl/context.rs` around lines 57 - 62, Update the public function `apply_wren_on_ctx` rustdoc to explicitly state that callers must complete top-level physical-catalog registration before starting a transform and that its catalog enumeration is only a best-effort, non-atomic snapshot. Keep the existing private-helper documentation unchanged.core/wren-core/core/src/mdl/mod.rs (1)
5294-5333: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd the replacement half of the snapshot contract.
This verifies post-apply additions, but not replacement of a catalog that existed at apply time. Replace an existing base catalog after applying, then assert the derived context retains the original
Arcwhile the base exposes the replacement.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/wren-core/core/src/mdl/mod.rs` around lines 5294 - 5333, Extend the test new_top_level_catalog_after_apply_is_absent_from_derived_ctx to register a catalog before apply, retain its original Arc, replace that catalog on base_ctx after apply, and assert base_ctx exposes the replacement while derived_ctx still exposes the original Arc. Preserve the existing post-apply addition assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@core/wren-core/core/src/mdl/context.rs`:
- Around line 57-62: Update the public function `apply_wren_on_ctx` rustdoc to
explicitly state that callers must complete top-level physical-catalog
registration before starting a transform and that its catalog enumeration is
only a best-effort, non-atomic snapshot. Keep the existing private-helper
documentation unchanged.
In `@core/wren-core/core/src/mdl/mod.rs`:
- Around line 5294-5333: Extend the test
new_top_level_catalog_after_apply_is_absent_from_derived_ctx to register a
catalog before apply, retain its original Arc, replace that catalog on base_ctx
after apply, and assert base_ctx exposes the replacement while derived_ctx still
exposes the original Arc. Preserve the existing post-apply addition assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: a5e83453-c573-4b76-a1ff-8686d601e428
📒 Files selected for processing (2)
core/wren-core/core/src/mdl/context.rscore/wren-core/core/src/mdl/mod.rs
|
Nice fix — the root cause is real: One thing worth calling out for the consumer side (
Two implications:
Neither blocks this PR (it's wren-core-only and correct as-is) — just flagging the follow-up so the guarantee doesn't quietly regress later. |
|
Thanks for the careful review — this is very helpful. Your reading is correct: the current Python methods register physical tables into I’d like to address this in a separate I’ll keep this PR scoped to |
|
Thanks for filing #2504 and for the thoughtful review! I also opened #2510 to share one Tokio runtime across Python session Addressing #2504 after #2510 should be cleaner, since removing the |
Problem
apply_wren_on_ctxbuilds derived DataFusion session states from a baseSessionContext.SessionStateBuilder::new_from_existingshares the base context's top-levelcatalog_list.register_table_with_mdlthen registers a new catalog before adding its models and views. Concurrent calls using the same base context can therefore replace or observe each other's partially constructed catalog.This can cause:
table not foundtable already existsFix
Create a private top-level catalog-list snapshot for each
apply_wren_on_ctxcall and attach it to the derived session states.The isolation contract is:
Arc-shared, preserving access to live physical catalogs.An internal invariant check returns a DataFusion internal error if the final derived state does not retain the per-call private list.
Tests
Added coverage for:
The concurrent stress test uses eight OS threads with current-thread Tokio runtimes and repeatedly contends on the same catalog key.
Verification
cargo fmt --all -- --checkcargo check --all-targetsRUST_MIN_STACK=8388608 cargo test --lib --tests --bins— 147 core tests and sqllogictests passedcargo clippy --all-targets --all-features -- -D warningsRelated
#2485 exposed this latent race by allowing concurrent Python calls to enter the Rust execution path. This PR fixes the underlying catalog-list isolation in
wren-coreand can merge independently.The per-context
call_lockin #2485 remains in place. Removing it and measuring same-context throughput will be a separate follow-up after both PRs land.Summary by CodeRabbit