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

Prevent ValueObservation from notifying duplicate initial values when no concurrent write is observed #940

Closed
wants to merge 2 commits into from

Conversation

groue
Copy link
Owner

@groue groue commented Mar 13, 2021

When one starts a ValueObservation in a DatabasePool, one would get a duplicate notification of the initial value.

Now this duplicate notification is avoided when we can prove that no transaction was committed, in the pool's writer connection, between the fetch of the initial value, and the first access to the writer connection (where the observation can really start by hooking on the SQLite commits).

A double notification will still happen if some writer commit is attempted during the ValueObservation start-up (even if the observed value is not impacted by the changes, and even if the commit fails).

As documented, ValueObservation users must be ready for duplicate notifications. This pull request produces less duplicate notifications, but does not remove all of them.

Fix #937

@pocketpixels
Copy link
Contributor

Thank you for tackling this. This solution looks good to me.

Just to make sure this is 100% guaranteed to be correct (I wouldn't care for my application, but I assume you probably would for general use):
Can we completely rule out that a commit that happens right around the time of reading the attemptedCommitCount pre-fetch could sneak through undetected?
In particular:
The sqlite3_commit_hook gets called right before the write transaction gets committed, right?
Let's say in the commit hook the attemptedCommitCount just got incremented but the hook/callback has not returned yet.
Immediately after the count is read from the reader connection.
Could it be possible that the initial fetch now happens and reads a version of the data that does not yet reflect the write transaction? Or does SQLite guarantee that his can never happen?

@groue
Copy link
Owner Author

groue commented Mar 14, 2021

Just to make sure this is 100% guaranteed to be correct (I wouldn't care for my application, but I assume you probably would for general use):
Can we completely rule out that a commit that happens right around the time of reading the attemptedCommitCount pre-fetch could sneak through undetected?

Thanks for the help 💯

In particular:
The sqlite3_commit_hook gets called right before the write transaction gets committed, right?

Correct.

Let's say in the commit hook the attemptedCommitCount just got incremented but the hook/callback has not returned yet.

OK. Let's say attemptedCommitCount is 1, but database is still at 0. I see you coming...

Immediately after the count is read from the reader connection.
Could it be possible that the initial fetch now happens and reads a version of the data that does not yet reflect the write transaction? Or does SQLite guarantee that his can never happen?

You're absolutely right. The read can fetch from state 0 (when commit is not performed yet), and when we later enter the writer queue, the commit has been performed, we compare 1 to 1, skip the second fetch, and miss the changes 🐛

All right, back to the drawing board! Thank you very much again!!

@groue groue closed this Mar 14, 2021
@groue groue added invalid or off-topic Not about GRDB, or does not contain any useful information and removed enhancement labels Mar 14, 2021
@groue groue deleted the dev/issue-937 branch August 25, 2022 06:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid or off-topic Not about GRDB, or does not contain any useful information
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants