Skip to content

Releases: toloco/warp_cache

0.7.0

13 Apr 17:08
Immutable release. Only release title and notes can be modified.
40e55c2

Choose a tag to compare

Changelog

Improve typing coverage with ParamSpec + Protocol (#27)

Type checkers now see cache_info() and cache_clear() on decorated functions, while preserving the original call signature:

  • Added CachedCallable[P, R] protocol using ParamSpec — decorated functions retain their arg/return types
  • Added BaseCacheInfo protocol for the common cache info interface (hits, misses, max_size, current_size)
  • cache() return type updated from Callable[[F], F] to Callable[[Callable[P, R]], CachedCallable[P, R]]
  • Added _probe to _warp_cache_rs.pyi stub
  • typing_extensions dependency added for Python 3.9 only

Document key serialization behavior (#28)

Added "Key serialization behavior" section to docs/usage.md:

  • How cache keys are formed from *args/**kwargs (sorted kwargs for determinism)
  • Memory backend: Python objects, hash(), single-process
  • Shared backend: fast-path binary format for primitives, pickle fallback
  • Cross-process determinism: fixed-seed ahash, immune to PYTHONHASHSEED

0.6.0

08 Apr 12:55
Immutable release. Only release title and notes can be modified.
04aeee4

Choose a tag to compare

Changelog

Async single-flight coalescing — dogpile prevention (#25)

When multiple async coroutines miss the cache for the same key concurrently, only one computes the result — the rest await and reuse it. Works for both memory and shared backends, default on for all async cached functions.

  • Error recovery: if the computing coroutine fails, a waiter automatically becomes the new leader
  • Cancellation safe: cancelled leaders don't block waiters
  • Zero Rust changes — implemented via asyncio.Event in the Python async wrapper

Fix async caching of None return values (#26)

Previously, async-wrapped functions returning None were never cached because get() couldn't distinguish "cache miss" from "cached None" (PyO3's Option<Py<PyAny>> conflates both to Python None).

  • Added _probe() method to both backends returning (hit: bool, value)
  • AsyncCachedFunction now uses _probe() instead of get()
  • get() unchanged for backwards compatibility

Housekeeping

  • Refactored README (#24)
  • Removed unused code and tightened types (#23)

0.5.0

06 Mar 10:51
a40a29d

Choose a tag to compare

Changelog

Replace LRU/MRU/FIFO/LFU with SIEVE eviction (#20)

The biggest change — unified eviction to SIEVE across both backends:

  • Removed src/strategies/ module entirely (~540 lines deleted): LRU, MRU, FIFO, LFU all gone
  • Removed Strategy enum and strategy= parameter from the Python API
  • Shared memory backend: reads are now fully lock-free (visited bit set via idempotent store, no write lock on hits)
  • Layout VERSION bumped 2 → 3 (forces recreation of old mmap files)
  • Performance gains (shared backend):
    • Single-process: 7.8M → 8.9M ops/s
    • Multi-process 4 procs: 3.1M → 7.7M ops/s (2.5x)
    • Multi-process 8 procs: 1.9M → 6.5M ops/s (3.4x)
    • Hit rate: 64.9% → 72.7% (scan-resistant eviction)
  • Updated all docs, examples, benchmarks, and llms.txt

PassthroughHasher, BorrowedArgs, GilCell, free-threaded Python support (#21)

Major performance optimization of the in-process memory backend:

  • PassthroughHasher: feeds Python's precomputed hash directly to hashbrown (skips foldhash re-hash, ~1-2ns saved per lookup)
  • BorrowedArgs: zero-alloc borrowed key for hit-path lookups via hashbrown's Equivalent trait — no CacheKey allocation or refcount churn on cache hits
  • GilCell: zero-cost UnsafeCell wrapper under GIL-enabled Python, replaced by parking_lot::RwLock under #[cfg(Py_GIL_DISABLED)] for free-threaded Python support
  • Sharded HashMap: per-shard locking enables true parallel reads under free-threaded Python

Bump PyO3 0.28.1 → 0.28.2 (#19)

  • Routine dependency update via Dependabot

Add Python 3.14 support (#22)

  • Added 3.14 to CI test matrix, publish workflow, classifiers, and benchmark defaults

0.2.1

20 Feb 12:47
28d6d8c

Choose a tag to compare

Change log:

  • Add support to Python 3.9

0.2.0

17 Feb 20:41
8888a80

Choose a tag to compare

Bug Fixes

  • Fix cross-process hashing for string/bytes keys (CRITICAL): The shared
    memory backend previously computed key hashes from Python's hash(), which is
    randomized per process (PYTHONHASHSEED) for str and bytes types. This
    caused cross-process cache lookups to silently miss — breaking the core value
    proposition of the shared backend. Key hashes are now computed from the
    deterministic serialized bytes using ahash with fixed seeds.

  • Fix oversize early-exit check: The __call__ path in
    SharedCachedFunction compared key_bytes.len() against max_size (the
    maximum entry count), which almost never triggered. The check now correctly
    delegates to is_oversize() only.

Improvements

  • Document approximate eviction ordering: Added doc comments to the internal
    ACCESS_LOG_CAPACITY constant and a Note: block to the cache() decorator
    docstring explaining that eviction ordering (LRU, MRU, LFU) is approximate
    under sustained hit-only workloads due to batched ordering updates.

  • Add PEP 561 typing support: Added py.typed marker and
    _warp_cache_rs.pyi type stubs for CacheInfo, SharedCacheInfo,
    CachedFunction, and SharedCachedFunction. Type checkers (mypy, pyright)
    can now understand the Rust extension's API.

Tests

  • Add cross-process string key test: New
    test_cross_process_str_key_different_hashseed spawns a subprocess with an
    explicit PYTHONHASHSEED=12345 to verify that string keys written by one
    process are correctly found by another — directly validating the hashing fix.

Other

  • Fix repository URL in pyproject.toml (tolotoloco).
  • Add ahash = "0.8" dependency (Unix targets only).

0.1.3

17 Feb 11:10

Choose a tag to compare

Add examples, lru_cache partial and contributing material

0.1.2

16 Feb 15:02

Choose a tag to compare

0.1.2

0.1.0

16 Feb 14:47

Choose a tag to compare

0.1.0