lattice_registers/lww_register
A last-writer-wins register (LWW-Register) CRDT.
Stores a single value with an associated timestamp. When two replicas
conflict, the value with the strictly higher timestamp wins. On equal
timestamps, the replica with the lexicographically greater replica_id
wins, ensuring fully commutative merge.
Example
import lattice_core/replica_id
import lattice_registers/lww_register
let a = lww_register.new("hello", 1, replica_id.new("node-a"))
let b = lww_register.new("world", 2, replica_id.new("node-b"))
let merged = lww_register.merge(a, b)
lww_register.value(merged) // -> "world"
Types
A register holding a single value alongside its write timestamp and replica identifier.
value is the stored payload, timestamp is an integer logical clock
used to resolve conflicts, and replica_id provides a deterministic
tie-breaker when timestamps are equal.
pub opaque type LWWRegister(a)
Values
pub fn from_json(
json_string: String,
) -> Result(LWWRegister(String), json.DecodeError)
Decode a LWWRegister(String) from a JSON string produced by to_json.
Supports both v1 (no replica_id, defaults to “”) and v2 (with replica_id)
envelopes. Returns Ok(LWWRegister(String)) on success, or
Error(json.DecodeError) if the input is not a valid LWW-Register JSON
envelope.
pub fn merge(
a: LWWRegister(a),
b: LWWRegister(a),
) -> LWWRegister(a)
Merge two LWW-Registers by returning the one with the higher timestamp.
When a.timestamp > b.timestamp, returns a. When b.timestamp > a.timestamp, returns b. On equal timestamps, the register whose
replica_id is lexicographically greater wins, providing a fully
commutative, associative, and idempotent merge.
pub fn new(
val: a,
timestamp: Int,
replica_id: replica_id.ReplicaId,
) -> LWWRegister(a)
Create a new LWW-Register with an initial value, timestamp, and replica ID.
timestamp should be a positive integer representing the logical time of
the write. Use a monotonically increasing source (e.g., wall-clock
milliseconds or a Lamport clock) so that later writes have higher values.
replica_id identifies the writing node and is used as a deterministic
tie-breaker when two registers have equal timestamps during merge.
pub fn set(
register: LWWRegister(a),
val: a,
timestamp: Int,
) -> LWWRegister(a)
Update the register if timestamp is strictly greater than the current one.
If timestamp > register.timestamp, replaces the stored value and
timestamp with the new ones. Otherwise returns the register unchanged.
This ensures only strictly newer writes are accepted.
The replica_id is preserved from the original register.
See set_with_delta for the delta-state variant that also returns a
small payload suitable for incremental sync (e.g. over websockets).
pub fn set_with_delta(
register: LWWRegister(a),
val: a,
timestamp: Int,
) -> #(LWWRegister(a), LWWRegister(a))
Set a value and return both the new state and a delta.
The returned delta is an LWWRegister carrying the write that was
actually accepted locally. When timestamp strictly exceeds the current
timestamp the delta carries the new (value, timestamp, replica_id);
otherwise the local set is a no-op and the delta carries the unchanged
register so that no rejected write can win on a remote replica.
Merging the delta into a remote via merge produces the same result as
merging the new local state, preserving convergence.
pub fn to_json(register: LWWRegister(String)) -> json.Json
Encode a LWWRegister(String) as a self-describing JSON value.
Produces an envelope with type, v (schema version = 2), and state.
Format: {"type": "lww_register", "v": 2, "state": {"value": "...", "timestamp": ..., "replica_id": "..."}}
Use from_json to decode the result back into a LWWRegister(String).
pub fn value(register: LWWRegister(a)) -> a
Return the current value of the register.
Provided for a uniform functional API since the type is opaque.