Crdt.Counter
crdt · API reference
PN-Counter CRDT extension built on vec node
Counter extension (cnt) - PN-Counter CRDT.
A PN-Counter (Positive-Negative Counter) is a CRDT that supports both increment and decrement operations. It's built on a vec node where:
- Even slots (0, 2, 4, ...) store positive counts per session
- Odd slots (1, 3, 5, ...) store negative counts per session Each session has two dedicated slots:
- Slot 2*(session_id mod 128): positive count
- Slot 2*(session_id mod 128) + 1: negative count The counter value is: sum(all positive slots) - sum(all negative slots)
This design ensures:
- Convergence: all replicas eventually agree on the value
- Commutativity: operations can be applied in any order
- Concurrent increments/decrements are preserved Usage:
let model = Model.create session_id in
let counter = Counter.create model in
Counter.increment counter;
Counter.increment ~by:5 counter;
Counter.decrement counter;
let v = Counter.value counter in (* 5 *)Types
type t = {
model : Model.t;
vec_node : Node.t;
}Counter handle wrapping a vec node
Session Slot Mapping
val positive_slot : int -> intGet the slot index for a session's positive count. Uses modular arithmetic to map sessions to slots 0-254 (even).
val negative_slot : int -> intGet the slot index for a session's negative count. Uses slots 1-255 (odd).
Creation
val create : Model.t -> tCreate a new counter. Creates a vec node in the model.
val of_node : Model.t -> Node.t -> tCreate a counter from an existing vec node. Use this when loading a counter from a decoded model.
val id : t -> Clock.timestampGet the vec node's timestamp ID
Reading
val get_slot_value : t -> int -> intGet the value stored in a slot, or 0 if not set
val value : t -> intCalculate the current counter value.
Sums all positive slots and subtracts all negative slots.
Modification
val set_slot : t -> int -> int -> unitSet a slot to a specific value, creating the con node
val increment : ?by:int -> t -> unitIncrement the counter by the given amount (default 1).
Uses the local session's positive slot.
val decrement : ?by:int -> t -> unitDecrement the counter by the given amount (default 1).
Uses the local session's negative slot.
val add : t -> int -> unitAdd to the counter (positive or negative).
Positive amounts use increment, negative use decrement.
val reset_local : t -> unitReset the counter for the local session.
Sets both positive and negative slots to 0. Does not affect other sessions' contributions.
Inspection
val slots : t -> (int * int) listGet the raw slot values as (slot_idx, value) pairs. Useful for debugging and serialization inspection.
val totals : t -> int * intGet positive and negative totals separately. Returns (positive_total, negative_total).
val session_count : t -> intGet the number of sessions that have contributed to this counter
Merging
val merge : t -> Node.t -> unitMerge another counter's vec node into this counter.
This applies the other counter's slots to this one using CRDT semantics (last-writer-wins per slot). Used during sync.