-
Notifications
You must be signed in to change notification settings - Fork 362
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
fix: synchronize access to the underlying transaction for ambient transactions #6616
fix: synchronize access to the underlying transaction for ambient transactions #6616
Conversation
…nsactions Synchronizes access to the underlying Spanner transaction to prevent multiple transactions from being created if parallel commands are executed on the ambient transaction.
cc @skuruppu |
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.
Great catch! I just have a suggestion for using Lazy instead of a normal lock. I think we could avoid calling Task.Result etc. and in any case it would be cleaner I think?
I'd definitely be happier using |
Using
|
You can have |
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.
I think I follow this and like it, but I'd like Amanda to check as well :)
apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/VolatileResourceManager.cs
Outdated
Show resolved
Hide resolved
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.
LGTM with a couple of suggestions.
apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/VolatileResourceManager.cs
Outdated
Show resolved
Hide resolved
apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/VolatileResourceManager.cs
Outdated
Show resolved
Hide resolved
Added do not merge label just while we finish discussing internally. |
I removed the |
@amanda-tarafa @jskeet Do you have any last comments/questions before merging this? |
Will have a look in a bit - I have a couple of other things on this morning. (If Amanda is happy, she's welcome to merge it - she's typically a better reviewer than I am anyway!) |
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.
LGTM with three small requests.
public void Dispose() | ||
{ | ||
try | ||
{ | ||
_transaction?.Dispose(); | ||
// Protect against multiple disposals | ||
if (IsTransactionCreated) |
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.
Actually I think you want here _transaction is null
only, without caring about the value having been created or not.
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.
No, in this case we do care, because it could be that the VolatileResourceManager
is being disposed without the SpannerTransaction
ever having been initialized. _transaction
is set to a non-null value in the constructor. The underlying SpannerTransaction
is however only created if it is actually needed. So if Dispose()
would be called before the transaction has been used, it would unnecessarily first create a new SpannerTransaction
and then dispose it right afterwards.
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.
Yep, you are right.
|
||
Assert.True(reader.Read()); | ||
Assert.Equal(keys.Length, reader.GetInt32(0)); | ||
Assert.False(reader.Read()); |
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.
nit: I would remove this one, your select is a COUNT and if that returns more than one row, that's a problem with the reader, not with this test.
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.
Removed.
scope.Complete(); | ||
} | ||
|
||
spannerClientMock.Verify(client => client.CommitAsync( |
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.
The verification in the next line superseeds this one. I think this one can be removed.
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.
I think it's better to have both, as they do check two different things:
- The first verification checks that there is only one
Commit
call, regardless of the number of mutations in the request. - The second verification checks that the only
Commit
call actually contains 3 mutations.
Removing the first verification would mean that if two commit requests were sent from the client, one without any mutations and the other with 3 mutations, the test would still pass. That is one of the scenarios that we want to verify is not happening. (Checking the number of BeginTransaction
calls is not a good measure, as multiple transactions could be prepared by the session pool.)
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.
Ah yes, you are right.
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.
LGTM
scope.Complete(); | ||
} | ||
|
||
spannerClientMock.Verify(client => client.CommitAsync( |
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.
Ah yes, you are right.
public void Dispose() | ||
{ | ||
try | ||
{ | ||
_transaction?.Dispose(); | ||
// Protect against multiple disposals | ||
if (IsTransactionCreated) |
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.
Yep, you are right.
Changes in Google.Cloud.Spanner.Data version 3.12.0: - [Commit 7c6a6f1](googleapis@7c6a6f1): feat: add support for JSON data type in Spanner ([issue 6390](googleapis#6390)) - [Commit ac367e2](googleapis@ac367e2): feat: Regenerate all APIs to support self-signed JWTs - [Commit 61938b6](googleapis@61938b6): - feat(Spanner): Support comments and statement hints in untyped commands. - Alternative to [issue 6848](googleapis#6848) - Closes [issue 6847](googleapis#6847) - [Commit d26b04c](googleapis@d26b04c): fix: address review comments - [Commit d2025be](googleapis@d2025be): fix: use logger from SpannerSettings - [Commit b34f6f4](googleapis@b34f6f4): cleanup: fix comment + remove unnecessary import - [Commit fc7a41b](googleapis@fc7a41b): test: remove connectionstring tests and add settings test - [Commit 6016ef0](googleapis@6016ef0): - feat: support custom SpannerSettings in SessionPoolManager - Support setting custom SpannerSettings when creating a SessionPoolManager. - [Commit 0ab6b8b](googleapis@0ab6b8b): - feat: allow adding an additional version header - Allows adding an additional version header to the connection string. This will be - added to the `x-goog-api-client` header that is used by the underlying Spanner client. - Only a fixed set of values may be set for the header (currently only 'efcore' is - allowed), and the property is not intended for public use. - [Commit 250124f](googleapis@250124f): - fix: synchronize access to the underlying transaction for ambient transactions ([issue 6616](googleapis#6616)) - * fix: synchronize access to the underlying transaction for ambient transactions - Synchronizes access to the underlying Spanner transaction to prevent - multiple transactions from being created if parallel commands are - executed on the ambient transaction. - * test: add integration test - * fix: use Lazy for initialization - * chore: address review comments - * fix: remove unnecessary read call Packages in this release: - Release Google.Cloud.Spanner.Admin.Database.V1 version 3.12.0 - Release Google.Cloud.Spanner.Admin.Instance.V1 version 3.12.0 - Release Google.Cloud.Spanner.Common.V1 version 3.12.0 - Release Google.Cloud.Spanner.Data version 3.12.0 - Release Google.Cloud.Spanner.V1 version 3.12.0
Changes in Google.Cloud.Spanner.Data version 3.12.0: - [Commit 7c6a6f1](7c6a6f1): feat: add support for JSON data type in Spanner ([issue 6390](#6390)) - [Commit ac367e2](ac367e2): feat: Regenerate all APIs to support self-signed JWTs - [Commit 61938b6](61938b6): - feat(Spanner): Support comments and statement hints in untyped commands. - Alternative to [issue 6848](#6848) - Closes [issue 6847](#6847) - [Commit d26b04c](d26b04c): fix: address review comments - [Commit d2025be](d2025be): fix: use logger from SpannerSettings - [Commit b34f6f4](b34f6f4): cleanup: fix comment + remove unnecessary import - [Commit fc7a41b](fc7a41b): test: remove connectionstring tests and add settings test - [Commit 6016ef0](6016ef0): - feat: support custom SpannerSettings in SessionPoolManager - Support setting custom SpannerSettings when creating a SessionPoolManager. - [Commit 0ab6b8b](0ab6b8b): - feat: allow adding an additional version header - Allows adding an additional version header to the connection string. This will be - added to the `x-goog-api-client` header that is used by the underlying Spanner client. - Only a fixed set of values may be set for the header (currently only 'efcore' is - allowed), and the property is not intended for public use. - [Commit 250124f](250124f): - fix: synchronize access to the underlying transaction for ambient transactions ([issue 6616](#6616)) - * fix: synchronize access to the underlying transaction for ambient transactions - Synchronizes access to the underlying Spanner transaction to prevent - multiple transactions from being created if parallel commands are - executed on the ambient transaction. - * test: add integration test - * fix: use Lazy for initialization - * chore: address review comments - * fix: remove unnecessary read call Packages in this release: - Release Google.Cloud.Spanner.Admin.Database.V1 version 3.12.0 - Release Google.Cloud.Spanner.Admin.Instance.V1 version 3.12.0 - Release Google.Cloud.Spanner.Common.V1 version 3.12.0 - Release Google.Cloud.Spanner.Data version 3.12.0 - Release Google.Cloud.Spanner.V1 version 3.12.0
Synchronizes access to the underlying Spanner transaction to prevent multiple transactions from being created when parallel commands are executed on the ambient transaction.
See error and discussion in GoogleCloudPlatform/dotnet-docs-samples#1320 for background.