pub struct LlmCache { /* private fields */ }Expand description
Content-hash-keyed file cache for LLM inference.
Cloning is cheap — the counters use shared atomics so a cloned
handle reports the same totals as its parent, which is the
invariant the CLI --stats subcommand relies on when multiple
pipeline threads each hold a handle.
Implementations§
Source§impl LlmCache
impl LlmCache
Sourcepub const fn new(root: PathBuf) -> Self
pub const fn new(root: PathBuf) -> Self
Constructs a cache rooted at root with the DEFAULT_TTL.
The directory is created lazily on the first write; calling this on a path that does not yet exist is fine.
§Examples
use ssg::llm_cache::LlmCache;
let tmp = tempfile::tempdir().unwrap();
let cache = LlmCache::new(tmp.path().to_path_buf());
assert_eq!(cache.root(), tmp.path());Sourcepub const fn with_ttl(root: PathBuf, ttl: Duration) -> Self
pub const fn with_ttl(root: PathBuf, ttl: Duration) -> Self
Constructs a cache rooted at root with a custom TTL. Used by
the AC4 expiry tests so they don’t have to wait 90 days.
§Examples
use std::time::Duration;
use ssg::llm_cache::LlmCache;
let tmp = tempfile::tempdir().unwrap();
let cache = LlmCache::with_ttl(tmp.path().to_path_buf(), Duration::from_secs(60));
assert_eq!(cache.stats().hits, 0);Sourcepub fn default_cache_dir() -> PathBuf
pub fn default_cache_dir() -> PathBuf
Resolves the platform-default cache root.
Selection order (first that yields a path wins):
$SSG_LLM_CACHE_DIR— explicit override, used by tests and by ops who want to point at a shared cache on tmpfs.$XDG_CACHE_HOME/ssg/llm— Linux /XDG_CACHE_HOMEset.$HOME/Library/Caches/ssg/llm— macOS default.%LOCALAPPDATA%\ssg\llm— Windows.$HOME/.cache/ssg/llm— generic Unix fallback../.ssg-llm-cache— last-resort relative path so the cache is still usable in sandboxes where neither$HOMEnor%LOCALAPPDATA%is set.
§Examples
use ssg::llm_cache::LlmCache;
let dir = LlmCache::default_cache_dir();
assert!(!dir.as_os_str().is_empty());Sourcepub fn compute_key(
endpoint: &str,
model: &str,
prompt: &str,
timeout_secs: u64,
) -> [u8; 32]
pub fn compute_key( endpoint: &str, model: &str, prompt: &str, timeout_secs: u64, ) -> [u8; 32]
Computes the 32-byte SHA-256 key for (endpoint, model, prompt, timeout_secs).
Every parameter that can change the model’s output is folded into the digest so a request that differs in even one byte gets a fresh inference (AC2). The hash is domain-separated with a versioned prefix so a future change to the key composition can be rolled out without colliding with stored entries.
§Examples
use ssg::llm_cache::LlmCache;
let a = LlmCache::compute_key("http://x", "llama", "hi", 30);
let b = LlmCache::compute_key("http://x", "llama", "hi", 30);
assert_eq!(a, b);
let c = LlmCache::compute_key("http://x", "llama", "bye", 30);
assert_ne!(a, c);Sourcepub fn get(&self, key: &[u8; 32]) -> Option<String>
pub fn get(&self, key: &[u8; 32]) -> Option<String>
Returns the cached payload for key, or None on miss /
stale / corrupt.
A corrupted entry (truncated JSON, version mismatch, length mismatch) is evicted in-place and reported as a miss so the caller does a fresh inference (AC5). A TTL-expired entry is handled the same way (AC4).
§Examples
use ssg::llm_cache::LlmCache;
let tmp = tempfile::tempdir().unwrap();
let cache = LlmCache::new(tmp.path().to_path_buf());
let key = LlmCache::compute_key("e", "m", "p", 1);
assert!(cache.get(&key).is_none());
cache.set(&key, "answer").unwrap();
assert_eq!(cache.get(&key).as_deref(), Some("answer"));Sourcepub fn set(&self, key: &[u8; 32], payload: &str) -> Result<()>
pub fn set(&self, key: &[u8; 32], payload: &str) -> Result<()>
Stores payload under key.
Returns Ok(()) on success. On any filesystem error the call
silently falls through (counter is not bumped) so a transient
disk failure never breaks the build — the next invocation
will just be another miss + recompute.
§Errors
Returns the underlying io::Error when the cache file cannot
be created or renamed into place.
§Examples
use ssg::llm_cache::LlmCache;
let tmp = tempfile::tempdir().unwrap();
let cache = LlmCache::new(tmp.path().to_path_buf());
let key = LlmCache::compute_key("e", "m", "p", 1);
cache.set(&key, "stored").unwrap();
assert_eq!(cache.stats().stores, 1);Sourcepub fn evict(&self, key: &[u8; 32]) -> Result<()>
pub fn evict(&self, key: &[u8; 32]) -> Result<()>
Removes the entry for key if present. Used by the
ssg cache --clear command and by the unit tests.
§Errors
Returns the underlying io::Error when the entry exists but
cannot be removed. A missing entry is treated as success.
§Examples
use ssg::llm_cache::LlmCache;
let tmp = tempfile::tempdir().unwrap();
let cache = LlmCache::new(tmp.path().to_path_buf());
let key = LlmCache::compute_key("e", "m", "p", 1);
cache.set(&key, "x").unwrap();
cache.evict(&key).unwrap();
assert!(cache.get(&key).is_none());Sourcepub fn stats(&self) -> CacheStats
pub fn stats(&self) -> CacheStats
Returns the running session counters.
§Examples
use ssg::llm_cache::LlmCache;
let tmp = tempfile::tempdir().unwrap();
let cache = LlmCache::new(tmp.path().to_path_buf());
let stats = cache.stats();
assert_eq!(stats.hits, 0);
assert_eq!(stats.stores, 0);Trait Implementations§
Auto Trait Implementations§
impl !Freeze for LlmCache
impl RefUnwindSafe for LlmCache
impl Send for LlmCache
impl Sync for LlmCache
impl Unpin for LlmCache
impl UnsafeUnpin for LlmCache
impl UnwindSafe for LlmCache
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more