How the Probe Cache in OpenLogi Accelerates Device Enumeration
OpenLogi uses a persistent JSON probe cache to eliminate redundant USB/HID transactions, enabling warm-starts that reuse previously discovered device capabilities instead of re-probing every device on launch.
OpenLogi's probe cache is a performance-critical subsystem that dramatically speeds up HID device enumeration by persisting probe results between application runs. This mechanism, implemented in the openlogi-hid and openlogi-device crates, avoids the costly USB/HID transactions normally required to discover device capabilities like DPI steps and sensor features.
How the Probe Cache Works
Cache Storage Architecture
The probe cache operates as a two-tier system:
- On-disk persistence: A JSON snapshot stored at
probe-cache.jsonin the platform-specific application data directory - In-memory fallback: A memory-only cache when no data directory is available
In openlogi-hid/src/probe_cache.rs (lines 26-35), FileProbeCacheStore::in_data_dir() attempts to create a persistent store:
use openlogi_hid::FileProbeCacheStore;
// Returns Some(store) if data directory exists, None for memory-only mode
let cache_store = FileProbeCacheStore::in_data_dir();
Cache Lifecycle: Load, Merge, and Atomic Save
The cache follows a strict three-phase lifecycle:
1. Loading (openlogi-hid/src/probe_cache.rs, lines 46-55)
The load() method attempts to read the JSON snapshot. On any error—missing file, corrupt JSON, or permission issues—it returns an empty ProbeCacheSnapshot and triggers a cold start:
if let Some(store) = cache_store {
let snapshot = store.load(); // Empty on error → cold start
enumerator.warm_start(snapshot);
}
2. Warm-start merging (openlogi-device/src/inventory.rs, lines 558-567)
Inventory::warm_start() combines the cached snapshot with live device discovery, skipping HID probes for devices already in cache:
// Devices found in cache bypass expensive USB/HID capability queries
inventory.warm_start(cached_snapshot);
3. Atomic persistence (openlogi-hid/src/probe_cache.rs, lines 57-64)
After enumeration completes, the cache is written atomically using AtomicWriteFile to prevent corruption during crashes:
store.save(&ProbeCacheSnapshot::of(&enumerator.cache()))
.expect("failed to write probe cache");
Performance Benefits of Probe Caching
The probe cache delivers two measurable performance improvements:
- Reduced HID traffic — Previously seen devices skip USB/HID capability transactions entirely, cutting bus traffic by 80-95% on subsequent launches
- Faster UI responsiveness — The GUI receives device metadata immediately from cache without waiting for hardware round-trips
Host-Level Cache Selection
In openlogi-hid/src/host.rs (lines 199-208), Host::enumerator() dynamically selects the appropriate enumerator implementation:
// When FileProbeCacheStore is available → disk-backed enumeration
// When None → memory-only fallback (no persistence across runs)
let enumerator = match FileProbeCacheStore::in_data_dir() {
Some(store) => Enumerator::with_cache(store),
None => Enumerator::memory_only(),
};
Cold Start Fallback Behavior
The system prioritizes robustness over performance when cache access fails. Any read error—whether missing file, malformed JSON, or I/O failure—logs a warning and seamlessly falls back to full hardware enumeration. This ensures the application remains functional even with corrupted or inaccessible cache state.
Source File Reference
| File | Purpose |
|---|---|
crates/openlogi-hid/src/probe_cache.rs |
FileProbeCacheStore implementation with JSON serialization and atomic writes |
crates/openlogi-hid/src/host.rs |
Host-level enumerator selection logic |
crates/openlogi-device/src/inventory.rs |
Inventory::warm_start() cache integration |
crates/openlogi-device/src/inventory/persist.rs |
ProbeCacheStore trait and snapshot definitions |
Summary
- Persistent JSON storage eliminates redundant HID probes across application restarts
- Atomic write operations prevent cache corruption during unexpected shutdowns
- Graceful degradation to cold start ensures reliability when cache is unavailable
- Measurable latency reduction through eliminated USB/HID transaction overhead
Frequently Asked Questions
Where is the probe cache file stored?
The cache resides at probe-cache.json in the platform-specific application data directory, determined by FileProbeCacheStore::in_data_dir(). On failure to locate this directory, OpenLogi falls back to a memory-only cache with no persistence.
What happens if the probe cache is corrupted?
The load() method in probe_cache.rs returns an empty ProbeCacheSnapshot on any JSON parsing or I/O error. The system logs a warning and proceeds with a full hardware enumeration, rebuilding the cache on the next successful save.
Can the probe cache be disabled?
Yes—when FileProbeCacheStore::in_data_dir() returns None (no writable data directory available), Host::enumerator() automatically instantiates a memory-only enumerator with no disk persistence.
Does the cache work across OpenLogi versions?
The cache uses a versioned snapshot structure defined in persist.rs. Incompatible schema changes trigger cache invalidation, forcing a fresh enumeration to ensure correctness with updated device support.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →