-
Notifications
You must be signed in to change notification settings - Fork 291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release connection lock before signaling SinglePhaseCommit completion #1801
Release connection lock before signaling SinglePhaseCommit completion #1801
Conversation
Codecov ReportBase: 70.68% // Head: 70.02% // Decreases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## main #1801 +/- ##
==========================================
- Coverage 70.68% 70.02% -0.67%
==========================================
Files 292 292
Lines 61727 61727
==========================================
- Hits 43634 43226 -408
- Misses 18093 18501 +408
Flags with carried forward coverage won't be shown. Click here to find out more.
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
Hi @roji Apologies for the delay, I've been heads down in release work. I tested these changes today with multiple cases and the fix looks good to me overall. However, since we don't have I couldn't reproduce this issue in .NET Framework too with the repro provided, so I'm not sure if we want to backport this fix just yet as Framework's been stable with the changes so I would be hesitant to touch it. I think due to lack of Distribution Transaction support in .NET Core, we couldn't really test this back then. But I'll be watchful of if/when |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would suggest adding a test case for future proofing this scenario with the repro from #1800 (comment)
Thanks for reviewing @cheenamalhotra!
Giving that this is a timing-sensitive race condition, that repro runs in a |
Hi @roji I got the repro simplified and can almost reproduce the issue everytime with this code. Tested with .NET 7 string connString = "Server=localhost; Integrated Security=true; Pooling=false;"; // remember to disable pooling
TransactionManager.ImplicitDistributedTransactions = true;
using var transaction = new CommittableTransaction();
// Uncommenting the following makes the deadlock go away as a workaround. If the transaction is promoted before
// the first SqlClient enlistment, it never goes into the delegated state.
// _ = TransactionInterop.GetTransmitterPropagationToken(transaction);
await using var conn = new SqlConnection(connString);
await conn.OpenAsync();
conn.EnlistTransaction(transaction);
await conn.CloseAsync();
// Enlisting the transaction in second connection causes the transaction to be promoted.
// After this, the transaction state will be "delegated" (delegated to SQL Server), and the commit below will
// trigger a call to SqlDelegatedTransaction.SinglePhaseCommit.
await using var conn2 = new SqlConnection(connString);
await conn2.OpenAsync();
conn2.EnlistTransaction(transaction);
// Enlisting the transaction in third connection causes the deadlock on transaction.Commit() below (issue 1800)
await using var conn3 = new SqlConnection(connString);
await conn3.OpenAsync();
await conn2.CloseAsync();
conn3.EnlistTransaction(transaction);
Console.WriteLine("Committing transaction...");
transaction.Commit();
// Never gets printed due to deadlock.
Console.WriteLine("Transaction committed."); There may be 1% chance it may not repro, but even if it does 99% of the time, we still have a possibility of capturing it if anything changes in future. I'd recommend adding this to test case with useful comments. 🙂 And once again, thank you for looking after this ❤️ |
OK, sounds good! Can you point me to where you guys put this kind of test? Or if you prefer, you can also just push a commit doing that to this PR. |
8f38613
to
8116d72
Compare
@cheenamalhotra thanks, I've pushed the test. Some notes:
@David-Engel and others, I really hope this can be patched in 5.0; the bug effectively prevents people from using distributed transactions with SqlClient on .NET 7 (the primary use case); in EF we won't be able to take a dependency on SqlClient 5.1 (7.0 is out, and patch releases generally can only bump patch versions of dependencies). |
Since we're in the middle of releasing the 5.1 GA, I'll need to wait for approval from @David-Engel before we can merge this. |
@roji failures are not related to your changes. I have added windows 11 and apparently there is a failure due to some access restriction for Namedpipes. I am addressing them. |
This is a possible fix for #1800, introduced by #1042; but it may re-introduce the issue that #1042 was meant to fix.
Fixes #1800