Min-Register (Monotone Low-Water Mark)
This page is part of the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at minregister.md, and llms.txt lists every page.tree.MinRegister<T>(key, orderKeySelector) -> MinRegisterAccessor<T>, merge
mode LatticeMergeMode.MinRegister.
Semantics
A Min-Register is the mirror image of the Max-Register: it keeps the smallest totally-ordered value ever written - a monotone low-water mark. A write advances the register only when the candidate beats the current value under the total order; concurrent active-active writes from different clusters converge on the single smallest value because the fold is a directional min over the total order, which is commutative, associative, and idempotent.
As with the Max-Register, you supply an orderKeySelector that produces an
order-preserving byte[] key for a value - its unsigned lexicographic byte
order must match the intended value order. The key travels on the wire alongside
the value so the receiver folds without needing your comparer.
Reach for it when a value only ever moves down: a min-seen latency floor, a first-seen timestamp, a lowest-price watermark. Its mirror is the Max-Register; for keeping concurrent values rather than the extreme, use the MV-Register.
Behaviour
Both clusters hold 37. Under the min order the smaller value is the higher state, so the join is the smaller write itself.
The fold keeps the smaller value under the total order, so it is commutative, associative, and idempotent.
sequenceDiagram
participant A as Cluster A
participant B as Cluster B
A->>A: Set(42)
B->>B: Set(37)
A-->>B: merge ships candidate 42
B-->>A: merge ships candidate 37
Note over A,B: fold keeps the smaller under the total order
Note over A,B: converged = 37 (min-wins)
Example
// The order key must be order-preserving: big-endian bytes of a non-negative reading.
var floor = tree.MinRegister<long>("service:api:latency-floor-ms", static v =>
{
var key = new byte[8];
System.Buffers.Binary.BinaryPrimitives.WriteInt64BigEndian(key, v);
return key;
});
// Two clusters report latencies concurrently; the register keeps the smaller.
await floor.SetAsync(42, cancellationToken);
await floor.SetAsync(37, cancellationToken);
long lowest = await floor.GetAsync(cancellationToken); // 37
// Before the first write GetAsync returns default(T) - 0 for a long - so ask
// HasValueAsync when "never written" must be told apart from a real 0.
bool written = await floor.HasValueAsync(cancellationToken);
See also: its high-water mirror Max-Register, the multi-value MV-Register, and the CRDT overview.