RoTTL — Rotating TTL Data Structures
RoTTL provides memory-efficient rotating sets, dicts, and Bloom filters with approximate TTL-based eviction.
Rather than maintaining per-item expiry timestamps, the TTL window is divided into a fixed number of rotating buckets — expired buckets are evicted as a whole, trading per-item precision for significantly lower memory usage and faster writes, at the cost of sequential bucket scans.
Installation
pip install rottl
The only dependency is rbloom. If you encounter installation issues, refer to their documentation.
Quickstart
RotatingTTLSet— exact membership tracking backed by native Pythonsetbuckets.
from rottl import RotatingTTLSet
seen_ids = RotatingTTLSet(
ttl=24 * 60 * 60, num_buckets=6, bucket_capacity=1_000_000
)
seen_ids.add("user_42")
print("user_42" in seen_ids) # True
RotatingTTLDict— key-value storage backed by native Pythondictbuckets.
from rottl import RotatingTTLDict
response_cache = RotatingTTLDict(
ttl=60 * 60, num_buckets=4, bucket_capacity=10_000
)
response_cache["GET /api/status"] = {"ok": True}
print(response_cache.get("GET /api/status")) # {'ok': True}
RotatingTTLBloom— probabilistic membership tracking backed byrbloom.Bloombuckets.
from rottl import RotatingTTLBloom
visited_urls = RotatingTTLBloom(
ttl=7 * 24 * 60 * 60, num_buckets=7, bucket_capacity=10_000_000, bucket_fpr=0.001
)
visited_urls.add("https://example.com")
print("https://example.com" in visited_urls) # True
All three structures rotate automatically based on time and capacity, though capacity tracking differs between implementations:
RotatingTTLSetandRotatingTTLDict: Capacity is checked inline on every insertion via an $O(1)$len()call.RotatingTTLBloom: Estimating the number of unique inserted items requires inspecting filter occupancy by counting set bits — an $O(M)$ operation. To keep the hot path $O(1)$ for the vast majority of insertions, capacity is managed via an amortized countdown that defers the check.
When to use RoTTL
- Approximate TTL is acceptable. Expiry happens at bucket boundaries, not per item. Under normal load (no capacity-based eviction), items live between
ttl - (ttl / num_buckets)andttlseconds. Capacity pressure can cause earlier eviction. Settingbucket_ttl_jitter_ratiofurther reduces the minimum, but helps avoid synchronized eviction spikes across instances. - Memory-constrained environments. RoTTL's bucket-level eviction avoids per-item bookkeeping, keeping structure overhead proportional to bucket count rather than item count.
RotatingTTLDictuses roughly 3–4× less memory thancachetools.TTLCache.
- Write-heavy workloads. RoTTL's write path is lightweight — no per-item expiry metadata is maintained on insertion.
RotatingTTLDictis 6–15× faster thancachetools.TTLCacheon insertions (varies by fast-reject usage and rotation pressure).
- Lookup performance scales with configuration. Lookups scan up to
num_bucketsbuckets, so with a small bucket count the overhead is negligible. With a large bucket count, hit cost depends on which bucket the item is found in, and miss cost grows linearly.RotatingTTLSetandRotatingTTLDict's history fast-reject option makes most miss latency independent ofnum_buckets, at the cost of slower rotations.
Advanced Usage
Because eviction happens at the bucket level, a rotation event drops all items in that bucket at
once. In deployments with multiple instances — such as Kubernetes pods — all instances initialized
around the same time will rotate in lockstep, causing simultaneous cache drops across the fleet.
bucket_ttl_jitter_ratio addresses this by randomly shortening each bucket's TTL by up to
ratio * bucket_ttl seconds on rotation, spreading eviction events out over time.
RotatingTTLSet and RotatingTTLDict support an optional history fast-reject mode, which
maintains an auxiliary Bloom filter over all non-expired historical buckets. This allows most
negative lookups to be rejected without scanning the full bucket deque, at the cost of filter
rebuild on each rotation.
Metadata
Release files for rottl 0.0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rottl-0.0.5.tar.gz | 12.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rottl-0.0.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.9 kB
Release files / rottl-0.0.5.tar.gz
| Download URL | rottl-0.0.5.tar.gz |
|---|---|
| Size | 12.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a8b7ac843ca8be91235263c83b2cecdffa8773465b267a86c1509dfb4d692fd9
|
|
BLAKE2b-256 checksum How to use checksums |
585bff52594a99669cf05485b47e616def51f24182b64b50e083b7c5889a8ba4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 17, 2026.
Transparency logRelease files / rottl-0.0.5-py3-none-any.whl
| Download URL | rottl-0.0.5-py3-none-any.whl |
|---|---|
| Size | 11.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0fbf5588d7d4506a4aa593d4a4e5946cedc078cd9766586a2dad3934f050d167
|
|
BLAKE2b-256 checksum How to use checksums |
767adabe9e810979da30254f10b7ca7e43eb223765601e600a2ff29e5cddd9cd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 17, 2026.
Transparency log