# diskcache_oxide > A shared, durable disk cache for Python, with a Rust engine, SQLite storage, and a diskcache-compatible API. ## Why choose it Measured against the defunct python-diskcache 5.6.3 (last release August 2023), same machine, same session: - A cached `get` in 0.76 µs at p50 (0.42× diskcache), a `set` in 22.6 µs (0.77×), on Python 3.14; the free-threaded build is within a few percent. See [Performance](https://mkennedy.codes/docs/diskcache-oxide/user-guide/performance.html). - Eight threads sharing one `Cache` at a 99:1 read:write mix: about 650,000 operations a second, flat from 1 to 8 threads, where diskcache falls from 406,000 to 19,000 (Apple M5 Pro, Python 3.14 with the GIL; `bench/results/macos/gate-3.14.txt`). See the chart on the [home page](https://mkennedy.codes/docs/diskcache-oxide/). - Eight worker processes writing to a `FanoutCache(shards=8)`: about 1.5 million operations a second, against 262,000 for a plain `Cache` and 1.24 million for diskcache's own `FanoutCache`. See [FanoutCache](https://mkennedy.codes/docs/diskcache-oxide/user-guide/fanoutcache.html). - A prefix scan over 400,000 keys in about 10 ms, against about 25 seconds in diskcache, because `iterkeys(prefix=)` is an indexed range scan. See [Getting started](https://mkennedy.codes/docs/diskcache-oxide/user-guide/getting-started.html#list-keys). - Beyond speed: safe across `fork()` and on free-threaded CPython, no pickle on disk unless asked for, bounded connections, memory and write-ahead log, and three diskcache bugs fixed (`clear()` losing concurrent writes, `expire()` leaving entries behind, spurious misses during an overwrite). See [Divergences](https://mkennedy.codes/docs/diskcache-oxide/user-guide/divergences.html). ## Docs ### API Reference #### Cache > Disk-backed cache backed by SQLite, shared safely across threads and processes. - [Cache](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.html): A disk cache backed by SQLite, shared safely across threads and processes #### Cache Methods > Methods for the Cache class - [Cache.directory](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.directory.html): The cache directory, as given to the constructor - [Cache.timeout](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.timeout.html): Seconds a call waits for a lock or a pending fork before raising `Timeout` - [Cache.size_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.size_limit.html): The disk budget in bytes. A `set()` that finds the cache over it evicts entries - [Cache.cull_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.cull_limit.html): The most entries a single `set()` evicts when the cache is over `size_limit` - [Cache.enabled](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.enabled.html): Always True for a real cache; False for a `NullCache` - [Cache.set](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.set.html): Store `value` under `key`, replacing any existing value - [Cache.add](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.add.html): Store `value` only if `key` is missing or expired - [Cache.delete](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.delete.html): Remove `key` - [Cache.pop](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.pop.html): Remove `key` and return its value, delivering it to exactly one caller - [Cache.touch](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.touch.html): Change the expiry of an existing entry without rewriting its value - [Cache.incr](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.incr.html): Add `delta` to the number stored under `key`, atomically, and return the result - [Cache.decr](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.decr.html): Subtract `delta` from the number stored under `key`, atomically. See `incr()` - [Cache.iterkeys](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.iterkeys.html): Iterate over keys in sorted order, optionally only those starting with `prefix` - [Cache.expire](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.expire.html): Remove every expired entry, and its value file - [Cache.clear](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.clear.html): Remove every entry that existed when the call started - [Cache.cull](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.cull.html): Remove expired entries, then evict the least recently stored until under `size_limit` - [Cache.volume](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.volume.html): The cache's size on disk in bytes: the database plus value files - [Cache.checkpoint](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.checkpoint.html): Copy the write-ahead log into the database and truncate it to zero - [Cache.close](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.close.html): Close this handle and return its connections - [Cache.transact](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.transact.html): A write transaction, for `with cache.transact() as tx:` - [Cache.__getitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__getitem__.html): `cache[key]`: the value, or `KeyError` if it's missing or expired, or the read failed under - [Cache.__setitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__setitem__.html): `cache[key] = value`: store a value that never expires, like `set()`. Under `durable=True` a failed write is - [Cache.__delitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__delitem__.html): `del cache[key]`: remove the entry, or raise `KeyError` if it's missing or expired, or the delete failed - [Cache.__contains__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__contains__.html): `key in cache`: True if the key holds a live (unexpired) value. False if the check failed under - [Cache.__len__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__len__.html): The number of entries, including expired entries not yet removed - [Cache.__bool__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__bool__.html): Always True, even when empty, so `if cache:` means "caching is on" - [Cache.__iter__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__iter__.html): Iterate over keys in insertion order. An overwrite keeps its key's place - [Cache.__enter__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__enter__.html): Return the cache, for `with Cache(...) as cache:` - [Cache.__exit__](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.__exit__.html): Close the cache, as `close()` does - [Cache.get](https://mkennedy.codes/docs/diskcache-oxide/reference/Cache.get.html): Return the value stored for `key`, or `default` if it's missing or expired #### FanoutCache > A cache sharded over several SQLite databases, so writers in many processes stop queueing on one write lock. - [FanoutCache](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.html): A disk cache split over several SQLite databases (shards), so reads and writes on different keys #### FanoutCache Methods > Methods for the FanoutCache class - [FanoutCache.directory](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.directory.html): The root directory, as given to the constructor - [FanoutCache.timeout](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.timeout.html): Seconds a call waits for a lock or a pending fork before raising `Timeout` - [FanoutCache.shards](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.shards.html): How many shards the root has - [FanoutCache.size_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.size_limit.html): The disk budget in bytes: the sum of every shard's - [FanoutCache.cull_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.cull_limit.html): The most entries a single `set()` evicts from its shard when that shard is over its share - [FanoutCache.enabled](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.enabled.html): Always True for a real cache; False for a `NullCache` - [FanoutCache.shard_of](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.shard_of.html): The shard `key` lives in, from 0 to `shards - 1`: the same in every process and release - [FanoutCache.transact](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.transact.html): A write transaction on the shard `key` lives in, for `with cache.transact(key='total') as tx:` - [FanoutCache.set](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.set.html): As `Cache.set`, on the key's shard - [FanoutCache.add](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.add.html): As `Cache.add`, on the key's shard: atomic across threads and processes - [FanoutCache.delete](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.delete.html): As `Cache.delete`, on the key's shard - [FanoutCache.pop](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.pop.html): As `Cache.pop`, on the key's shard - [FanoutCache.touch](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.touch.html): As `Cache.touch`, on the key's shard - [FanoutCache.incr](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.incr.html): As `Cache.incr`, on the key's shard: atomic across threads and processes - [FanoutCache.decr](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.decr.html): As `Cache.decr`, on the key's shard - [FanoutCache.volume](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.volume.html): The total disk use in bytes of every shard (databases plus value files) - [FanoutCache.expire](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.expire.html): Remove every expired entry from every shard, and its value file, as `Cache.expire` does - [FanoutCache.clear](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.clear.html): Remove every entry that existed when the call started, from every shard - [FanoutCache.cull](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.cull.html): Remove expired entries, then evict the least recently stored from each shard until it's - [FanoutCache.checkpoint](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.checkpoint.html): Checkpoint every shard's write-ahead log and truncate it to zero, as `Cache.checkpoint` does - [FanoutCache.iterkeys](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.iterkeys.html): Iterate over keys in sorted order, optionally only those starting with `prefix` - [FanoutCache.__iter__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__iter__.html): Iterate over every key once: shard 0's in insertion order, then shard 1's, and so on - [FanoutCache.close](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.close.html): Close this handle on every shard, as `Cache.close()` does for one - [FanoutCache.__getitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__getitem__.html): `cache[key]`, as on `Cache` - [FanoutCache.__setitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__setitem__.html): `cache[key] = value`, as on `Cache` - [FanoutCache.__delitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__delitem__.html): `del cache[key]`, as on `Cache` - [FanoutCache.__contains__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__contains__.html): `key in cache`, as on `Cache` - [FanoutCache.__len__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__len__.html): The number of entries in every shard, including expired entries not yet removed - [FanoutCache.__bool__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__bool__.html): Always True, even when empty, so `if cache:` means "caching is on" - [FanoutCache.__enter__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__enter__.html): Return the cache, for `with FanoutCache(...) as cache:` - [FanoutCache.__exit__](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.__exit__.html): Close the cache, as `close()` does - [FanoutCache.get](https://mkennedy.codes/docs/diskcache-oxide/reference/FanoutCache.get.html): As `Cache.get`, on the key's shard #### NullCache > Switched-off cache behaving as if every entry expires instantly. - [NullCache](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.html): A switched-off cache, so app code needs no `if cache is None` checks - [CacheLike](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.html): What application code can rely on from a `Cache`, a `FanoutCache` or a `NullCache` - [TransactionalCacheLike](https://mkennedy.codes/docs/diskcache-oxide/reference/TransactionalCacheLike.html): A `CacheLike` with `transact()`, which `Cache` and `NullCache` both have - [ShardedCacheLike](https://mkennedy.codes/docs/diskcache-oxide/reference/ShardedCacheLike.html): A `CacheLike` with a sharded cache's `transact(*, key, retry=False)`, which `FanoutCache` and #### NullCache Methods > Methods for the NullCache class - [NullCache.__repr__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__repr__.html): Shows the directory and any `invalidate=` cache - [NullCache.directory](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.directory.html): The directory passed to the constructor, or None. Nothing is created there - [NullCache.timeout](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.timeout.html): The timeout passed to the constructor (default 60). Unused - [NullCache.size_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.size_limit.html): The size limit passed to the constructor (default 1 GiB). Unused - [NullCache.cull_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.cull_limit.html): The cull limit passed to the constructor (default 10). Unused - [NullCache.enabled](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.enabled.html): Always False: caching is off - [NullCache.get](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.get.html): Return `default`, as every entry has already expired. With `expire_time=True`, `(default, None)` - [NullCache.__getitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__getitem__.html): Always raises `KeyError`, as every entry has already expired - [NullCache.__contains__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__contains__.html): Always False - [NullCache.__len__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__len__.html): Always 0 - [NullCache.__bool__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__bool__.html): Always False, so `if cache:` means "caching is on" - [NullCache.__iter__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__iter__.html): Yields nothing - [NullCache.volume](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.volume.html): Always 0: a `NullCache` uses no disk - [NullCache.checkpoint](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.checkpoint.html): Always True: there is no write-ahead log to reset - [NullCache.set](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.set.html): Return True without storing anything: the write succeeds, then expires instantly - [NullCache.__setitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__setitem__.html): Store nothing, as `set()` does - [NullCache.add](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.add.html): Return True without storing anything: the key is always absent, so the add succeeds - [NullCache.touch](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.touch.html): Always False: the key never exists - [NullCache.incr](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.incr.html): Return `default + delta`, since every count starts again from `default` - [NullCache.decr](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.decr.html): Return `default - delta`. See `incr()` - [NullCache.delete](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.delete.html): False, or with `invalidate=`, delete the key from that cache and return its result - [NullCache.__delitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__delitem__.html): Raise `KeyError`, or with `invalidate=`, delete the key from that cache - [NullCache.pop](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.pop.html): Return `default`. With `invalidate=`, also delete the key from that cache - [NullCache.clear](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.clear.html): 0, or with `invalidate=`, clear that cache (passing `timeout` on) and return its count - [NullCache.iterkeys](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.iterkeys.html): Yield nothing, or with `invalidate=`, that cache's keys, so list-then-delete still works - [NullCache.transact](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.transact.html): A no-op context manager that yields this `NullCache` - [NullCache.expire](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.expire.html): Always 0 - [NullCache.cull](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.cull.html): Always 0 - [NullCache.close](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.close.html): Do nothing. An `invalidate=` cache is never closed: it belongs to whoever created it - [NullCache.__enter__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__enter__.html): Return the cache, for `with NullCache() as cache:` - [NullCache.__exit__](https://mkennedy.codes/docs/diskcache-oxide/reference/NullCache.__exit__.html): Do nothing, as `close()` does #### CacheLike Methods > Methods for the CacheLike class - [CacheLike.directory](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.directory.html): The cache directory (None for a `NullCache` created without one) - [CacheLike.timeout](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.timeout.html): Seconds a write waits for another process's lock before raising `Timeout` - [CacheLike.size_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.size_limit.html): The disk budget in bytes - [CacheLike.cull_limit](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.cull_limit.html): The most entries one `set()` evicts when over `size_limit` - [CacheLike.enabled](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.enabled.html): True if caching is on (`Cache`), False if it's off (`NullCache`) - [CacheLike.get](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.get.html): Return the value for `key`, or `default` if it's missing or expired - [CacheLike.set](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.set.html): Store `value` under `key`, with an optional expiry in seconds - [CacheLike.add](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.add.html): Store `value` only if `key` is missing or expired. True if it was stored - [CacheLike.delete](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.delete.html): Remove `key`. True if a live entry was removed - [CacheLike.pop](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.pop.html): Remove `key` and return its value, or `default` - [CacheLike.touch](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.touch.html): Change an existing entry's expiry. True if the entry existed - [CacheLike.incr](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.incr.html): Add `delta` to the number under `key`, atomically, and return the result - [CacheLike.decr](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.decr.html): Subtract `delta` from the number under `key`, atomically, and return the result - [CacheLike.iterkeys](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.iterkeys.html): Iterate over keys in sorted order, optionally only those starting with `prefix` - [CacheLike.expire](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.expire.html): Remove every expired entry. Returns how many were removed - [CacheLike.clear](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.clear.html): Remove every entry that existed when the call started. Returns how many - [CacheLike.cull](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.cull.html): Remove expired entries, then evict until under `size_limit`. Returns how many - [CacheLike.volume](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.volume.html): The size on disk in bytes - [CacheLike.checkpoint](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.checkpoint.html): Empty the write-ahead log. True if it was reset, False if other processes kept it busy - [CacheLike.close](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.close.html): Close this handle and return its connections - [CacheLike.__getitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__getitem__.html): `cache[key]`: the value, or `KeyError` if it's missing or expired - [CacheLike.__setitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__setitem__.html): `cache[key] = value`: store a value that never expires - [CacheLike.__delitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__delitem__.html): `del cache[key]`: remove the entry, or raise `KeyError` - [CacheLike.__contains__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__contains__.html): `key in cache`: True if the key holds a live value - [CacheLike.__len__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__len__.html): The number of entries - [CacheLike.__bool__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__bool__.html): True if caching is on, so `if cache:` reads naturally - [CacheLike.__iter__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__iter__.html): Iterate over every key once. A `Cache` yields them in insertion order - [CacheLike.__enter__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__enter__.html): Return the cache, for use in a `with` block - [CacheLike.__exit__](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheLike.__exit__.html): Close the cache #### Caches > A registry of named caches under one base directory. - [Caches](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.html): A registry of named caches under one base directory - [CacheStats](https://mkennedy.codes/docs/diskcache-oxide/reference/CacheStats.html): One cache's numbers, for an admin page. `error` says why it couldn't be read, if it couldn't #### Caches Methods > Methods for the Caches class - [Caches.__repr__](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.__repr__.html): Shows the base directory and the registered names - [Caches.register](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.register.html): Register a cache. Nothing opens until its first lookup - [Caches.__contains__](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.__contains__.html): Whether `name` is registered - [Caches.__iter__](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.__iter__.html): The registered names, in registration order - [Caches.__len__](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.__len__.html): How many caches are registered - [Caches.directory](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.directory.html): Where the named cache lives - [Caches.__getitem__](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.__getitem__.html): The named plain cache: opened on first use, then the same object every time - [Caches.fanout](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.fanout.html): The named sharded cache (one registered with `shards=`), looked up as `caches[name]` is - [Caches.disable](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.disable.html): Later lookups of these caches return `NullCache(invalidate=real)` - [Caches.enable](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.enable.html): Later lookups of these caches return the real cache again - [Caches.enabled](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.enabled.html): Whether lookups of this cache return the real one (it may still fail to open) - [Caches.stats](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.stats.html): Count and volume for every registered cache, opening each one. Never raises for a cache - [Caches.clear](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.clear.html): Clear the real cache, even while it's disabled. Returns how many entries were removed - [Caches.expire_all](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.expire_all.html): Remove expired entries from every cache. Returns how many each removed, or None for a - [Caches.close_all](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.close_all.html): Close every opened cache and forget it; a later lookup opens it again - [Caches.__enter__](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.__enter__.html): Return the registry, for `with Caches(...) as caches:` - [Caches.__exit__](https://mkennedy.codes/docs/diskcache-oxide/reference/Caches.__exit__.html): Close every opened cache, as `close_all()` does #### Errors > Exceptions raised by cache operations. - [Timeout](https://mkennedy.codes/docs/diskcache-oxide/reference/Timeout.html): A lock stayed held, or a fork stayed pending, for longer than the cache's timeout - [TransactionBusy](https://mkennedy.codes/docs/diskcache-oxide/reference/TransactionBusy.html): A thread holding one cache's transaction couldn't begin another's, because another thread holds its write - [UnsafeValueError](https://mkennedy.codes/docs/diskcache-oxide/reference/UnsafeValueError.html): A pickle=False cache read a value that was stored with pickle - [CorruptValueError](https://mkennedy.codes/docs/diskcache-oxide/reference/CorruptValueError.html): A stored value couldn't be decoded: an unknown mode, or bytes that don't parse - [ForeignValueError](https://mkennedy.codes/docs/diskcache-oxide/reference/ForeignValueError.html): A stored value this build can't read but another might: an unknown mode, tag or extension (a newer version wrote - [FormatMismatchError](https://mkennedy.codes/docs/diskcache-oxide/reference/FormatMismatchError.html): The cache directory holds a database in a format this version doesn't support - [LayoutMismatchError](https://mkennedy.codes/docs/diskcache-oxide/reference/LayoutMismatchError.html): The directory's layout doesn't match how it was opened: a plain `Cache` on a `FanoutCache` root or shard, a #### SQLite and System > Information about the bundled SQLite and environment. - [sqlite_version](https://mkennedy.codes/docs/diskcache-oxide/reference/sqlite_version.html): The SQLite version reported at runtime by `sqlite3_libversion()` - [sqlite_compile_options](https://mkennedy.codes/docs/diskcache-oxide/reference/sqlite_compile_options.html): The compile-time options of the linked SQLite (`PRAGMA compile_options`) - [BUNDLED_SQLITE_VERSION](https://mkennedy.codes/docs/diskcache-oxide/reference/BUNDLED_SQLITE_VERSION.html): The SQLite version compiled into this build, as a string ### User Guide #### Get started - [New to caching? Start here](https://mkennedy.codes/docs/diskcache-oxide/user-guide/new-to-caching.html): What a cache is, why it's worth it, the words people use, and the two famously hard problems: invalidation and naming things - [Getting started](https://mkennedy.codes/docs/diskcache-oxide/user-guide/getting-started.html): Install diskcache-oxide, open a cache, store and read values, expiry, atomic counters and claims, eviction, timeouts, durable=True and a clean shutdown - [Switching from python-diskcache](https://mkennedy.codes/docs/diskcache-oxide/user-guide/switching-from-diskcache.html): The one-line switch from python-diskcache, and everything you might notice afterwards - [Errors and what to do about them](https://mkennedy.codes/docs/diskcache-oxide/user-guide/errors.html): Every exception diskcache-oxide raises, what it means, and what to do about it - [Vision and roadmap](https://mkennedy.codes/docs/diskcache-oxide/user-guide/roadmap.html): The vision in three stages, what exists today, what's next, and the non-goals #### Core Features - [Serialization](https://mkennedy.codes/docs/diskcache-oxide/user-guide/serialization.html): msgpack and JSON with exact type tags, registering your own types, and why pickle is off by default - [NullCache](https://mkennedy.codes/docs/diskcache-oxide/user-guide/null-cache.html): Caching switched off without changing call sites: NullCache, the CacheLike protocol, and keeping invalidations flowing while it's off - [Caches: named caches](https://mkennedy.codes/docs/diskcache-oxide/user-guide/caches.html): A registry of named caches under one base directory: each opens on first use, a NullCache stands in while one can't open, any can be switched off by name, and an admin page gets counts and sizes - [FanoutCache: sharded caches](https://mkennedy.codes/docs/diskcache-oxide/user-guide/fanoutcache.html): A cache sharded over several SQLite databases, so many writing processes stop queueing on one write lock, and when a plain Cache is the better choice - [Transactions](https://mkennedy.codes/docs/diskcache-oxide/user-guide/transactions.html): transact(): several writes that commit together or not at all, with TransactionBusy, TransactionAborted and retry - [Concurrency and forks](https://mkennedy.codes/docs/diskcache-oxide/user-guide/concurrency-and-forks.html): Threads, worker processes, pre-forking servers and free-threaded Python sharing one cache, and the fork barrier that keeps a child from inheriting half a transaction - [Storage and WAL](https://mkennedy.codes/docs/diskcache-oxide/user-guide/storage-and-wal.html): What's in the cache directory, how memory and disk stay bounded, and the write-ahead log and checkpoint() #### Background & Reference - [Performance](https://mkennedy.codes/docs/diskcache-oxide/user-guide/performance.html): The measured numbers against the defunct python-diskcache, where the speed comes from, the known slow spots and what's next - [Divergences from python-diskcache](https://mkennedy.codes/docs/diskcache-oxide/user-guide/divergences.html): Every deliberate difference from python-diskcache 5.6.3, with the reason and the test that records it ### Recipes - [Using the cache from asyncio](https://mkennedy.codes/docs/diskcache-oxide/recipes/asyncio.html): Read inline, write off the loop, and keep transactions on one thread: the three rules for FastAPI, Starlette, aiohttp and friends until AsyncCache lands - [Caching expensive calls](https://mkennedy.codes/docs/diskcache-oxide/recipes/caching-expensive-calls.html): The cache-aside pattern, and a decorator that caches any function's results - [Caching responses from other services](https://mkennedy.codes/docs/diskcache-oxide/recipes/caching-http-responses.html): Cache what an upstream API returns, honor its max-age, revalidate with ETags, and keep serving the last good answer when it's down - [Counting things](https://mkennedy.codes/docs/diskcache-oxide/recipes/counters.html): View counts, download totals and usage quotas with incr() and decr(), shared by every worker and flushed to the database without losing a count - [Storing your own types](https://mkennedy.codes/docs/diskcache-oxide/recipes/custom-types.html): UUIDs, enums, timedeltas, Paths, Pydantic models and dataclasses in the cache with register_type(), and no pickle - [Invalidating groups of keys](https://mkennedy.codes/docs/diskcache-oxide/recipes/invalidating-groups.html): Clear everything cached for one user or one object, by key prefix or by generation number - [Rate limiting](https://mkennedy.codes/docs/diskcache-oxide/recipes/rate-limiting.html): Fixed-window request limits shared by every worker on the machine, with add() and incr() - [Running a job once across workers](https://mkennedy.codes/docs/diskcache-oxide/recipes/run-once.html): Use add() to make sure only one worker process runs a scheduled job - [Server-side sessions](https://mkennedy.codes/docs/diskcache-oxide/recipes/sessions.html): Sessions every worker can read, with a sliding idle timeout from touch(), an absolute lifetime, and log-out-everywhere by key prefix - [Single-use keys](https://mkennedy.codes/docs/diskcache-oxide/recipes/single-use-keys.html): One-time codes, reset links and idempotency keys: pop() hands a value to exactly one caller, and add() accepts a key exactly once - [Serving stale values while refreshing](https://mkennedy.codes/docs/diskcache-oxide/recipes/stale-while-revalidate.html): Give an entry a freshness deadline shorter than its expiry, so readers never wait for a recompute and only one worker does it - [Testing code that uses a cache](https://mkennedy.codes/docs/diskcache-oxide/recipes/testing.html): pytest fixtures for a real cache, a NullCache, and a fake clock for testing expiry - [Sharing a cache across web workers](https://mkennedy.codes/docs/diskcache-oxide/recipes/web-workers.html): Directory, startup, request-path timeouts and shutdown for gunicorn, uvicorn, FastAPI, Flask, Django and Celery ### Agent Skill and Full Context - [Agent Skill (SKILL.md)](https://mkennedy.codes/docs/diskcache-oxide/skill.md): Compact guide, decision table, gotchas and examples for AI coding agents - [Full Documentation (llms-full.txt)](https://mkennedy.codes/docs/diskcache-oxide/llms-full.txt): Complete API reference and User Guide in a single file