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

Make begin,commit,rollback cancel-safe in sqlite #2057

Merged

Conversation

madadam
Copy link
Contributor

@madadam madadam commented Aug 17, 2022

Closes #2054

@madadam madadam force-pushed the sqlite-transaction-cancel-safety branch from 3944f84 to 4155986 Compare August 17, 2022 14:32
@madadam
Copy link
Contributor Author

madadam commented Aug 22, 2022

This fix is not sufficient. Consider a begin() is cancelled on one connection and another begin() is called on a different connection. The transaction depth is tracked per connection so this case would be missed. Need to think of a different approach.

EDIT: fixed

@madadam madadam force-pushed the sqlite-transaction-cancel-safety branch from 4155986 to dda5551 Compare August 22, 2022 14:35
@madadam
Copy link
Contributor Author

madadam commented Aug 22, 2022

Take two. This time it should work across multiple connections as well. The idea is to try to recover from cancellation immediately as it is detected and on the same connection, not delay it until the next command (which might happen on another connection).

@abonander
Copy link
Collaborator

Could this be simplified somewhat if we just switched channel implementations to one that has more consistent behavior re. send()? I'm not really attached to Flume.

@madadam
Copy link
Contributor Author

madadam commented Aug 23, 2022

Could this be simplified somewhat if we just switched channel implementations to one that has more consistent behavior re. send()? I'm not really attached to Flume.

I'm not sure. Let's say we have a channel whose send guarantees the message is not sent unless polled to completion. Then we would be able to implement the fix described in #2054. However, there are at least two problems with it:

  1. The fix implicitly assumes that the BEGIN command always succeeds. But what can happen (at least in theory) is this:

    1. begin() is called and the command is sent to the worker thread
    2. begin() is then cancelled
    3. The RAII guard's destructor is called which sends a ROLLBACK command
    4. the worker thread processes the BEGIN but it fails for some reason
    5. the worker thread then processes the ROLLBACK, rolling back an incorrect transaction

    The problem is that we don't know whether the BEGIN succeeded until we receive the response, but that can be cancelled. So the decision whether to fire the ROLLBACK can't be made solely based on whether the first send completed or not.

  2. Even if this somehow fixed the issues with begin cancellation, there is still issue with commit / rollback cancellation. The problem there is that if they are cancelled, the open flag is not cleared and so the Transaction destructor sends another ROLLBACK.

@madadam
Copy link
Contributor Author

madadam commented Aug 23, 2022

One way to simplify this PR (in terms of number of changed lines) is instead of the ad-hoc rendezvous_oneshot channel to use flume::bounded(0) which is supposed to work as a rendezvous channel. However, I'm not sure it has the necessary cancellation guarantees.

@madadam madadam force-pushed the sqlite-transaction-cancel-safety branch from dda5551 to 8334760 Compare August 23, 2022 13:39
@abonander abonander merged commit f38c739 into launchbadge:main Sep 13, 2022
@madadam madadam deleted the sqlite-transaction-cancel-safety branch September 13, 2023 14:44
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.

begin is not cancel-safe
2 participants