A high-throughput W-TinyLFU local cache adapter for Nebulex.
A Nebulex adapter implementing the Window TinyLFU (W-TinyLFU) cache admission policy — a port of Caffeine, the reference Java implementation. W-TinyLFU combines recency (LRU) and frequency (TinyLFU) to deliver near-optimal hit rates across mixed workloads while keeping the hot path lock-free.
Highlights:
- W-TinyLFU admission — a 4-bit Count-Min Sketch with periodic aging decides which entries are worth keeping. Outperforms plain LRU on most real workloads, especially scan-resistant access patterns.
- Lock-free hot path —
cache.get/1,cache.put/2, and friends hit ETS directly and append to a deduplicated buffer. No GenServer calls, no policy work blocking the caller. - Segmented LRU — three deques (Window → Probation → Protected) protect frequently-accessed entries while still admitting new arrivals.
- Bounded or unbounded — set
:max_sizefor managed eviction, or omit it for a plain ETS cache with zero eviction overhead. - TTL with on-demand expiration, queryable, observable, info, and stats support out of the box.
See the module documentation for a deeper look at the architecture, the admission/eviction flow, and tuning notes.
Add :nebulex_tiny_lfu to your list of dependencies in mix.exs:
def deps do
[
{:nebulex_tiny_lfu, "~> 3.0"},
{:telemetry, "~> 0.4 or ~> 1.0"}, # For observability/telemetry support
{:decorator, "~> 1.4"}, # For declarative caching
]
endThe :telemetry (observability and monitoring of cache operations) and
:decorator (declarative caching) dependencies are optional but highly
recommended for production use.
Define your cache:
defmodule MyApp.Cache do
use Nebulex.Cache,
otp_app: :my_app,
adapter: Nebulex.Adapters.TinyLFU
endConfigure it in config/config.exs:
config :my_app, MyApp.Cache,
max_size: 100_000Add it to your application's supervision tree:
def start(_type, _args) do
children = [
{MyApp.Cache, []},
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
endThen use the standard Nebulex.Cache API:
MyApp.Cache.put!("user:42", user)
MyApp.Cache.fetch!("user:42")
MyApp.Cache.delete!("user:42")See the online documentation for configuration options,
the :max_size eventual-consistency model, and the full architecture
walkthrough.
Since this adapter uses support modules and shared tests from Nebulex,
but the test folder is not included in the Hex dependency, the following
steps are required to run the tests.
First, set the environment variable NEBULEX_PATH to nebulex:
export NEBULEX_PATH=nebulex
Second, fetch the :nebulex dependency directly from GitHub:
mix nbx.setup
Third, fetch deps:
mix deps.get
Finally, run the tests:
mix test
Running tests with coverage:
mix coveralls.html
You will find the coverage report within cover/excoveralls.html.
The adapter ships with benchmarks based on benchee, located in benchmarks/.
To run a benchmark:
MIX_ENV=test mix run benchmarks/BENCH_TEST_FILE
Where BENCH_TEST_FILE can be any of:
frequency_sketch.exs— micro-benchmark for the Count-Min Sketch used by the admission filter.
Contributions to Nebulex are very welcome and appreciated!
Use the issue tracker for bug reports or feature requests. Open a pull request when you are ready to contribute.
When submitting a pull request you should not update the CHANGELOG.md, and you should make sure your changes are covered by tests — include unit tests alongside any new or changed code.
Before submitting a PR, run mix test.ci and make sure all checks pass.
Copyright (c) 2026 Carlos Andres Bolaños R.A.
nebulex_tiny_lfu source code is licensed under the
MIT License.