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.

Search Document