Rga

@Serializable
class Rga<V> : Quilted<Rga<V>> , OpLogCrdt<RgaId, V, RgaOp<V>>

A Replicated Growable Array (RGA): an op-based sequence CRDT for ordered collections such as chat messages or collaborative text.

How it fits Quilted. Unlike the delta-state types in this module, RGA's natural unit is an operation, not a state fragment. The "state" here is the full op-log: a set of RgaOps. piece is an idempotent union of two op-logs — that union satisfies the lattice laws (idempotent, commutative, associative) because the ops are uniquely identified and set-union has those properties. Any two replicas that have absorbed the same set of ops compute the identical sequence from toList, regardless of the order in which they absorbed them.

Concurrent-insert tiebreak. When two Insert(idA, _, p) and Insert(idB, _, p) share the same predecessor p, the larger id wins the immediately-after slot. With idA > idB the resulting list is … p A B ….

Tombstones. Removed elements remain in the op-log. This is deliberate: a future Insert(id, _, removedId) must still find the predecessor. GC of tombstones is performed by compact.

Lamport clock. Each replica tracks a local lamport counter. Minting a new op increments it and records the current maximum observed across all received ops.

Type Parameters

V

the element type. Must be serializable for wire transport.

Samples

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

val (rgaA, opA) = Rga.empty<String>().insertAt(a, 0, "Hello")
val (rgaB, opB) = Rga.empty<String>().insertAt(b, 0, "World")

// Both replicas absorb both ops.
val mergedByA = rgaA.apply(opB)
val mergedByB = rgaB.apply(opA)

// Convergence: both produce the same list regardless of delivery order.
check(mergedByA.toList() == mergedByB.toList())

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard

Per-author high-water of dots this replica has compacted away — every dot (r, s) with s <= compactedBelow[r] is permanently suppressed.

Link copied to clipboard

All ids that have been garbage-collected by any RgaOp.Compact in this op-log — the unbounded half of the compaction record, as against the O(authors) compactedBelow floor.

Link copied to clipboard

How many RgaOp.Compact ops this log retains.

Link copied to clipboard

This replica's current Lamport timestamp (max seen + 1 after any op).

Link copied to clipboard

How many operations this log holds — Inserts, Removes and retained Compacts alike.

Link copied to clipboard

The materialized sequence of all RgaIds in RGA order, including tombstones. Computed lazily and cached.

Link copied to clipboard
val size: Int

The number of visible elements.

Link copied to clipboard

The set of all RgaIds that have been tombstoned (and not yet compacted).

Functions

Link copied to clipboard
fun apply(op: RgaOp<V>): Rga<V>

Apply an op received from a remote replica, advancing the Lamport clock.

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

The causal Dots this op-log has delivered: every Insert's own dot (id.dot = (replicaId, seq)) plus every dot recorded in a Compact op.

Link copied to clipboard
open override fun causalFloor(): VersionVector

The delivered dots this replica compacted away without keeping their ids — exactly compactedBelow.

Link copied to clipboard
open override fun classify(op: RgaOp<V>): LogOp<RgaId>

Classify one RgaOp — see OpLogCrdt.classify. Delegates to the sole classifier.

Link copied to clipboard
fun compact(stableCut: VersionVector, frontierMax: VersionVector, delivered: VersionVector): Pair<Rga<V>, RgaOp.Compact>?

Garbage-collect tombstoned elements that are causally stable under the eviction-safe causal-stability barrier (ADR-003 addendum v3, #262).

Link copied to clipboard
open override fun dotOf(id: RgaId): Dot

The causal dot id belongs to — see OpLogCrdt.dotOf.

Link copied to clipboard
fun dropWindow(self: ReplicaId, dropped: Set<RgaId>): Pair<Rga<V>, Patch<Rga<V>>>?

Drop dropped from this log — the un-gated history-windowing path (#254), not the causal-stability barrier of compact.

Link copied to clipboard
fun entries(): List<Pair<RgaId, V>>

The visible elements paired with their RgaIds, in sequence order — the id-carrying form of toList (toList() == entries().map { it.second }).

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

Two Rga instances are equal when their op-sets and their compactedBelow floors are equal — i.e. they represent the same CRDT state.

Link copied to clipboard
open override fun hashCode(): Int
Link copied to clipboard
fun insertAfter(replica: ReplicaId, after: RgaId, value: V): Pair<Rga<V>, RgaOp.Insert<V>>

Insert value immediately after the element with after id, minting a new RgaId on behalf of replica.

Link copied to clipboard
fun insertAllAfter(replica: ReplicaId, after: RgaId, values: List<V>): Pair<Rga<V>, List<RgaOp.Insert<V>>>

Append values as a chain starting immediately after after, minting one RgaOp.Insert per element on behalf of replica.

Link copied to clipboard
fun insertAt(replica: ReplicaId, index: Int, value: V): Pair<Rga<V>, RgaOp.Insert<V>>

Insert value at visible position index (0 = prepend before first visible element). Computes the after id from the current visible sequence.

Link copied to clipboard
open override fun operations(): Sequence<RgaOp<V>>

The ops this replica currently holds — see OpLogCrdt.operations.

Link copied to clipboard
open override fun opSerializer(vSerializer: KSerializer<V>): KSerializer<RgaOp<V>>
Link copied to clipboard
open override fun piece(other: Rga<V>): Rga<V>

Merge two replicas' op-logs. The result is the idempotent union — both replicas converge to the same toList after piece.

Link copied to clipboard

Returns a positions map for ids: each id mapped to its RgaOp.Insert.after. All ids must be present in insertsById (non-compacted — live or tombstoned). Used by us.tractat.kuilt.quilter.RgaGcCoordinator to build positions for window-dropped live elements when constructing a combined RgaOp.Compact.

Link copied to clipboard
fun removeAt(index: Int): Pair<Rga<V>, RgaOp.Remove<V>>?

Remove the visible element at index.

Link copied to clipboard

Tombstone the first count visible elements, minting one RgaOp.Remove each.

Link copied to clipboard
fun toList(): List<V>

The current visible (non-tombstoned) elements, in sequence order.

Link copied to clipboard
open override fun toString(): String
Link copied to clipboard
fun valueAt(id: RgaId): V

The element id carries — O(1), and the only way to read one element's value.