Skip to content
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

Cloud Spanner Client should prevent nested transactions #3476

Closed
vkedia opened this issue Jun 6, 2017 · 14 comments
Closed

Cloud Spanner Client should prevent nested transactions #3476

vkedia opened this issue Jun 6, 2017 · 14 comments
Assignees
Labels
api: spanner Issues related to the Spanner API. priority: p1 Important issue which blocks shipping the next release. Will be fixed prior to next release. release blocking Required feature/issue must be fixed prior to next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@vkedia
Copy link

vkedia commented Jun 6, 2017

Cloud Spanner does not support nested transactions. But the client library does allow users to call database.run_in_transaction inside of the callback that is provided to an outer database.run_in_transaction. This is misleading since users might believe that this will behave like a nested transaction but in reality these will be two independent transactions. This is confusing and a source of bugs. Specifically the inner transaction might succeed while the outer might ABORT, in which case the callback will be rerun thus rerunning the inner transaction.
We should prevent this from happening by detecting and raising an error if someone calls database.run_in_transaction inside the callback provided to database.run_in_transaction. Note that this needs to be done before Beta since this is a known breaking change.
Also note that if we come across a use case where we do want to allow calling a nested database.run_in_transaction, we should be able to enable that in future without making a breaking change.

cc @jgeewax @bjwatson

@vkedia vkedia added api: spanner Issues related to the Spanner API. priority: p0 Highest priority. Critical issue. P0 implies highest priority. labels Jun 6, 2017
@bjwatson bjwatson added status: acknowledged type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. labels Jun 9, 2017
@bjwatson bjwatson added priority: p1 Important issue which blocks shipping the next release. Will be fixed prior to next release. and removed priority: p0 Highest priority. Critical issue. P0 implies highest priority. labels Jun 21, 2017
@bjwatson
Copy link

@tseaver This can wait until you have time to work on the Spanner integration tests.

@vkedia
Copy link
Author

vkedia commented Aug 7, 2017

Note that this also is beta blocking.

@bjwatson bjwatson added the release blocking Required feature/issue must be fixed prior to next release. label Aug 7, 2017
@bjwatson
Copy link

bjwatson commented Aug 7, 2017

Thanks for the reminder, @vkedia. I'm reviewing the Python Spanner issues, and adding the status: release blocking to any that are Beta blocking. That way we can see a hotlist for remaining issue.

@vkedia
Copy link
Author

vkedia commented Aug 10, 2017

Can this be reopened? I don't think the fix actually fixes this.

@bjwatson bjwatson reopened this Aug 10, 2017
@bjwatson
Copy link

Reopened on behalf of @vkedia, so the remaining issues can be discussed further.

@lukesneeringer
Copy link
Contributor

I reviewed the code; it does exactly what it says on the tin. What is the problem exactly?

@vkedia
Copy link
Author

vkedia commented Aug 10, 2017

The exact requirements are if someone calls database.run_in_transaction inside the callback passed to database.run_in_transaction it should blow up. I don't think that would happen with the fix. You can verify that by writing a test that does this. Infact such a test should have been there in the PR in the first place.

@lukesneeringer
Copy link
Contributor

There is a test that does this.

@vkedia
Copy link
Author

vkedia commented Aug 10, 2017

It is not the same thing. That test is calling session.transaction. I am talking about database.run_in_transaction. The issue is when you call database.run_in_transaction again, it will checkout a new session so it will keep on working.
Right way to fix this would be somehow track in a thread local context or something analogous that there is an ongoing transaction in this thread and use that to prevent any other transaction from being opened.

@lukesneeringer
Copy link
Contributor

lukesneeringer commented Aug 10, 2017

@tseaver I think I agree with Vikas here. The session checkout would still fundamentally allow...

def bad_news():
    database.run_in_transaction(unit_of_work)

database.run_in_transaction(bad_news)

Note: This is so incredibly unusual in Python that I am struggling to figure out how to properly prevent it. Nevermind, I think I know what to do.

@tseaver
Copy link
Contributor

tseaver commented Aug 10, 2017

@lukesneeringer FWIW, the callback passed to Database.run_in_transaction ought to be using only the locals it is passed.

@lukesneeringer
Copy link
Contributor

lukesneeringer commented Aug 10, 2017

@tseaver Agreed, but we have no way to enforce that.

In fairness, relying on this kind of weird scoping is uncommon in Python, so this entire issue is well into the edge case territory ("if someone aims a gun at their foot...").

Regardless, I will have a PR in a moment.

@tseaver
Copy link
Contributor

tseaver commented Aug 10, 2017

Calling database.run_in_transaction from within the unit-of-work callback (e.g., bad_news) will check out a new session, start a new transaction in it, and call the passed other-unit-of-work callback. I don't see how we can prevent that.

@bjwatson
Copy link

@lukesneeringer @tseaver I understand that we might have some false negatives, because we cannot catch all cases in which a nested transaction might be initiated. Are we avoiding all false positives (i.e. failing on a non-existent nested transaction)?

I remember this was a concern in Node.js.

landrito pushed a commit to landrito/google-cloud-python that referenced this issue Aug 21, 2017
landrito pushed a commit to landrito/google-cloud-python that referenced this issue Aug 22, 2017
landrito pushed a commit to landrito/google-cloud-python that referenced this issue Aug 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: spanner Issues related to the Spanner API. priority: p1 Important issue which blocks shipping the next release. Will be fixed prior to next release. release blocking Required feature/issue must be fixed prior to next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

No branches or pull requests

4 participants