Grove.Register.LWWRegister (Grove v0.1.1)

View Source

A Last-Write-Wins Register (LWW-Register) CRDT.

Each update is tagged with a Lamport timestamp. On merge, the value with the highest timestamp wins. Ties are broken by comparing actor IDs.

Important

Uses Lamport timestamps (logical clocks), NOT wall-clock time. This ensures correctness even with clock skew between nodes.

Delta-State Support

This CRDT supports delta-state replication. Note that for LWWRegister, the delta is the full register state since merge needs all metadata. The delta buffer tracks whether any local changes have been made.

  • delta/1 - Returns the register state if modified, or empty state if not
  • reset_delta/1 - Clears the dirty flag after synchronization

Example

iex> reg = Grove.Register.LWWRegister.new(:node_a)
iex> reg = Grove.Register.LWWRegister.set(reg, "hello")
iex> Grove.Register.LWWRegister.value(reg)
"hello"

Summary

Functions

Returns the accumulated delta since the last reset.

Merges two LWW-Registers.

Creates a new LWW-Register for the given actor.

Resets the delta buffer after synchronization.

Sets the value of the register.

Sets the value with an explicit timestamp.

Returns the current timestamp.

Returns the current value of the register.

Types

actor()

@type actor() :: term()

t()

@type t() :: %Grove.Register.LWWRegister{
  actor: actor(),
  delta_dirty: boolean(),
  timestamp: non_neg_integer(),
  value: term()
}

Functions

delta(register)

@spec delta(t()) :: t()

Returns the accumulated delta since the last reset.

For LWWRegister, the delta is the full register state if any changes were made locally, or an empty register (timestamp 0) if not.

merge(reg1, reg2)

@spec merge(t(), t()) :: t()

Merges two LWW-Registers.

The value with the higher timestamp wins. Ties are broken by comparing actor IDs, then values (higher wins).

Note: The actor field represents the origin of the current value, not the replica doing the merge. This is essential for associativity.

new(actor)

@spec new(actor()) :: t()

Creates a new LWW-Register for the given actor.

reset_delta(register)

@spec reset_delta(t()) :: t()

Resets the delta buffer after synchronization.

Call this after sending the delta to other replicas.

set(register, value)

@spec set(t(), term()) :: t()

Sets the value of the register.

Automatically increments the timestamp.

set(register, value, timestamp)

@spec set(t(), term(), non_neg_integer()) :: t()

Sets the value with an explicit timestamp.

Use this when applying remote operations.

timestamp(lww_register)

@spec timestamp(t()) :: non_neg_integer()

Returns the current timestamp.

value(lww_register)

@spec value(t()) :: term()

Returns the current value of the register.