Skip to content

feat(transactions): add read-committed reads to ITransactionalState - #11615

Open
scalalang2 wants to merge 1 commit into
dotnet:mainfrom
scalalang2:feat/transactions-read-committed
Open

scalalang2 wants to merge 1 commit into
dotnet:mainfrom
scalalang2:feat/transactions-read-committed

Conversation

@scalalang2

@scalalang2 scalalang2 commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Disclaimer:
This code was written by Claude Fable 5. but I reviewed it myself.

Add ReadIsolation and a PerformRead overload that returns the most recently committed state without starting a transaction, taking a lock, or writing to storage. A read-committed read is rejected inside an ambient transaction because the snapshot is outside that transaction's locks and would break serializability.

Adding interface members is an intentional break against the 10.4.0 package baseline, so CompatibilitySuppressions.xml is added for Orleans.Transactions and Orleans.Transactions.TestKit.Base.

Closes #11611

Microsoft Reviewers: Open in CodeFlow

Add ReadIsolation and a PerformRead overload that returns the most
recently committed state without starting a transaction, taking a lock,
or writing to storage. A read-committed read is rejected inside an
ambient transaction because the snapshot is outside that transaction's
locks and would break serializability.

Adding interface members is an intentional break against the 10.4.0
package baseline, so CompatibilitySuppressions.xml is added for
Orleans.Transactions and Orleans.Transactions.TestKit.Base.

Closes dotnet#11611
@github-actions

Copy link
Copy Markdown
Contributor

Code coverage

Metric Pull request Current main Variance
Lines 83.86% (120,945 / 144,225) 83.83% (120,850 / 144,155) +0.0252 pp
Branches 73.68% (36,281 / 49,240) 73.67% (36,263 / 49,222) +0.0096 pp

Report-only conclusion: improved.

The current-main baseline is commit 30137dd94f and uses the same reviewed coverage matrix.

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

@ReubenBond
ReubenBond requested a balanced review from Copilot October 28, 2026 20:09
@ReubenBond ReubenBond changed the title Add read-committed reads to ITransactionalState feat(transactions): add read-committed reads to ITransactionalState Oct 28, 2026

Copilot AI 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.

🟡 Changes recommended

The new read path lacks a deterministic test proving nonblocking reads of the previous committed value during a pending write that later aborts, and its public documentation omits mutation restrictions and visibility-lag caveats.

3 open issues
What changed in this PR

Adds non-transactional committed reads to Orleans transactional state, addressing #11611 by avoiding the storage writes required by read-only transactions.

Changes:

  • Adds ReadIsolation and a PerformRead overload using the locally committed snapshot, with ambient-transaction rejection.
  • Extends transaction test grains and runners to check committed reads and transaction rejection.
  • Updates generated API surfaces, grain contracts, and compatibility suppressions for the intentional interface additions.
File Description
test/​Transactions/​Orleans.Transactions.Tests/​TransactionCoordinatorInputValidationTests.cs Adds the committed-read test stub.
test/​Transactions/​Orleans.Transactions.Tests/​FaultInjectionTransactionalStateAttributeMapperTests.cs Updates the recording state for the overload.
test/​Transactions/​Orleans.Transactions.Tests/​ExclusiveLockCoordinatorInputValidationTests.cs Adds unexpected-call handling for committed reads.
test/​Transactions/​Orleans.Transactions.Tests/​ConsistencyTestGrainInputValidationTests.cs Updates the state test double.
src/​Orleans.Transactions/​State/​TransactionQueue.cs Exposes the stable committed snapshot.
src/​Orleans.Transactions/​State/​TransactionalState.cs Implements isolation selection and committed reads.
src/​Orleans.Transactions/​CompatibilitySuppressions.xml Records the intentional interface compatibility break.
src/​Orleans.Transactions/​Abstractions/​ReadIsolation.cs Defines public read isolation options.
src/​Orleans.Transactions/​Abstractions/​ITransactionalState.cs Adds the isolation-aware read contract.
src/​Orleans.Transactions.TestKit.xUnit/​GoldenPathTransactionTestRunner.cs Exposes new scenarios as xUnit theories.
src/​Orleans.Transactions.TestKit.Base/​TestRunners/​GoldenPathTransactionTestRunner.cs Tests committed values and ambient-transaction rejection.
src/​Orleans.Transactions.TestKit.Base/​OrleansContracts.txt Records new grain methods and refreshes regeneration comments.
src/​Orleans.Transactions.TestKit.Base/​Grains/​TransactionCoordinatorGrain.cs Invokes committed reads inside a transaction.
src/​Orleans.Transactions.TestKit.Base/​Grains/​MultiStateTransactionalGrain.cs Reads committed values across grain states.
src/​Orleans.Transactions.TestKit.Base/​Grains/​ITransactionTestGrain.cs Declares the committed-read grain method.
src/​Orleans.Transactions.TestKit.Base/​Grains/​ITransactionCoordinatorGrain.cs Declares the transaction-rejection test entry point.
src/​Orleans.Transactions.TestKit.Base/​FaultInjection/​ControlledInjection/​FaultInjectionTransactionState.cs Forwards the isolation-aware overload.
src/​Orleans.Transactions.TestKit.Base/​CompatibilitySuppressions.xml Records intentional test-grain interface breaks.
src/​api/​Orleans.Transactions/​Orleans.Transactions.cs Updates the generated transaction API surface.
src/​api/​Orleans.Transactions.TestKit.xUnit/​Orleans.Transactions.TestKit.xUnit.cs Refreshes generated test APIs and attributes.
src/​api/​Orleans.Transactions.TestKit.Base/​Orleans.Transactions.TestKit.Base.cs Updates generated test-kit APIs and invocation types.

Review effort: Balanced


await this.queue.Ready();

this.queue.GetCommittedState(out var state, out var sequenceNumber);
/// Performs a read operation with the specified isolation and returns the result.
/// </summary>
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="readFunction">A function that reads the state and returns the result.</param>
Comment on lines +14 to +15
/// Reads the most recently committed state without a transaction, lock, or storage write.
/// Rejected when an ambient transaction exists.

This branch has not been deployed

No deployments
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.

[Proposal] Non-transactional committed read on ITransactionalState<T>

2 participants