Skip to main content

ferrox_core/
expert_store.rs

1//! A bounded, lease-protected byte cache for routed-expert weights --
2//! the storage foundation for running MoE checkpoints whose experts do
3//! not all fit in RAM at once (stream cold experts from SSD, keep hot
4//! ones resident under one global byte budget).
5//!
6//! Status: wired into both decode paths as an opt-in
7//! (`Decoder::from_gguf_with_expert_cache` for GGUF,
8//! `load_kimi_checkpoint_with_expert_cache` for Kimi safetensors, both
9//! behind the server's `FERROX_EXPERT_CACHE_BYTES` or
10//! `FERROX_SSD_STREAMING=1` which defaults the cache to 2 GiB), each
11//! proven
12//! bit-identical to its resident path on the committed fixtures at
13//! both generous and smaller-than-one-expert budgets. Without the
14//! opt-in, experts still load resident (mmap) exactly as before.
15//! [`ExpertStore::prefetch`] warms keys for ds4-style SSD streaming
16//! overlap (caller supplies the hotlist). Never yet exercised against
17//! a real large checkpoint. Reference clone: `.scratch/ds4` (gitignored).
18//!
19//! Design:
20//!
21//! - [`ExpertSource`] abstracts where bytes come from (a file with
22//!   positional reads, a shard set, an in-memory test source). The
23//!   store never caches a partial expert: one `(layer, expert)` key
24//!   maps to one complete byte buffer (gate+up+down and any auxiliary
25//!   tensors, concatenated by the source in a layout the consumer
26//!   defines).
27//! - [`ExpertStore::acquire`] returns an [`ExpertLease`] -- a cheap
28//!   `Arc` handle that *pins* the entry: eviction skips any entry with
29//!   an outstanding lease, so a slot can never be reused while
30//!   CPU (or, later, GPU) work still reads it. This is the
31//!   slot-reuse-corruption guard, enforced structurally (an `Arc` with
32//!   `strong_count > 1` is simply not freeable), not by convention.
33//! - When an expert doesn't fit even after evicting every unleased
34//!   entry (e.g. a cache configured smaller than one decode step's
35//!   expert union), `acquire` still succeeds: the bytes are read and
36//!   returned as an *uncached* pass-through lease. Capacity pressure
37//!   degrades to more I/O, never to a wrong answer or a deadlock.
38//! - Reads happen outside the store lock, so concurrent misses on
39//!   different experts overlap their I/O. Two concurrent misses on the
40//!   *same* expert may both read it; the first to insert wins and the
41//!   loser's buffer becomes that caller's private pass-through copy --
42//!   duplicated work under a rare race, never wrong bytes.
43
44use std::collections::HashMap;
45use std::io;
46use std::sync::atomic::{AtomicU64, Ordering};
47use std::sync::{Arc, Mutex};
48
49/// Stable identity of one routed expert within a checkpoint.
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
51pub struct ExpertKey {
52    pub layer: u32,
53    pub expert: u32,
54}
55
56/// Where expert bytes come from. Implementations must be cheap to call
57/// concurrently (positional reads, not a shared seek cursor).
58pub trait ExpertSource: Send + Sync {
59    /// The exact byte length of this expert, or `None` if the key does
60    /// not exist. Used for budget accounting *before* reading.
61    fn expert_len(&self, key: ExpertKey) -> Option<usize>;
62
63    /// Reads this expert's complete bytes.
64    fn read_expert(&self, key: ExpertKey) -> io::Result<Vec<u8>>;
65}
66
67/// A pinned handle to one expert's bytes. While any lease for an entry
68/// is alive, the store cannot evict or reuse that entry's memory.
69pub struct ExpertLease {
70    data: Arc<Vec<u8>>,
71}
72
73impl ExpertLease {
74    pub fn bytes(&self) -> &[u8] {
75        &self.data
76    }
77
78    /// The shared buffer behind this lease, for building
79    /// `WeightBytes::Shared` sub-range views (one per matrix packed
80    /// into the expert's combined bytes). Every clone extends the
81    /// entry's pin: the store cannot evict while any of these views is
82    /// alive.
83    pub fn shared_buf(&self) -> Arc<Vec<u8>> {
84        Arc::clone(&self.data)
85    }
86}
87
88/// Monotonic counters, readable at any time without taking the store
89/// lock. `resident_bytes` is a gauge (current cache footprint).
90#[derive(Debug, Clone, Copy, Default)]
91pub struct ExpertStoreStats {
92    pub hits: u64,
93    pub misses: u64,
94    pub evictions: u64,
95    /// Acquires that could not be cached (entry larger than what the
96    /// budget could free) and were served as uncached pass-throughs.
97    pub pass_throughs: u64,
98    pub bytes_read: u64,
99    pub resident_bytes: u64,
100}
101
102struct Entry {
103    data: Arc<Vec<u8>>,
104    /// Monotonic recency stamp; smallest = least recently used. A
105    /// stamp per touch is simpler and cheaper than reshuffling a
106    /// dedicated LRU list under the same lock, at the cost of an O(n)
107    /// scan on eviction -- fine for the hundreds-to-low-thousands of
108    /// entries a real expert cache holds.
109    last_used: u64,
110}
111
112struct Inner {
113    entries: HashMap<ExpertKey, Entry>,
114    resident_bytes: usize,
115    clock: u64,
116}
117
118/// Bytes every live [`ExpertStore`] in this process has committed to
119/// holding expert weights.
120///
121/// This module is the SINGLE holder of the expert byte budget, because
122/// on unified memory two budgets are the same RAM counted twice. That
123/// rule only bites when something *else* also wants to retain weight
124/// bytes, and something else now does: `weight_matrix::repack_cache`
125/// keeps interleaved copies of matrices it has packed. This gauge is
126/// how that cache subtracts rather than restates -- see
127/// [`crate::host_memory::derived_copy_budget`].
128static COMMITTED_EXPERT_BYTES: AtomicU64 = AtomicU64::new(0);
129
130/// Bytes currently committed to expert caches across the process. See
131/// [`COMMITTED_EXPERT_BYTES`].
132pub fn committed_expert_bytes() -> u64 {
133    COMMITTED_EXPERT_BYTES.load(Ordering::Relaxed)
134}
135
136/// The bounded cache. See the module docs for the design contract.
137pub struct ExpertStore<S: ExpertSource> {
138    source: S,
139    budget_bytes: usize,
140    inner: Mutex<Inner>,
141    hits: AtomicU64,
142    misses: AtomicU64,
143    evictions: AtomicU64,
144    pass_throughs: AtomicU64,
145    bytes_read: AtomicU64,
146}
147
148impl<S: ExpertSource> Drop for ExpertStore<S> {
149    fn drop(&mut self) {
150        COMMITTED_EXPERT_BYTES.fetch_sub(self.budget_bytes as u64, Ordering::Relaxed);
151    }
152}
153
154impl<S: ExpertSource> ExpertStore<S> {
155    pub fn new(source: S, budget_bytes: usize) -> Self {
156        COMMITTED_EXPERT_BYTES.fetch_add(budget_bytes as u64, Ordering::Relaxed);
157        ExpertStore {
158            source,
159            budget_bytes,
160            inner: Mutex::new(Inner {
161                entries: HashMap::new(),
162                resident_bytes: 0,
163                clock: 0,
164            }),
165            hits: AtomicU64::new(0),
166            misses: AtomicU64::new(0),
167            evictions: AtomicU64::new(0),
168            pass_throughs: AtomicU64::new(0),
169            bytes_read: AtomicU64::new(0),
170        }
171    }
172
173    pub fn budget_bytes(&self) -> usize {
174        self.budget_bytes
175    }
176
177    pub fn stats(&self) -> ExpertStoreStats {
178        let resident = self
179            .inner
180            .lock()
181            .unwrap_or_else(|p| p.into_inner())
182            .resident_bytes as u64;
183        ExpertStoreStats {
184            hits: self.hits.load(Ordering::Relaxed),
185            misses: self.misses.load(Ordering::Relaxed),
186            evictions: self.evictions.load(Ordering::Relaxed),
187            pass_throughs: self.pass_throughs.load(Ordering::Relaxed),
188            bytes_read: self.bytes_read.load(Ordering::Relaxed),
189            resident_bytes: resident,
190        }
191    }
192
193    /// Best-effort warm of `keys` into the cache (ds4-style SSD
194    /// streaming prefetch): acquires each key and drops the lease so
195    /// the entry stays resident under the budget until eviction.
196    /// Concurrent acquires on the same key may duplicate I/O; never
197    /// returns wrong bytes. Failures on individual keys are skipped.
198    pub fn prefetch(&self, keys: &[ExpertKey]) {
199        for &key in keys {
200            let _ = self.acquire(key);
201        }
202    }
203
204    /// Returns a pinned lease on `key`'s bytes, reading them from the
205    /// source on a miss. Never blocks waiting for other leases to be
206    /// released: if the entry cannot fit in the budget right now, the
207    /// bytes are returned uncached (see module docs).
208    pub fn acquire(&self, key: ExpertKey) -> io::Result<ExpertLease> {
209        // Fast path: cache hit under the lock.
210        {
211            let mut inner = self.inner.lock().unwrap_or_else(|p| p.into_inner());
212            inner.clock += 1;
213            let clock = inner.clock;
214            if let Some(entry) = inner.entries.get_mut(&key) {
215                entry.last_used = clock;
216                self.hits.fetch_add(1, Ordering::Relaxed);
217                return Ok(ExpertLease {
218                    data: Arc::clone(&entry.data),
219                });
220            }
221        }
222
223        // Miss: read outside the lock so concurrent misses overlap I/O.
224        self.misses.fetch_add(1, Ordering::Relaxed);
225        let data = self.source.read_expert(key)?;
226        self.bytes_read
227            .fetch_add(data.len() as u64, Ordering::Relaxed);
228        let size = data.len();
229        let data = Arc::new(data);
230
231        let mut inner = self.inner.lock().unwrap_or_else(|p| p.into_inner());
232        // Someone else may have inserted this key while we read -- use
233        // theirs (keeps exactly one cached copy), our read becomes the
234        // rare-race duplicate described in the module docs. Already
235        // counted as a miss above (each acquire increments exactly one
236        // of hits/misses), so no hit is recorded here.
237        if let Some(entry) = inner.entries.get_mut(&key) {
238            return Ok(ExpertLease {
239                data: Arc::clone(&entry.data),
240            });
241        }
242
243        if size > self.budget_bytes {
244            self.pass_throughs.fetch_add(1, Ordering::Relaxed);
245            return Ok(ExpertLease { data });
246        }
247
248        // Evict least-recently-used *unleased* entries until it fits.
249        while inner.resident_bytes + size > self.budget_bytes {
250            let victim = inner
251                .entries
252                .iter()
253                .filter(|(_, e)| Arc::strong_count(&e.data) == 1)
254                .min_by_key(|(_, e)| e.last_used)
255                .map(|(k, _)| *k);
256            match victim {
257                Some(k) => {
258                    let e = inner.entries.remove(&k).expect("victim key just found");
259                    inner.resident_bytes -= e.data.len();
260                    self.evictions.fetch_add(1, Ordering::Relaxed);
261                }
262                None => {
263                    // Every resident entry is pinned by a live lease --
264                    // serve uncached rather than waiting (a wait here
265                    // could deadlock against our own caller's leases).
266                    self.pass_throughs.fetch_add(1, Ordering::Relaxed);
267                    return Ok(ExpertLease { data });
268                }
269            }
270        }
271
272        inner.clock += 1;
273        let clock = inner.clock;
274        inner.resident_bytes += size;
275        inner.entries.insert(
276            key,
277            Entry {
278                data: Arc::clone(&data),
279                last_used: clock,
280            },
281        );
282        Ok(ExpertLease { data })
283    }
284}
285
286/// A file-backed [`ExpertSource`]: each expert is one contiguous
287/// `(offset, len)` byte range in a single file, read with positional
288/// reads (`pread`-style on unix, so concurrent misses never contend on
289/// a shared seek cursor). This is the portable buffered-I/O default
290/// the storage design starts from; `O_DIRECT`/`F_NOCACHE`/`io_uring`
291/// variants are future work behind the same trait and must produce
292/// identical bytes.
293pub struct FileRangeSource {
294    file: std::fs::File,
295    ranges: HashMap<ExpertKey, (u64, usize)>,
296    /// Non-unix fallback only: serializes seek+read pairs.
297    #[cfg(not(unix))]
298    seek_lock: Mutex<()>,
299}
300
301impl FileRangeSource {
302    pub fn new(file: std::fs::File, ranges: HashMap<ExpertKey, (u64, usize)>) -> Self {
303        FileRangeSource {
304            file,
305            ranges,
306            #[cfg(not(unix))]
307            seek_lock: Mutex::new(()),
308        }
309    }
310}
311
312impl ExpertSource for FileRangeSource {
313    fn expert_len(&self, key: ExpertKey) -> Option<usize> {
314        self.ranges.get(&key).map(|&(_, len)| len)
315    }
316
317    fn read_expert(&self, key: ExpertKey) -> io::Result<Vec<u8>> {
318        let &(offset, len) = self
319            .ranges
320            .get(&key)
321            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, format!("{key:?}")))?;
322        let mut buf = vec![0u8; len];
323        #[cfg(unix)]
324        {
325            use std::os::unix::fs::FileExt;
326            self.file.read_exact_at(&mut buf, offset)?;
327        }
328        #[cfg(not(unix))]
329        {
330            use std::io::{Read, Seek, SeekFrom};
331            let _guard = self.seek_lock.lock().unwrap_or_else(|p| p.into_inner());
332            let mut f = &self.file;
333            f.seek(SeekFrom::Start(offset))?;
334            f.read_exact(&mut buf)?;
335        }
336        Ok(buf)
337    }
338}
339
340#[cfg(test)]
341mod tests {
342    use super::*;
343
344    /// Deterministic per-key content so any slot-reuse/wrong-bytes bug
345    /// fails loudly: byte `i` of expert `(l, e)` is a function of all
346    /// three.
347    struct PatternSource {
348        len: usize,
349        n_layers: u32,
350        n_experts: u32,
351    }
352
353    fn expected_bytes(key: ExpertKey, len: usize) -> Vec<u8> {
354        (0..len)
355            .map(|i| (key.layer as usize * 31 + key.expert as usize * 7 + i * 13) as u8)
356            .collect()
357    }
358
359    impl ExpertSource for PatternSource {
360        fn expert_len(&self, key: ExpertKey) -> Option<usize> {
361            (key.layer < self.n_layers && key.expert < self.n_experts).then_some(self.len)
362        }
363        fn read_expert(&self, key: ExpertKey) -> io::Result<Vec<u8>> {
364            if self.expert_len(key).is_none() {
365                return Err(io::Error::new(io::ErrorKind::NotFound, "no such expert"));
366            }
367            Ok(expected_bytes(key, self.len))
368        }
369    }
370
371    fn key(layer: u32, expert: u32) -> ExpertKey {
372        ExpertKey { layer, expert }
373    }
374
375    fn store(len: usize, budget: usize) -> ExpertStore<PatternSource> {
376        ExpertStore::new(
377            PatternSource {
378                len,
379                n_layers: 8,
380                n_experts: 8,
381            },
382            budget,
383        )
384    }
385
386    /// The process-wide gauge tracks every live store's budget and
387    /// releases it on drop.
388    ///
389    /// It exists so `weight_matrix::repack_cache` can SUBTRACT the
390    /// expert budget from the same pool rather than declare a second
391    /// one: on unified memory an expert byte and a repacked byte are
392    /// the same RAM, and this module is the single holder of the expert
393    /// half. A gauge that did not fall on drop would starve the repack
394    /// cache for the rest of the process.
395    ///
396    /// The gauge is process-wide and the harness runs these tests in
397    /// parallel, so this asserts against a SENTINEL budget larger than
398    /// every other budget in this module put together rather than
399    /// against an exact total another test could move under it.
400    ///
401    /// Sabotage: delete the `fetch_add` in `new` or the `Drop` impl and
402    /// this goes red.
403    #[test]
404    fn the_committed_gauge_rises_with_a_store_and_falls_when_it_drops() {
405        const SENTINEL: usize = 1 << 40;
406        {
407            let _held = store(64, SENTINEL);
408            assert!(
409                committed_expert_bytes() >= SENTINEL as u64,
410                "a live store must have committed its budget"
411            );
412        }
413        assert!(
414            committed_expert_bytes() < SENTINEL as u64,
415            "a dropped store must return its budget to the pool, or the \
416             repack cache is starved of it for the rest of the process"
417        );
418    }
419
420    #[test]
421    fn hits_misses_and_lru_eviction_order() {
422        let s = store(100, 250); // fits 2 experts
423        assert_eq!(
424            s.acquire(key(0, 0)).unwrap().bytes(),
425            expected_bytes(key(0, 0), 100)
426        );
427        assert_eq!(
428            s.acquire(key(0, 1)).unwrap().bytes(),
429            expected_bytes(key(0, 1), 100)
430        );
431        // Touch (0,0) so (0,1) is now least recently used.
432        s.acquire(key(0, 0)).unwrap();
433        // Third expert evicts (0,1), not (0,0).
434        s.acquire(key(0, 2)).unwrap();
435        let before = s.stats();
436        s.acquire(key(0, 0)).unwrap(); // must still be a hit
437        let after = s.stats();
438        assert_eq!(after.hits, before.hits + 1);
439        assert_eq!(after.misses, before.misses);
440        assert_eq!(after.evictions, 1);
441        assert!(after.resident_bytes <= 250);
442        // (0,1) was the eviction victim: acquiring it again is a miss.
443        s.acquire(key(0, 1)).unwrap();
444        assert_eq!(s.stats().misses, after.misses + 1);
445    }
446
447    #[test]
448    fn a_live_lease_pins_its_entry_against_eviction() {
449        let s = store(100, 250); // fits 2 experts
450        let pinned = s.acquire(key(1, 0)).unwrap();
451        // Fill and churn the cache well past the budget: the pinned
452        // entry must never be evicted or corrupted while the lease
453        // lives...
454        for e in 1..6 {
455            s.acquire(key(1, e)).unwrap();
456        }
457        assert_eq!(pinned.bytes(), expected_bytes(key(1, 0), 100));
458        // ...and it is still resident (a re-acquire is a hit).
459        let hits_before = s.stats().hits;
460        let again = s.acquire(key(1, 0)).unwrap();
461        assert_eq!(s.stats().hits, hits_before + 1);
462        assert_eq!(again.bytes(), expected_bytes(key(1, 0), 100));
463
464        // Once every lease is dropped, pressure may evict it like any
465        // other entry.
466        drop(pinned);
467        drop(again);
468        for e in 1..6 {
469            s.acquire(key(2, e)).unwrap();
470        }
471        let misses_before = s.stats().misses;
472        s.acquire(key(1, 0)).unwrap();
473        assert_eq!(
474            s.stats().misses,
475            misses_before + 1,
476            "unpinned entry was evictable"
477        );
478    }
479
480    /// The plan's "cache smaller than one token's expert union" case:
481    /// a budget that can't hold even one expert still serves correct
482    /// bytes on every acquire, as uncached pass-throughs.
483    #[test]
484    fn budget_smaller_than_one_expert_degrades_to_pass_through_not_failure() {
485        let s = store(100, 50);
486        for e in 0..4 {
487            let lease = s.acquire(key(0, e)).unwrap();
488            assert_eq!(lease.bytes(), expected_bytes(key(0, e), 100));
489        }
490        let st = s.stats();
491        assert_eq!(st.pass_throughs, 4);
492        assert_eq!(st.resident_bytes, 0);
493        assert_eq!(st.evictions, 0);
494    }
495
496    /// If every resident entry is pinned, a new acquire must not
497    /// deadlock or evict a pinned entry -- it passes through.
498    #[test]
499    fn fully_pinned_cache_serves_new_experts_uncached() {
500        let s = store(100, 200);
501        let _a = s.acquire(key(0, 0)).unwrap();
502        let _b = s.acquire(key(0, 1)).unwrap();
503        let c = s.acquire(key(0, 2)).unwrap();
504        assert_eq!(c.bytes(), expected_bytes(key(0, 2), 100));
505        assert_eq!(s.stats().pass_throughs, 1);
506        assert_eq!(s.stats().evictions, 0);
507        // The two pinned entries are still hits.
508        let hits_before = s.stats().hits;
509        s.acquire(key(0, 0)).unwrap();
510        s.acquire(key(0, 1)).unwrap();
511        assert_eq!(s.stats().hits, hits_before + 2);
512    }
513
514    #[test]
515    fn missing_expert_is_a_clean_error() {
516        let s = store(100, 1000);
517        assert!(s.acquire(key(99, 0)).is_err());
518    }
519
520    /// Concurrent stress under a deliberately tiny budget: many
521    /// threads acquiring random keys while evictions churn constantly.
522    /// Every lease's bytes must match that key's expected pattern --
523    /// the direct test for slot-reuse corruption.
524    #[test]
525    fn concurrent_acquires_under_eviction_pressure_never_yield_wrong_bytes() {
526        let s = Arc::new(store(64, 200)); // fits 3 of 16 hot keys
527        let mut handles = Vec::new();
528        for t in 0..8u32 {
529            let s = Arc::clone(&s);
530            handles.push(std::thread::spawn(move || {
531                let mut state = t.wrapping_mul(2654435761).wrapping_add(12345);
532                for _ in 0..500 {
533                    state = state.wrapping_mul(1664525).wrapping_add(1013904223);
534                    let k = key((state >> 8) % 4, (state >> 16) % 4);
535                    let lease = s.acquire(k).expect("in-range key must read");
536                    assert_eq!(
537                        lease.bytes(),
538                        expected_bytes(k, 64),
539                        "wrong bytes for {k:?} -- slot reuse corruption"
540                    );
541                }
542            }));
543        }
544        for h in handles {
545            h.join().unwrap();
546        }
547        let st = s.stats();
548        assert_eq!(
549            st.hits + st.misses,
550            8 * 500,
551            "every acquire is a hit or a miss"
552        );
553        assert!(st.resident_bytes <= 200, "budget held under concurrency");
554    }
555
556    /// The bridge to the weight types: a quantized `WeightMatrix` built
557    /// over a lease's shared buffer must (a) compute exactly what the
558    /// same bytes compute as an owned buffer, and (b) keep the cache
559    /// entry pinned for as long as the matrix lives, even after the
560    /// original lease is dropped.
561    #[test]
562    fn weight_matrix_over_a_lease_computes_identically_and_extends_the_pin() {
563        use crate::weight_matrix::{QuantKind, WeightBytes, WeightMatrix};
564
565        // A source whose "expert" payload is real Q8_0 rows.
566        struct QuantSource {
567            rows: Vec<u8>,
568        }
569        impl ExpertSource for QuantSource {
570            fn expert_len(&self, _k: ExpertKey) -> Option<usize> {
571                Some(self.rows.len())
572            }
573            fn read_expert(&self, _k: ExpertKey) -> io::Result<Vec<u8>> {
574                Ok(self.rows.clone())
575            }
576        }
577
578        let cols = 64;
579        let rows = 2;
580        let values: Vec<f32> = (0..rows * cols)
581            .map(|i| ((i as f32) * 0.11).sin())
582            .collect();
583        let mut packed = Vec::new();
584        for r in 0..rows {
585            packed.extend(ferrox_quant::quantize_q8_0(
586                &values[r * cols..(r + 1) * cols],
587            ));
588        }
589        let store = ExpertStore::new(
590            QuantSource {
591                rows: packed.clone(),
592            },
593            packed.len(),
594        );
595
596        let lease = store.acquire(key(0, 0)).unwrap();
597        let matrix = WeightMatrix::Quantized {
598            data: WeightBytes::Shared {
599                buf: lease.shared_buf(),
600                range: 0..packed.len(),
601            },
602            rows,
603            cols,
604            kind: QuantKind::Q8_0,
605        };
606        drop(lease); // the matrix alone must keep the entry pinned
607
608        let owned = WeightMatrix::Quantized {
609            data: WeightBytes::Owned(packed),
610            rows,
611            cols,
612            kind: QuantKind::Q8_0,
613        };
614        let x: Vec<f32> = (0..cols).map(|i| ((i as f32) * 0.07).cos()).collect();
615        assert_eq!(
616            matrix.apply(&x),
617            owned.apply(&x),
618            "lease-backed == owned, bit for bit"
619        );
620
621        // Entry is still resident (pinned by the matrix): re-acquire is
622        // a hit even though the budget is exactly one expert.
623        let hits_before = store.stats().hits;
624        store.acquire(key(0, 0)).unwrap();
625        assert_eq!(store.stats().hits, hits_before + 1);
626    }
627
628    /// End-to-end through a real on-disk file: positional-range reads
629    /// through the bounded store return exactly the bytes written at
630    /// each expert's offset, including under concurrent access.
631    #[test]
632    fn file_range_source_reads_correct_ranges_through_the_store() {
633        let dir = std::env::temp_dir();
634        let path = dir.join(format!(
635            "ferrox_expert_store_test_{}.bin",
636            std::process::id()
637        ));
638        let mut file_bytes = Vec::new();
639        let mut ranges = HashMap::new();
640        for l in 0..3u32 {
641            for e in 0..4u32 {
642                let content = expected_bytes(key(l, e), 96);
643                ranges.insert(key(l, e), (file_bytes.len() as u64, content.len()));
644                file_bytes.extend_from_slice(&content);
645            }
646        }
647        std::fs::write(&path, &file_bytes).unwrap();
648        let source = FileRangeSource::new(std::fs::File::open(&path).unwrap(), ranges);
649        let store = Arc::new(ExpertStore::new(source, 300)); // fits 3 of 12
650
651        let mut handles = Vec::new();
652        for t in 0..4u32 {
653            let store = Arc::clone(&store);
654            handles.push(std::thread::spawn(move || {
655                for i in 0..200u32 {
656                    let k = key((t + i) % 3, i % 4);
657                    let lease = store.acquire(k).unwrap();
658                    assert_eq!(lease.bytes(), expected_bytes(k, 96));
659                }
660            }));
661        }
662        for h in handles {
663            h.join().unwrap();
664        }
665        std::fs::remove_file(&path).ok();
666    }
667}