Upstream Change Summary
Type: bug-fix
Difficulty: Hard
Recommendation: Adopt
Two closely related Rust engine fixes that must be ported together — they address a concurrent preempt race in target-state ownership transfer and a follow-up rollback gap:
PR #1994 closes the initial race: adds pending_process_token: Option<u128> to TargetStateInfoItem, written by pre_commit when it queues a sink action and cleared by commit_in_txn. A detection sub-pass at the top of pre_commit handles tokens: live token from same process → PendingRetry with exponential backoff (5ms → 200ms, max 8 retries); dead token from a crashed prior process → force prev_may_be_missing=true on reconcile.
PR #1996 supersedes part of #1994's design: moves pending_process_token from per-item (TargetStateInfoItem) to per-component (StablePathEntryTrackingInfo), closes a rollback gap where rollback_pending_tokens clearing per-item tokens lost the dead-token signal, and uses item.is_pending() (multi-state) directly instead of the separate detection sub-pass. Also removes dead_token_paths, deduplicates tracking_info deserialization (was twice; now once), and eliminates the detection sub-pass's own-tracking branch.
Upstream References
Relevant Upstream Files / Areas
rust/cocoindex/src/engine/ — pre_commit, commit_in_txn, Committer, target-state reconcile
rust/cocoindex/src/state_store/ — TargetStateInfoItem, StablePathEntryTrackingInfo
- Spec:
specs/target_state_ownership_transfer/concurrent_preempt_race_fix.md
Recoco Considerations
Integration Notes
Port #1994 first to understand the problem fully, then apply #1996's structural cleanup which supersedes some of #1994's intermediate design. The final state after both PRs is the target. The is_pending() predicate (multi-state item shape) is the key correctness invariant — ensure recoco's state representation supports it.
Upstream Change Summary
Type: bug-fix
Difficulty: Hard
Recommendation: Adopt
Two closely related Rust engine fixes that must be ported together — they address a concurrent preempt race in target-state ownership transfer and a follow-up rollback gap:
PR #1994 closes the initial race: adds
pending_process_token: Option<u128>toTargetStateInfoItem, written bypre_commitwhen it queues a sink action and cleared bycommit_in_txn. A detection sub-pass at the top ofpre_commithandles tokens: live token from same process →PendingRetrywith exponential backoff (5ms → 200ms, max 8 retries); dead token from a crashed prior process → forceprev_may_be_missing=trueon reconcile.PR #1996 supersedes part of #1994's design: moves
pending_process_tokenfrom per-item (TargetStateInfoItem) to per-component (StablePathEntryTrackingInfo), closes a rollback gap whererollback_pending_tokensclearing per-item tokens lost the dead-token signal, and usesitem.is_pending()(multi-state) directly instead of the separate detection sub-pass. Also removesdead_token_paths, deduplicatestracking_infodeserialization (was twice; now once), and eliminates the detection sub-pass's own-tracking branch.Upstream References
Relevant Upstream Files / Areas
rust/cocoindex/src/engine/—pre_commit,commit_in_txn,Committer, target-state reconcilerust/cocoindex/src/state_store/—TargetStateInfoItem,StablePathEntryTrackingInfospecs/target_state_ownership_transfer/concurrent_preempt_race_fix.mdRecoco Considerations
crates/recoco-core/src/engine/(pre_commit, committer),crates/recoco-core/src/state_store/rollback_pending_tokenslogic and the retry backoff constants (5ms → 200ms, max 8 retries) should be adopted as-isIntegration Notes
Port #1994 first to understand the problem fully, then apply #1996's structural cleanup which supersedes some of #1994's intermediate design. The final state after both PRs is the target. The
is_pending()predicate (multi-state item shape) is the key correctness invariant — ensure recoco's state representation supports it.