Skip to content

Speedup recall using Hugging Face local cache#42

Merged
dacorvo merged 5 commits into
mainfrom
use_hf_cache_recall
Jun 30, 2026
Merged

Speedup recall using Hugging Face local cache#42
dacorvo merged 5 commits into
mainfrom
use_hf_cache_recall

Conversation

@dacorvo

@dacorvo dacorvo commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

The default lance opendal[huggingface] backend used for recall does not perform any caching.

We wrap the lance object store used when reading to replace opendal download calls by hf-hub download calls that benefit from the local cache.

Details:

  • Reads are pinned to the resolved head commit, so every file is immutable and whole-file caching is always safe (no path allowlist). Freshness comes from each command re-opening and re-resolving the head; if it can't be resolved (offline/transient) the open degrades to a live, uncached read.
  • FetchStore is a generic ObjectStore decorator (the read mirror of CaptureStore); the HF-specific HubFetcher/FetchWrapper live in hf_dataset, so the generic layer stays backend-agnostic.
  • Effect: warm remote recall ≈ local (the per-call hf:// round-trips are gone); the first touch still pays a one-time download. Guarded by a gated live test (tests/remote_cache.rs).
  • Also fixes bench_recall --cold to isolate the hf-hub file cache (it was isolating the Xet cache, which this path no longer uses) and drops its hf-CLI dependency in favour of the hf-hub crate.

dacorvo and others added 5 commits June 30, 2026 21:36
Add FetchStore, the read mirror of CaptureStore: an ObjectStore
decorator that serves every get from a whole local file supplied by a
FileFetcher (sliced to the requested range) and delegates every other
method to the inner store. It owns no cache — the fetcher decides where
files come from and whether they persist — so the module stays
backend-agnostic, with no reference to HF, exactly like capture_store.

The HF-specific pieces live in hf_dataset beside CaptureWrapper:
HubFetcher (hf-hub download_file pinned to a commit SHA, for
zero-network warm reads over an immutable file set) and FetchWrapper
(the WrappingObjectStore that installs FetchStore). hf_dataset depends
on fetch_store, never the reverse.

This is Phase 1 of caching remote recall reads; the mechanism is inert
until FetchWrapper is wired into Store::open (Phase 2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the FetchWrapper into Store::open. A remote open now resolves the
head commit, pins lance to it (hf_revision), and installs the wrapper, so
lance's reads go through hf-hub's download_file instead of opendal's
per-range fetches over hf://. hf-hub serving repeat reads from its local
cache — what makes warm recalls fast — is the bonus that justifies it over
opendal; a cold read still downloads.

- dataset::open_wrapped installs a WrappingObjectStore before load, so it
  covers the load-time reads too, and stays backend-agnostic.
- hf_dataset::fetch_wrapper builds the repo handle, resolves the head, and
  returns the wrapper pinned to that SHA.
- Freshness: every command re-opens and re-resolves the head, so a push is
  seen on the next call. If the head can't be resolved (offline/transient),
  degrade to a live, uncached open rather than fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a gated live test (HF_FUNES_TEST_TOKEN, like the other remote tests)
that isolates HF_HUB_CACHE to a temp dir and asserts a warm recall over
the test fixture downloads nothing: the cache footprint is byte-for-byte
unchanged across a cold then warm recall, and both surface the marker.

This is the regression guard for the read-through cache's core guarantee
— a change that broke caching (e.g. dropping the token so reads fall back
to the live store) would otherwise pass CI silently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The read-through cache change made hf-hub's file cache (HF_HUB_CACHE) the
operative one for remote reads, but bench_recall's --cold still isolated
HF_XET_CACHE — which the read path no longer uses — so a populated file
cache served the "cold" leg and it reported a warm-as-cold (cold ≈ warm).
Point --cold at HF_HUB_CACHE so the remote cold call is a genuine download
again: cold shows the one-time download premium, warm collapses to ≈ local.

Also drop the shell-out to the `hf` CLI for the local-leg download — funes
already depends on hf-hub, so fetch via snapshot_download with local_dir
(which writes straight to the temp dir, bypassing the hub cache, so it
can't pre-warm the remote leg) and let HFClient read the token from the
environment. No external CLI needed.

Refresh benchmark/README.md to the new behavior (warm remote ≈ local, not
~10×) and note the absolute numbers are rerank-bound and host-dependent —
compare the remote/local ratio, not the floor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI's format check runs nightly rustfmt, which wraps the long assert! that
stable rustfmt (used locally) left on one line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dacorvo
dacorvo merged commit 20d879f into main Jun 30, 2026
7 checks passed
@dacorvo
dacorvo deleted the use_hf_cache_recall branch June 30, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant