You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug: patterns of one query can read different database states under concurrent writes #555
Affected versions: v1.1.0 (daa80a9, selective fetch in filter_facts_for_query, #208) through v2.0.5, and v3.
Bug
A query does not read the database at one instant. selective_fact_fetch (src/query/datalog/executor.rs) calls FactStorage::get_live_facts once per entity or attribute it needs, and each call takes and releases the pending store's read lock. A transaction that commits between two calls is visible to some patterns of the query and not to others. The query then returns rows that match no committed state of the database.
Reproducer
tests/snapshot_atomicity_test.rs on branch test/snapshot-atomicity-repro (dc7fa7a):
patterns_of_one_query_see_one_state_in_memory
patterns_of_one_query_see_one_state_on_file
Every transaction writes [:pN :pair/x N] and [:pN :pair/y N] together, using execute, which is atomic. A concurrent
must always be empty. It returns an entity within milliseconds on v3 and on main. Single-threaded, the query is correct.
cargo test --test snapshot_atomicity_test patterns -- --ignored
Fix
A query must read all its facts from one snapshot: one acquisition of the read lock for every fetch, or a snapshot taken once (committed reader plus pending length) and read from. #473 spec §4.1 (#543) gives v3 this. v2.x needs its own fix.
Correction: the query above, with :pair/x positive, only ever caught #554 (execute added :pair/x before :pair/y). Lookups run in sorted attribute order, so a commit landing between the two lookups shows up only with :pair/y positive: [:find ?e :where [?e :pair/y ?v] (not [?e :pair/x ?v])]. With #554 fixed, that query fails within milliseconds and the original one passes. The reproducer now runs both.
Workaround
Do not query from one thread while another writes.
Status
v3: PR #557 (FactStorage::get_live_facts_of_scans, one read lock for all of a query's lookups; stacked on #556). v2.x backport to follow.
Activity
Merge pull request #557 from project-minigraf/fix/555-one-read-lock
Merge pull request #559 from project-minigraf/fix/554-555-backport
release: v2.0.6
adityamukho commentedon Oct 14, 2026
Fixed in v2.0.6 (released 2026-10-14, on crates.io). Moved to "Fixed in v2.0.6" in #421.
fix: queries see whole transactions and one state per query (project-…