Repository navigation
fix(adonet): wrap grain state versions instead of overflowing - #11563
Merged
ReubenBond merged 6 commits intoOct 28, 2026
Merged
Conversation
Contributor
Code coverage
Report-only conclusion: regressed. The current-main baseline is commit Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities. The comparison remains report-only while normal line and branch variance is calibrated. Coverage details |
Preserve historical migrations and use current persistence scripts for fresh test databases. Require providers to reload cached SQL during upgrades and cover stale ETags and continued writes around the wrap boundary.
Use canonical provider SQL for setup and upgrades, refresh query catalogs without replacing grain state, and remove new versioned migration and historical fixture copies. Exercise repeated upgrades of populated databases and wrapped-version reads through pre-upgrade cached queries.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #8379
ADO.NET grain storage increments a 32-bit integer version inside SQL. Once a row reaches 2,147,483,647, SQL Server, PostgreSQL and MySQL reject further writes. SQLite and Oracle can commit a larger value which the provider then cannot read as an integer.
The canonical persistence scripts now advance versions using
Version % 2147483647 + 1(MODon Oracle), cycling from the maximum back to 1. Conditional mutations continue to match the supplied ETag, and a successful operation returns a different ETag. Keeping versions within the existing integer range preserves compatibility with older provider binaries and avoids rewriting the storage table to widen the column.Database setup and upgrade
Each canonical
*-Persistence.sqlscript supports setup and repeatable upgrades. New databases first run their shared Main script to create the query catalog, then the persistence script. Existing databases reapply the current persistence script: table/index setup preserves existing objects, routines are refreshed, and query keys are inserted or updated while grain payloads and unrelated queries are preserved. The new versioned migration copies and historical SQL test copies have been removed.Stop all silos using the database before applying the persistence script, then restart them so every provider reloads its cached queries. Binary rolling upgrades can proceed after that database update. MySQL recreates procedures, so reapply any routine-specific
EXECUTEgrants before restarting. Oracle and SQLite also normalize already-committed versions above the integer maximum while preserving payloads. SQLite's_11_0temporary-object names install the updated trigger on reused connections.Accepted concurrency limit
An ETag repeats after 2,147,483,647 mutations of the same row. An activation retaining that ETag for a full cycle could then compare equal to the current version and overwrite newer state (ABA). At 1,000 mutations per second, the cycle takes about 25 days. The provider has no enforced maximum stale-ETag lifetime. The maintainer has accepted this bounded ABA limitation, which is also documented in the persistence README. DynamoDB also uses a finite counter, with a different cycle length.
Boundary and upgrade coverage
The shared provider scenario covers
int.MaxValue - 1 → int.MaxValue → 1 → 2, stale write and clear rejection on both sides of the wrap, clear/delete at the maximum, and writing again after clear. It runs for SQL Server, PostgreSQL and MySQL with both clear modes, and SQLite.Repeatable-upgrade tests install non-wrapping logic over the unchanged schema, populate grain state, reapply canonical SQL twice, and assert preservation of payloads, ETags and unrelated queries plus restoration of every persistence query. The boundary scenario also reads wrapped versions through a provider retaining its pre-upgrade cached read query. SQLite additionally covers oversized-version repair and replacement of a legacy temporary trigger on an existing connection. Oracle has no automated CI coverage.
Microsoft Reviewers: Open in CodeFlow