Harden SqlConnection state transitions with CAS guards#4267
Harden SqlConnection state transitions with CAS guards#4267paulmedynski wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request hardens SqlConnection’s internal state machine by guarding critical inner-connection transitions with Interlocked.CompareExchange (CAS), making contention/race paths deterministic and ensuring side effects (close-count, StateChange) occur only for committed transitions.
Changes:
- Made
TryOpenInnersnapshot/type-check the active inner connection before accessing parser state (and exposed it asinternalfor unit testing). - Updated
SetInnerConnectionEvent/SetInnerConnectionToto validate expected source states, commit with CAS, and apply side effects only after a successful CAS. - Added new unit tests covering race-path determinism and transition side-effect invariants.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs | Adds CAS-based guards + expected-state validation for key inner-connection transitions; snapshots/type-checks inner connection in TryOpenInner. |
| src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlConnectionStateTransitionTests.cs | Adds regression tests for race-sensitive state transitions and side-effect invariants. |
bb83c58 to
cdfd27a
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4267 +/- ##
==========================================
- Coverage 65.69% 63.68% -2.02%
==========================================
Files 285 280 -5
Lines 43311 66207 +22896
==========================================
+ Hits 28453 42163 +13710
- Misses 14858 24044 +9186
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
cdfd27a to
0622b0c
Compare
…ange tests - Add eventCount tracking to both SetInnerConnectionEvent tests to verify exactly one StateChange event is raised per transition. - Fix TryOpenConnection/TryReplaceConnection override signatures to include TimeoutTimer parameter added on main.
… transitions The CAS guard in SetInnerConnectionTo rejects writes when the current state is not a valid transitional state (DbConnectionClosedBusy or DbConnectionClosedConnecting). Tests from ef6aacf (main) assumed plain assignment. Use SetInnerConnectionFrom instead, which performs a CAS swap from the current state without precondition validation on the source state.
Summary
SqlConnectioninner-state transitions with targetedInterlocked.CompareExchangeguards.Key Changes
TryOpenInnernow snapshots and type-checks the inner connection before parser access.SetInnerConnectionEventnow:SetInnerConnectionTonow:ConnectionString_Setnow releases Busy -> Closed via guarded helper instead of direct write.Tests
SqlConnectionStateTransitionTestsdotnet test src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft.Data.SqlClient.UnitTests.csproj --filter "FullyQualifiedName~SqlConnectionStateTransitionTests" -p:Configuration=Debug -p:ReferenceType=ProjectApp-visible Behavior Analysis
Potential app-visible behavior changes are limited to race paths; normal single-threaded use should be unchanged.
InvalidOperationExceptioninstead ofInvalidCastExceptionSqlConnection.TryOpenInner, the method now snapshots and type-checks the inner connection after open/replace.InvalidCastException.InvalidOperationExceptionpath.InvalidCastExceptionfrom this race would now seeInvalidOperationException.SetInnerConnectionEventandSetInnerConnectionTonow enforce expected source states and use CAS.InvalidOperationExceptionerrors in contention cases.StateChangepatterns may see fewer spurious side effects from losing writers.ConnectionString_Setnow releases Busy -> Closed through the guarded helper rather than direct assignment.TryOpenInneraccess changed from private to internal for testability.Checklist
Observability Notes
ADP.ConnectionErrorvalues for guarded transition failures:InvalidSourceStateForSetInnerConnectionToFailedToCommitSetInnerConnectionToInvalidSourceStateForSetInnerConnectionEventFailedToCommitSetInnerConnectionEventSetInnerConnectionToandSetInnerConnectionEvent.InvalidOperationException; however, the internal connection error code embedded in the message (Internal DbConnection Error: {0}) is now more specific for these paths.