1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! # Capability cache lifecycle (1.1.0)
//!
//! Demonstrates the three public capability-cache entry points:
//!
//! - [`fsys::capability::capabilities`] — cached, sub-millisecond.
//! - [`fsys::capability::probe_capabilities_fresh`] — forces a
//! re-probe and rewrites the cache file.
//! - [`fsys::capability::invalidate_capability_cache`] — deletes
//! the cache file so the next process re-probes.
//!
//! The example also shows the timing delta between a cached
//! lookup and a fresh probe so consumers see why caching matters.
//!
//! Run: `cargo run --example 31_capability_cache_lifecycle`
use std::time::Instant;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// First call to `capabilities()` will read the cache file (or
// probe + write it if missing). Subsequent calls hit the
// process-wide `OnceLock`.
let t = Instant::now();
let first = fsys::capability::capabilities();
let first_call = t.elapsed();
let t = Instant::now();
let _second = fsys::capability::capabilities();
let second_call = t.elapsed();
println!("capabilities() — first call: {:?}", first_call);
println!("capabilities() — second call: {:?}", second_call);
println!(" fsys version: {}", first.fsys_version);
println!(" os target: {}", first.os_target);
println!(" spdk eligible: {}", first.spdk_eligible);
println!();
// Forced fresh probe — ignores the cache file, writes a new
// one on success. Note this does *not* update the process-wide
// `OnceLock` — that is only re-populated on a fresh process.
let t = Instant::now();
let fresh = fsys::capability::probe_capabilities_fresh();
let fresh_probe = t.elapsed();
println!("probe_capabilities_fresh(): {:?}", fresh_probe);
println!(" schema version: {}", fresh.schema_version);
println!();
// Cache file location (overridable via FSYS_CACHE_DIR).
match fsys::capability::cache::cache_file_path() {
Some(p) => println!("Cache file: {}", p.display()),
None => println!("Cache file: <no candidate directory>"),
}
println!();
// Invalidation deletes the cache file. The next process start
// will re-probe and rewrite. Within this process the cached
// `OnceLock` remains valid for backwards-compatibility — the
// contract is "delete the file"; the cached in-memory snapshot
// outlives the file.
fsys::capability::invalidate_capability_cache()?;
println!("invalidate_capability_cache() — cache file deleted");
Ok(())
}