Don't schedule a move-later alarm if an interleaving commit setAlarm() #5589
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Prior to yielding to the event loop when we try to persist to SQLite, we save the current alarm time in
alarmStateForCommit. When we come back after the operation completes, this value remains unchanged, butalarmScheduledNoLaterThanmay have changed while we were async.Prior to this commit, that meant we might schedule a move-later alarm synchronization with the alarm manager if
alarmScheduledNoLaterThanwas now earlier thanalarmStateForCommit, even ifalarmStateForCommitwas set to the currently durable (and synced!) alarm time.Consider the following:
commitImplwhen we try to persist the write to SQLite, but savealarmStateForCommitas the current alarm time (2 years from now)alarmStateForCommitis 2 years from now, andalarmScheduledNoLaterThanis 5 minutes from now. We decide to do a background "move-later" sync with the alarm manager, then finish the commit.The end state is we essentially miss the "move-earlier" update in the alarm manager, breaking our model of "move-early eagerly and move-later lazily".
The fix
We track
alarmVersion, which is incremented every time the application calls setAlarm(). We capture this value before starting to persist to SQLite and compare it against the currentalarmVersionafter continuing commitImpl. If our capturedalarmVersiondiffers from the current version, then the application called setAlarm() while our SQLite commit was in-flight, and so we can safely skip attempting a move-later sync with the alarm manager, since a subsequent commit will modify the alarm anyways.