Severity: medium
Component: fluree-db-api local cache event listener / ledger reconciliation
Summary
spawn_local_cache_event_listener (fluree-db-api/src/lib.rs:1197) reconciles the in-process ledger cache in response to nameservice events, but it only acts on LedgerIndexPublished and LedgerRetracted. LedgerCommitPublished falls through the catch-all Ok(_) => {} arm (fluree-db-api/src/lib.rs:1241) and is silently ignored.
The net effect: in-process cache reconciliation is index-driven only. The cache catches up when a new index root is published (asynchronous, rate-limited by reindex_min_bytes, ~100KB default), not when a commit is published.
Impact
- Harmless for a strict single-process writer: the committer advances its own cached handle atomically under the write lock (
finalize_commit → write_guard.replace), so it never depends on the event listener to see its own writes.
- Load-dependent read staleness for passively-synced readers: any peer/proxy/SSE-follower — or any component reading a handle it did not itself write — only reflects committed-but-unindexed data after the next index publish. Under high write rates the window between a commit and the next index-published reconcile widens, so a read can transiently observe a behind-head cached
t.
This is the same class of gap previously root-caused as the Raft follower-cache CI flake (the follower cache ignored LedgerCommitPublished). It is also the seam that a min-t read masks today: await_query_min_t_requirements → refresh() → notify() forces a catch-up that the listener would otherwise only perform on index publish.
Current code
fluree-db-api/src/lib.rs:1207-1241:
Ok(NameServiceEvent::LedgerIndexPublished { ledger_id, .. }) => { /* ledger_manager.notify(...) */ }
Ok(NameServiceEvent::LedgerRetracted { ledger_id }) => { /* ledger_manager.disconnect(...) */ }
Ok(_) => {} // <-- LedgerCommitPublished lands here and is dropped
The event exists and is emitted on every commit publish:
NameServiceEvent::LedgerCommitPublished { ledger_id, commit_id, commit_t }
(fluree-db-nameservice/src/lib.rs:831; emitted at fluree-db-nameservice/src/notifying.rs:181 and :286).
Proposed fix
Add a LedgerCommitPublished arm that calls ledger_manager.notify(NsNotify { ledger_id, record: None }), routing through the CommitCatchUp path in LedgerManager::notify / UpdatePlan, so the cache reconciles on commits rather than only on index publishes.
UpdatePlan::plan is already novelty-protective (no-op when local t ≥ nameservice head; IndexOnly/CommitCatchUp only when behind), so this is safe for the writer's own handle and only advances lagging readers.
Notes / context
- Found while triaging a (separate, misdiagnosed) DELETE-WHERE staleness report. On a strict single in-process node the write path is read-your-writes-correct and this listener gap does not affect it; the gap matters specifically for the peer/proxy/follower read paths, which is why it is filed here alongside the Raft work.
Severity: medium
Component:
fluree-db-apilocal cache event listener / ledger reconciliationSummary
spawn_local_cache_event_listener(fluree-db-api/src/lib.rs:1197) reconciles the in-process ledger cache in response to nameservice events, but it only acts onLedgerIndexPublishedandLedgerRetracted.LedgerCommitPublishedfalls through the catch-allOk(_) => {}arm (fluree-db-api/src/lib.rs:1241) and is silently ignored.The net effect: in-process cache reconciliation is index-driven only. The cache catches up when a new index root is published (asynchronous, rate-limited by
reindex_min_bytes, ~100KB default), not when a commit is published.Impact
finalize_commit→write_guard.replace), so it never depends on the event listener to see its own writes.t.This is the same class of gap previously root-caused as the Raft follower-cache CI flake (the follower cache ignored
LedgerCommitPublished). It is also the seam that amin-tread masks today:await_query_min_t_requirements→refresh()→notify()forces a catch-up that the listener would otherwise only perform on index publish.Current code
fluree-db-api/src/lib.rs:1207-1241:The event exists and is emitted on every commit publish:
NameServiceEvent::LedgerCommitPublished { ledger_id, commit_id, commit_t }(
fluree-db-nameservice/src/lib.rs:831; emitted atfluree-db-nameservice/src/notifying.rs:181and:286).Proposed fix
Add a
LedgerCommitPublishedarm that callsledger_manager.notify(NsNotify { ledger_id, record: None }), routing through theCommitCatchUppath inLedgerManager::notify/UpdatePlan, so the cache reconciles on commits rather than only on index publishes.UpdatePlan::planis already novelty-protective (no-op when localt≥ nameservice head;IndexOnly/CommitCatchUponly when behind), so this is safe for the writer's own handle and only advances lagging readers.Notes / context