In-memory key-value namespaces backed by SuperCache ETS partitions.
Works transparently in both local and distributed modes — the
mode is determined by the :cluster option passed to SuperCache.start!/1.
Multiple independent namespaces coexist using different kv_name values.
ETS table type support
KeyValue adapts its behavior based on the configured :table_type:
| Operation | :set / :ordered_set | :bag / :duplicate_bag |
|---|---|---|
add/3 | Atomic upsert (update or insert) | Insert (duplicates allowed) |
get/3 | Single value or default | Most recent value or default |
get_all/3 | List with at most one element | All values for the key |
update/3 | Atomic via update_element | Delete-all + insert (not atomic) |
update/4 | Best-effort read-modify-write | Best-effort read-modify-write |
increment/4 | Atomic via update_counter | Not supported (raises) |
replace/3 | Same as update/3 | Delete-all + insert |
Atomic operations
update/3— atomically set a value using:ets.update_element/3,4(:set/:ordered_setonly). If the key does not exist, a new record is inserted (upsert semantics).increment/4— atomically increment a counter using:ets.update_counter/3,4(:set/:ordered_setonly).add/3on:set/:ordered_settables usesupdate_elementwith a default for true atomic upsert semantics in:async/:syncreplication mode.
Read modes (distributed)
Pass read_mode: :primary or read_mode: :quorum when you need to read
your own writes from any node.
Example
alias SuperCache.KeyValue
# Works identically in local and distributed mode
KeyValue.add("session", :user_id, 42)
KeyValue.get("session", :user_id) # => 42
KeyValue.keys("session") # => [:user_id]
KeyValue.remove("session", :user_id)
KeyValue.remove_all("session")
# Atomic operations (:set / :ordered_set tables)
KeyValue.update("counters", :hits, 1) # => :ok
KeyValue.increment("counters", :hits, 0, 1) # => 2
# Bag table support
KeyValue.get_all("tags", :elixir) # => [1, 2] (all values)
KeyValue.replace("tags", :elixir, 3) # => :ok (replace all)
Summary
Functions
Add or update a key-value pair.
Add multiple key-value pairs in a single batch operation.
Get the value for key, returning default if not found.
Get all values for key as a list.
Atomically increment a counter field.
Remove multiple keys in a single batch operation.
Replace all values for key with a single value.
Atomically set the value for key (upsert semantics).
Update the value for key using a function.
Functions
Add or update a key-value pair.
For :set/:ordered_set tables, this is an atomic upsert — if the key
exists, the value is updated in-place via :ets.update_element; if not,
a new record is inserted.
For :bag/:duplicate_bag tables, this inserts a new record. Duplicate
keys are allowed. Use replace/3 to atomically replace all values for a key.
Returns true.
Add multiple key-value pairs in a single batch operation.
Groups entries by partition and sends each group in a single :erpc call
in distributed mode, dramatically reducing network overhead.
Example
KeyValue.add_batch("session", [
{:user_1, %{name: "Alice"}},
{:user_2, %{name: "Bob"}}
])
@spec count( any(), keyword() ) :: non_neg_integer()
Get the value for key, returning default if not found.
For :set/:ordered_set tables, returns the single value or default.
For :bag/:duplicate_bag tables, returns the most recently inserted
value. Use get_all/3 to retrieve all values for a key.
Get all values for key as a list.
Useful for :bag/:duplicate_bag tables where multiple records can share
the same key. For :set/:ordered_set tables, returns a list with at most
one element.
Atomically increment a counter field.
The value at key must be a number. If the key doesn't exist, default
is used as the initial value before incrementing by step.
Only supported for :set/:ordered_set tables. Raises ArgumentError
for :bag/:duplicate_bag tables — use :set or :ordered_set for
atomic counter operations.
Returns the new counter value.
@spec remove_all(any()) :: :ok
Remove multiple keys in a single batch operation.
Groups entries by partition and sends each group in a single :erpc call
in distributed mode.
Example
KeyValue.remove_batch("session", [:user_1, :user_2])
Replace all values for key with a single value.
For :bag/:duplicate_bag tables, this deletes all existing records for
the key and inserts a single new record. For :set/:ordered_set tables,
this is equivalent to update/3 (atomic upsert).
Note: For :bag/:duplicate_bag tables, this operation is not atomic —
a concurrent reader may observe the key as missing between the delete and
the insert.
Returns :ok.
Atomically set the value for key (upsert semantics).
For :set/:ordered_set tables, uses :ets.update_element/3,4 which is
guaranteed atomic at the ETS level. If the key doesn't exist, a new record
is inserted.
For :bag/:duplicate_bag tables, deletes all existing records for the key
and inserts a new one. This is not atomic — a concurrent reader may
observe the key as missing between the delete and the insert. Prefer
:set or :ordered_set tables when atomic updates are required.
Returns :ok.
Update the value for key using a function.
fun receives the current value (or default if the key doesn't exist)
and must return the new value.
Warning: This is a read-modify-write operation and is not atomic.
A concurrent writer may modify the value between the read and the write,
causing a lost update. For atomic value updates, use update/3. For
atomic counter increments, use increment/4.
In distributed mode, fun is serialized and sent to the primary node via
:erpc. The function must not capture node-specific resources (PIDs, etc.).
Returns the new value.