emulators.extraction_cache.ExtractionCache
A per-instance, opt-in archive/pkg extraction cache.
A per-instance, opt-in archive/pkg extraction cache.
One instance owns one cache directory tree and one lock; no two instances may ever own or nest the same directory (a convention this class does not itself enforce).
Functions
func__init__(self, name, cache_dir, enabled, max_gb, find_boot_target, *, budget=None, stage=None, phase_name=lambda rom: 'extracting_archive', on_evict=None, expansion_factor=lambda: 4.0, extract_timeout=lambda: 1800.0, lock_wait=lambda: 120.0, missing_target_error='held no bootable target') -> NoneInitialize the extraction cache with callables for all configuration.
All configuration parameters are stored as callables, never snapshotted, so consumer modules can monkeypatch their module-level config at test time and this instance will read the current values on each call.
paramselfparamnamestrThe cache name, for logging and identification.
paramcache_dirCallable[[], Path]Callable returning the cache root directory.
paramenabledCallable[[], bool]Callable returning True if the cache is enabled.
parammax_gbCallable[[], float]Callable returning the maximum cache size in GB.
paramfind_boot_targetCallable[[Path], Optional[Path]]Callable taking a Path and returning the bootable target inside it, or None.
parambudgetOptional[Callable[[Path], tuple[int, int]]]= NoneOptional callable for cache budget calculation.
paramstageOptional[Callable[[Path, Path, Path, Emulator, int], None]]= NoneOptional callable for custom extraction staging.
paramphase_nameCallable[[Path], str]= lambda rom: 'extracting_archive'Callable returning the phase name for a ROM.
paramon_evictOptional[Callable[[Path], None]]= NoneOptional callable run when evicting a cache entry.
paramexpansion_factorCallable[[], float]= lambda: 4.0Callable returning the expected extraction expansion factor.
paramextract_timeoutCallable[[], float]= lambda: 1800.0Callable returning extraction timeout in seconds.
paramlock_waitOptional[Callable[[], float]]= lambda: 120.0Optional callable returning lock wait timeout in seconds.
parammissing_target_errorstr= 'held no bootable target'Error message when no bootable target is found.
Returns
Nonefuncroot(self) -> PathThe configured cache directory, read live from the cache_dir callable.
paramselfReturns
pathlib.Pathfuncentry_dir(self, rom) -> Optional[Path]The cache entry an earlier extract of rom left, without extracting anything.
paramselfparamromPathThe archive or package.
Returns
typing.OptionalThe entry's directory, or None when rom has not been extracted
func_cache_size_bytes(self) -> intSum the sizes of all cache entries, or zero if the cache dir doesn't exist yet.
paramselfReturns
intThe total size in bytes of all files in all cache entries under root(), or 0 if root() is not a directory.
func_evict_lru(self, needed_bytes, keep) -> NoneEvict least-recently-used cache entries until needed_bytes fits within max_gb.
paramselfparamneeded_bytesintAdditional bytes that must fit under the cache cap.
paramkeepstrThe cache key currently being (re-)extracted, so a stale entry for it already removed by the caller is never chosen.
Returns
Nonefunc_require_room(self, peak_bytes, kept_bytes, rom_name) -> NoneRefuse an extraction that cannot fit before any of it is written.
Two different figures cover two different ceilings: the cache cap
counts only what survives (kept_bytes), while the free-space guard
counts what is on disk at the extraction's worst moment (peak_bytes),
which can exceed what is kept when a consumer's staging needs scratch
space alongside its final output.
Raises
RuntimeError: If the cache cap or the filesystem cannot hold it.
paramselfparampeak_bytesintBytes on disk at the height of the extraction.
paramkept_bytesintBytes the finished extraction leaves in the cache.
paramrom_namestrThe ROM being extracted, named in the error.
Returns
Nonefunc_locked(self, what) -> Iterator[None]Hold this instance's lock for the block.
Blocks with no timeout when lock_wait is None; otherwise gives up
and raises after lock_wait() seconds.
Raises
RuntimeError: When a boundedlock_waitelapses before the lock is free.
paramselfparamwhatstrThe operation waiting for the lock, named in the log and the error.
Returns
typing.Iterator[None]func_clear_scratch(self) -> NoneRemove every staged extraction under the scratch dir. Callers must hold _locked.
The lock is what makes this safe: no extraction can be mid-flight while it is held, so anything still sitting here was orphaned by a process that died.
paramselfReturns
Nonefuncsweep_stale_extractions(self) -> NoneRemove extraction scratch dirs orphaned by a crashed broker process.
Call once at broker startup: the only other caller is an extraction, which a library of already-extracted (or never-archived) titles may never run again.
paramselfReturns
Nonefunc_default_stage(self, archive, staged, scratch, emulator, kept_bytes) -> NoneThe default stage: extract archive directly into staged.
paramselfparamarchivePathparamstagedPathparamscratchPathparamemulatorEmulatorparamkept_bytesintReturns
Nonefunc_default_budget(self, rom) -> tuple[int, int]The default budget: the archive's own listed size, or a compressed-size fallback.
paramselfparamromPathReturns
tuple[int, int]funcextract(self, rom, emulator) -> PathGet rom booting from the cache, extracting it if not already cached.
Reuses a prior extraction keyed by _cache_key when one already
holds a bootable target. rom is staged under a scratch dir and only
renamed to the persistent game_dir once a boot target is confirmed,
so game_dir either does not exist or holds a complete extraction.
Holds this instance's lock for the whole call: eviction, extraction, and the boot-target lookup all touch the same cache tree, so a second call racing in here must wait rather than potentially evicting the directory this one is mid-extracting into or about to boot from.
Raises
RuntimeError: Ifromcannot be read to key it, the extraction cannot fit in the cache or on the disk,stagefails, the extraction holds no boot target, or the finished extraction cannot be moved to its cache key.OSError: If the cache dir or a scratch dir cannot be created at all.
paramselfparamromPathThe archive or package to extract.
paramemulatorEmulatorThe launching emulator; emulator.extraction_phase is
set while this runs, cleared again before returning or raising.
Returns
pathlib.Path