pub struct NeighborCache { /* private fields */ }Expand description
Ready results plus in-flight/failed bookkeeping.
Implementations§
Source§impl NeighborCache
impl NeighborCache
pub fn new() -> Self
pub fn get(&self, k: &CacheKey) -> Option<&NeighborResult>
pub fn error(&self, k: &CacheKey) -> Option<&str>
Sourcepub fn mark_wanted(&mut self, k: CacheKey)
pub fn mark_wanted(&mut self, k: CacheKey)
Queue a miss for fetching. Idempotent: a key already ready, in flight, failed, or already queued is not queued again — so holding a navigation key cannot stampede the backend and a failure cannot retry-loop.
Sourcepub fn take_wanted(&mut self) -> Vec<(CacheKey, u64)>
pub fn take_wanted(&mut self) -> Vec<(CacheKey, u64)>
Drain queued keys, marking each in flight under a fresh epoch. The
epoch identifies THIS attempt: the host must hand it back to
fill/fail so a settle can be matched to the attempt that produced
it. Without that, two outstanding attempts for one key (possible after
a cancel, since the key carries no slot and re-queues) are
indistinguishable.
Sourcepub fn fill(&mut self, k: CacheKey, epoch: u64, res: NeighborResult)
pub fn fill(&mut self, k: CacheKey, epoch: u64, res: NeighborResult)
Store a received result for the attempt tagged epoch. pending is a
client-side concept — it means “this placeholder stands in for a fetch
we have not received yet” — so a value decoded off the wire is never
trusted: a host or proxy echoing {"pending":true} would otherwise
land a permanent cache HIT that reports pending, wedging the view on a
spinner that can never resolve.
Sourcepub fn fail(&mut self, k: CacheKey, epoch: u64, err: String)
pub fn fail(&mut self, k: CacheKey, epoch: u64, err: String)
Record a failure for the attempt tagged epoch.
Sourcepub fn cancel(&mut self, k: &CacheKey)
pub fn cancel(&mut self, k: &CacheKey)
Cancel a fetch. A key still queued is simply dequeued; a key in flight
loses its slot, so is_loading() goes quiet at once and the stale
settle is discarded by the epoch check in fill/fail. Cancellation
is not sticky: the key carries no slot afterwards, so mark_wanted
queues it again.
Sourcepub fn is_in_flight(&self, k: &CacheKey) -> bool
pub fn is_in_flight(&self, k: &CacheKey) -> bool
Whether a fetch for k is currently outstanding. Hosts holding
per-fetch resources (an AbortController, say) use this to prune.
Sourcepub fn take_dirty(&mut self) -> bool
pub fn take_dirty(&mut self) -> bool
True once since the last call; consumed by the renderer.
Sourcepub fn take_failures(&mut self) -> Vec<(CacheKey, String)>
pub fn take_failures(&mut self) -> Vec<(CacheKey, String)>
Drain failures that have not yet been reported. The Slot::Failed
record remains, so a failed key still does not auto-retry.
Sourcepub fn take_new_arrivals(&mut self) -> Vec<CacheKey> ⓘ
pub fn take_new_arrivals(&mut self) -> Vec<CacheKey> ⓘ
Drain the keys filled since the last call, so a host can absorb only what actually arrived instead of re-walking every ready result.
Sourcepub fn clear_failures(&mut self)
pub fn clear_failures(&mut self)
Forget every recorded failure, so those keys can be queued again by a
subsequent mark_wanted. Ready and in-flight entries are untouched.
Failures are never cleared automatically — that would hammer a down
backend — so this is the hook behind an explicit host “retry”.
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Forget everything: entries, in-flight slots, the queue, the dirty flag, undrained failures and arrivals, and the settled high-water map.
A load REPLACES the dataset, so every cached neighborhood now
describes a graph that no longer exists. Keeping them would serve the
old graph’s neighbors for any id the new one happens to reuse — and id
reuse is the norm rather than the exception for generated or
synthetically-keyed datasets, where w0/c0 mean something different
in each. Recorded failures are wrong for exactly the same reason, and
worse for being sticky: a node that failed under the old dataset would
be a permanent dead end under the new one.
next_epoch deliberately does NOT restart. Fetches issued for the old
dataset are still on the wire, and rewinding the counter would let one
of them settle under an epoch a post-reset attempt also claims. Instead
the counter’s current value becomes an epoch floor: every attempt drawn
before this reset is at or below it, and is_stale discards it on
arrival. Without that floor, clearing slots and settled would
actually WIDEN the hole — both of fill’s other guards read those maps,
so an old-dataset answer would land unopposed.
pub fn is_loading(&self) -> bool
Sourcepub fn ready_results(&self) -> impl Iterator<Item = &NeighborResult>
pub fn ready_results(&self) -> impl Iterator<Item = &NeighborResult>
Every result received so far. Used to grow the known graph (the traditional view starts at the seed and expands as neighborhoods land).