CounterEx.Backend.Counters (CounterEx v0.2.0)
View SourceCounters-based backend for CounterEx using Erlang's :counters module.
This backend uses Erlang's :counters for write-optimized atomic counter operations:
- Fixed capacity: Pre-allocated array of atomic counters
- Write-optimized: Optimized for heavy concurrent writes
- No GC pressure: Counters live outside the process heap
- Key mapping: Uses ETS to map keys to array indices
Characteristics
- Performance: Optimized for write-heavy workloads
- Memory: Fixed at initialization
- Limitations: Fixed number of counters per namespace (default: 1000)
Configuration
Options:
:capacity- Max counters per namespace (default: 1000):write_concurrency- Enable write concurrency optimization (default: true)
When to Use
Use this backend when:
- You have write-heavy workloads with many concurrent writers
- You have a bounded, known set of counters
- You can pre-allocate capacity
- You need predictable memory usage
Atomics vs Counters
- Atomics: Better for read-heavy or mixed workloads
- Counters: Better for write-heavy workloads with many concurrent writers
Limitations
- Cannot create more counters than the configured capacity
- Deleting a counter doesn't free its slot (reusable after explicit delete)
- Each namespace requires separate counter array
- Counters do not support compare-and-swap natively (emulated with get+put)
Example
# Initialize with capacity for 5,000 counters
{:ok, state} = CounterEx.Backend.Counters.init(capacity: 5_000)
{:ok, 1} = CounterEx.Backend.Counters.inc(state, :default, :requests, 1, 0)
{:ok, 1} = CounterEx.Backend.Counters.get(state, :default, :requests)
Summary
Types
@type t() :: %CounterEx.Backend.Counters{ capacity: pos_integer(), metadata: :ets.tid(), registry: :ets.tid(), write_concurrency: boolean() }