Skip to content

Invalidate fixpoint memos after cancellation#1100

Merged
MichaReiser merged 11 commits into
salsa-rs:masterfrom
MichaReiser:micha/fixpoint-cancellation-counter
Jun 4, 2026
Merged

Invalidate fixpoint memos after cancellation#1100
MichaReiser merged 11 commits into
salsa-rs:masterfrom
MichaReiser:micha/fixpoint-cancellation-counter

Conversation

@MichaReiser

@MichaReiser MichaReiser commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the issue discussed in #1063.

Salsa "poisons" a fixpoint query when it panics when executing. All subsequent runs of that query within the same revision will panic with a PropagatedPanic. The issue with that approach is that it incorrectly assumed that the only reason a query can panic and be re-executed in the same revision is due to a bug in the query function. However, this is not the case. A query can also panic due to cancellation that isn't followed by a write.

Ideally, we'd remove the poisoning of fixpoint queries all together. But this is likely a more involved change. The challenge here is that we need a way to mark all cycle heads within a failed query as "failed" to avoid that validate_same_iteration incorrectly returns true for a memo that only reference heads from a sub-cycle because we don't traverse cycle heads recursively.

This PR introduces a new cancellation_count (u8) and packs it into the IterationCount (renamed to IterationStamp). A provisional memo can only be reused if both the iteration count and the cancellation count are equal. I used an u8 because that fits into the QueryRevisionExtra padding. Salsa will "poison" the revision when the u8 overflows. That means, Salsa will force-bump the revision in cancel_others if the cancellation count overflowed even if not followed by any writes. This has the downside that Salsa runs the more expensive deep_verify_memo for LOW durability queries during their next fetch. But that should still be cheap and I'd expect overflows to be rare.

Alternatives

Poison revision

The simplest fix here is that we poison the current revision when a query with fixpoint iteration panics. Salsa bumps the revision on the next cancellation. This is by far the simplest change, but it has the downside that we always bump the revision, including panics that are bugs in the query function.

Tracking cycle states in a central location

The main challenge with fixpoint queries is that we have no reliable way to easily evict the state of an entire cycle because the state is stored across different cycle head memos. I had Codex prototype an implementation where the cycle state is stored in a centralized location #1098 but this resulted in a refactor that's way larger than I currently have an appetite for.

However, I do think that reconsidering where and how we store cycle state might be a worthwhile refactor in the future. Not only might it allow us to remove the cycle head poisoning, it may also help reduce memory usage.

@netlify

netlify Bot commented Jun 1, 2026

Copy link
Copy Markdown

👷 Deploy Preview for salsa-rs processing.

Name Link
🔨 Latest commit 3bf6884
🔍 Latest deploy log https://app.netlify.com/projects/salsa-rs/deploys/6a1d42bd4f464c00089b3c48

@netlify

netlify Bot commented Jun 1, 2026

Copy link
Copy Markdown

Deploy Preview for salsa-rs canceled.

Name Link
🔨 Latest commit 5c4439b
🔍 Latest deploy log https://app.netlify.com/projects/salsa-rs/deploys/6a1ed13f9d5d5800082af63d

@codspeed-hq

codspeed-hq Bot commented Jun 2, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 26 untouched benchmarks


Comparing MichaReiser:micha/fixpoint-cancellation-counter (5c4439b) with master (e4ae47b)

Open in CodSpeed

@MichaReiser MichaReiser closed this Jun 2, 2026
@MichaReiser MichaReiser reopened this Jun 2, 2026
@MichaReiser MichaReiser closed this Jun 2, 2026
@MichaReiser MichaReiser reopened this Jun 2, 2026
@MichaReiser MichaReiser force-pushed the micha/fixpoint-cancellation-counter branch from 12379b4 to ce0ea9b Compare June 2, 2026 11:26
Comment thread src/cycle.rs
pub(crate) database_key_index: DatabaseKeyIndex,
pub(crate) iteration_count: AtomicIterationCount,
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) iteration: AtomicIterationStamp,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We never persist provisional memos

@MichaReiser MichaReiser force-pushed the micha/fixpoint-cancellation-counter branch from f2a2340 to 3e9062b Compare June 2, 2026 12:37

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Tests from #1085

@MichaReiser MichaReiser marked this pull request as ready for review June 2, 2026 12:52
@MichaReiser MichaReiser requested a review from carljm June 2, 2026 12:52

@carljm carljm 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.

Looks good to me! Nice find that we can remove the iteration count from ActiveQuery.

@MichaReiser MichaReiser added this pull request to the merge queue Jun 4, 2026
Merged via the queue into salsa-rs:master with commit 0d356cf Jun 4, 2026
12 checks passed
@MichaReiser MichaReiser deleted the micha/fixpoint-cancellation-counter branch June 4, 2026 06:53
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.

3 participants