LWWMap

@Serializable
class LWWMap<K, V> : Quilted<LWWMap<K, V>>

A map from K to last-writer-wins values V: per-key LWWRegisters composed under union-merge of keys. Each set (or remove — a tombstone write) tags one key with (timestamp, replicaId); merge picks the per-key max tag.

Suited to settings, ready-toggles, and similar small key→latest-value state where surfacing concurrent edits (a la MVRegister) is unwanted.

Immutable, and every mutator returns the change rather than a new map: set and remove hand back a Patch holding just the one cell they wrote, which is what belongs on the wire. piece is the per-key merge — it absorbs a patch, and it is also how a caller who wants the resulting whole map gets one: map.piece(map.set(replica, timestamp, key, value)).

Clock-skew warning. Wall-clock timestamps work only when clocks are well-synchronized across all replicas. NTP-class drift will cause surprising silent drops: a write with a lagging timestamp loses to an older write from a faster clock. For correctness under arbitrary clock skew, pair this map with a Hybrid Logical Clock above this layer.

Samples

val a = ReplicaId("A")
val b = ReplicaId("B")

// Two peers have converged on a settings map.
var alpha = LWWMap.empty<String, String>()
    .piece { it.set(a, timestamp = 1L, key = "lang", value = "en") }
    .piece { it.set(a, timestamp = 2L, key = "tz", value = "UTC") }
    .piece { it.set(a, timestamp = 3L, key = "theme", value = "dark") }
var bravo = alpha

// B changes one setting and puts only that cell on the wire. The frame is the same size
// whether the map holds three keys or ten thousand, and the other keys are untouched.
val change = alpha.set(b, timestamp = 4L, key = "theme", value = "light")
alpha = alpha.piece(change)
bravo = bravo.piece(change)
check(alpha == bravo)
check(alpha["theme"] == "light")
check(alpha["lang"] == "en")

// Per key the higher (timestamp, replica) tag wins, and a remove is a write like any other,
// so its delta is a one-cell tombstone map…
val forget = bravo.remove(b, timestamp = 5L, key = "lang")
check(alpha.piece(forget)["lang"] == null)

// …and never an empty map, which is the lattice identity and carries no removal at all.
check(alpha.piece(LWWMap.empty<String, String>())["lang"] == "en")

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard
val entries: Map<K, V>

All currently-set entries with their values.

Functions

Link copied to clipboard
open fun causalDots(): Set<Dot>

The causal Dots this state has delivered — (author, author-seq) per op.

Link copied to clipboard

The per-author high-water of dots this state delivered and has since compacted away without retaining their identities.

Link copied to clipboard
open operator override fun equals(other: Any?): Boolean
Link copied to clipboard
operator fun get(key: K): V?

The current value for key, or null if unset.

Link copied to clipboard
open override fun hashCode(): Int
Link copied to clipboard
open override fun piece(other: LWWMap<K, V>): LWWMap<K, V>

The join: per-key max-tag of the underlying registers.

Link copied to clipboard
fun remove(replica: ReplicaId, timestamp: Long, key: K): Patch<LWWMap<K, V>>

Remove key tagged with (timestamp, replica) — a last-writer-wins tombstone (LWWRegister.unset) that competes under merge exactly like a set: a remove at a later tag beats an earlier set, and a set at a later tag revives the key, with the same deterministic (timestamp, replicaId) tie-break. Removed keys disappear from get and entries. Returns the change: one key's tombstone cell, not the whole map.

Link copied to clipboard
fun set(replica: ReplicaId, timestamp: Long, key: K, value: V): Patch<LWWMap<K, V>>

Write value for key tagged with (timestamp, replica) — and return the change, one key's cell, rather than the whole map.

Link copied to clipboard
open override fun toString(): String