Expand description
Concurrent, process-safe storage for immutable [LLVM GSYM] files.
gsym-cache separates the profiler’s read path from the machinery that
creates and maintains cached files. A lookup takes no lock and performs no
write. Optional features add debounced recency markers, nonblocking
population ownership, verified atomic publication, negative caching, and
bounded maintenance.
Conversion, downloads, worker scheduling, and resource limits remain with the application.
§Quick start
Open a cache without creating it, then look up a binary build identifier:
use gsym_cache::{BuildId, Cache, CacheEpoch};
let cache = Cache::open("/var/cache/my-profiler/gsym", CacheEpoch::new(1))?;
let build_id: BuildId = "1212121212121212121212121212121212121212".parse()?;
if let Some(entry) = cache.lookup(&build_id)? {
println!("cached GSYM: {} bytes", entry.len());
}Population is an explicit, nonblocking state machine:
use std::fs::File;
use std::io;
use gsym_cache::{BuildId, Cache, CacheEpoch, PopulationOutcome};
let cache = Cache::open("/var/cache/my-profiler/gsym", CacheEpoch::new(1))?;
let build_id = BuildId::new([0x12; 20])?;
match cache.try_begin_population(&build_id)? {
PopulationOutcome::Present(entry) => drop(entry),
PopulationOutcome::Acquired(population) => {
let mut source = File::open("artifact.gsym")?;
let mut writer = population.into_writer()?;
io::copy(&mut source, &mut writer)?;
drop(writer.publish()?.into_entry());
}
PopulationOutcome::Suppressed(failure) => {
eprintln!("retry after {:?}", failure.expires_at());
}
PopulationOutcome::Busy => eprintln!("another process owns population"),
}§Choosing an entry point
| To … | Use | Notes |
|---|---|---|
| use an explicit cache root | Cache::open | suitable for services and privileged applications |
| follow the XDG cache convention | Cache::open_xdg | validates the cache home and application component |
| read an immutable entry | Cache::lookup | lock-free and deliberately does not decode GSYM |
| record coarse recency | Cache::record_access | access feature; call only after a hit |
| coordinate a cache miss | Cache::try_begin_population | manage feature; never waits |
| enforce capacity or age limits | Cache::prune | manage feature; uses 80% low-watermark hysteresis |
| verify and repair stored state | Cache::scrub | manage feature; checks complete GSYM files |
§Usage notes
-
A
BuildIdis an opaque cache key, not proof that input is trustworthy. Keep one private root per trust domain and isolate converters that consume untrusted binaries. -
CacheEpochversions the application’s conversion policy. Increment it when the same build ID could produce different bytes. Old epochs are separate namespaces and can be removed after their workers stop. -
Cache::lookupverifies ownership and file type, but not GSYM contents. Managed publication and scrubbing perform complete GSYM verification so the profiler-facing path stays small. -
Directory descriptors are pinned after they are opened. Create a new
Cacheafter replacing a cache namespace directory. -
Durability and no-clobber behavior assume a private cache root on a local Linux filesystem with advisory
flock, atomic rename, and directoryfsyncsemantics.
§Feature flags
| Feature | Default | Adds |
|---|---|---|
lookup | yes | build IDs, cache opening, and lock-free lookup |
access | no | debounced access markers; implies lookup |
manage | no | population, negative caching, pruning, and scrubbing; implies access |
Read-only use needs only the default feature:
[dependencies]
gsym-cache = "0.1"§Errors
Fallible entry points return Result<T>. Error distinguishes I/O,
unsafe directory or entry layouts, invalid GSYM, build-ID mismatch, and invalid
negative-cache lifetimes. It is #[non_exhaustive], so exhaustive matches need
a fallback arm.
Cache misses, active population, and active maintenance are ordinary outcomes, not errors.
§Guides
docs::deployment: roots, epochs, trust boundaries, filesystems, and process behavior.docs::operations: population, negative caching, access tracking, pruning, scrubbing, and crash recovery.docs::cookbook: complete lookup, publication, suppression, and maintenance recipes. [LLVM GSYM]: https://llvm.org/doxygen/namespacellvm_1_1gsym.html
Modules§
- docs
- Deployment and operations guides.
Structs§
- BuildId
- A validated, owned binary build identifier.
- Build
IdMismatch Error - GSYM build-identifier mismatch with bounded diagnostic data.
- Byte
Limit - Nonzero cache-size limit in bytes.
- Cache
- A configured GSYM filesystem cache.
- Cache
Entry - An opened, immutable cache entry.
- Cache
Epoch - Version of the conversion policy used to create cached GSYM files.
- Cache
Stats - Current size of the recognized object tree.
- Cached
Failure - An unexpired persistent population failure.
- Entry
Limit - Nonzero cache-entry limit.
- Invalid
Gsym Error - Invalid GSYM file with its cache path.
- Population
- Exclusive population capability for one build identifier.
- Population
Writer - Exclusive write-only owner of a staged GSYM file.
- Prune
Policy - Size, count, and age policy for cache pruning.
- Prune
Report - Measurements from a completed prune pass.
- Scrub
Report - Measurements from a completed scrub pass.
Enums§
- Access
Update - Whether access-marker write traffic was required.
- Build
IdError - Build identifier validation error.
- Error
- Cache operation failure.
- Failure
Kind - Stable class of a population failure.
- Population
Outcome - Outcome of trying to acquire population ownership.
- Prune
Outcome - Outcome of nonblocking cache pruning.
- Publish
Outcome - Result of publishing a verified staged file.
- Scrub
Outcome - Outcome of nonblocking cache scrubbing.
Constants§
- MAX_
FAILURE_ TTL - Longest accepted negative-cache lifetime.
Type Aliases§
- Result
- Result type used by this crate.