Repository navigation
fix: select latest SQLite checkpoint when timestamps tie - #920
elijahbenizzy merged 2 commits into
Conversation
Use insertion order to disambiguate same-second checkpoints in sync and async SQLite persisters. Add durable reopening and partition regressions. Assisted-by: Codex
|
There are two distinct CI blockers on current head Could a maintainer approve the pending runs and inspect the documentation workflow's startup failure? The successful labeling/mergeability checks do not run the SQLite checkpoint regressions. No source change or workflow rerun was made in this follow-up. |
sangkyoonnam
left a comment
There was a problem hiding this comment.
Thanks for the clean repro. This looks correct to me.
I ran the new tests locally. On main (8161159), 8 of the 10 load_latest tests fail. On the head, both test files pass, 60 tests. Without touching created_at, three saves within the same second on main make load("pk", None) return the first save, a-app seq 11. The head returns the last one, z-app.
rowid is the right tie-break for rows the persister inserts, since sequence_id doesn't compare across apps.
One thing outside this PR: list_app_ids orders SELECT DISTINCT app_id by created_at, which isn't tied to each app's newest row. Saving a, z, a at distinct seconds returns ['z-app', 'a-app'] on both main and the head. Is that order meant to mean anything, or should I file an issue?
|
Thanks @sangkyoonnam for the independent same-second and reopen checks. Your 8/10 failures on main and 60 passing tests on this head are useful additional evidence; they are your results, separate from my earlier local runs. I checked the This PR's head remains |
elijahbenizzy
left a comment
There was a problem hiding this comment.
Correct tie-break: sequence_id doesn't compare across apps, rowid does, and we own the table so it's never WITHOUT ROWID. Nice deterministic tests. Elijah
Pull request was closed
# Conflicts: # tests/integrations/persisters/test_b_aiosqlite.py
|
Merged main into your branch to resolve a conflict with #942 in the test file (both sets of tests kept, your commits untouched). Auto-merge is armed; it lands when CI is green. |
SQLitePersister.load(partition_key, None)and its async counterpart can return an older checkpoint when several saves share a timestamp. SQLite's defaultCURRENT_TIMESTAMPhas second precision, and the current query orders only by that timestamp. In a deterministic reproduction, saving sequence 11 followed by sequence 12 and loading after reopening the database returns sequence 11. Across applications it can also return the wrong app.Changes
rowidas the secondary ordering key in the latest-across-apps query, aftercreated_at.This uses the rowid already present in tables created by these persisters; no schema migration or change to app-specific sequence selection is needed. The tie-breaker follows insertion order in the persister-managed table, not a portable identifier for externally rewritten database rows.
Related: #807 explicitly notes the timestamp-tie limitation in its test-only PR. This PR fixes the behavior in both implementations; it does not duplicate those construction/lifecycle tests or depend on that PR.
How I tested this
Python 3.13.14 on Windows, using actual SQLite/aiosqlite databases:
Pre-commit passes on all four changed files: Black 23.11.0, isort 5.12.0, flake8 6.1.0, whitespace/EOF, AST, and ASF headers. The frontend hook was explicitly skipped because this changes only Python persistence; the full external-database test matrix was not run.
Notes
Checklist