SharedStates

class SharedStates(codec: EventCodec, readers: Map<String, Set<AggregateType>>, options: SharedStateOptions = SharedStateOptions(), timeSource: TimeSource = TimeSource.Monotonic, val gate: ReplayGate = ReplayGate.OPEN)

The shared states of one bounded context, shared by every state consumer of it: the snapshot subscription, the subscriptions of annotated processors, and later the sinks. Each of them is a named readers entry with the aggregate types it reads.

  • Recording: the executor records the state after each commit of an aggregate type some reader reads, while the aggregate's lane still holds it; a reader that had to rebuild a state (SharedStateReader) puts it here too, so the other readers, and its own next entry of the aggregate, start from it.

  • Expecting: the log hands a commit to this node's subscriptions as it commits, before the executor can record it. So the executor first expects the state of the stream it is about to append, a pending view of the aggregate, and record then makes it a view; a reader handed the commit meanwhile gets the pending view (get by stream) only for that very append, the same command, request and commit time at the same version: the entry it holds proves that append committed. The lane forgets it whatever the outcome, so an append that did not commit (or whose outcome is unknown) leaves nothing behind. An aggregate has a pending view for each stream its lane is appending: one, or the streams of a batch.

  • Reading: a view is used only for the exact version it was taken at (get), never taken away: every reader gets it. floor gives the latest one before a version, which a reader behind it evolves with the log's tail.

  • Eviction: a reader passes an aggregate's version once it is done with it. A view is evicted once every reader of its type passed a later version of its aggregate, so the latest view each reader handled stays as the base of its next entry; and in any case once it is older than SharedStateOptions.maxAge or the views exceed SharedStateOptions.capacity, oldest first: a reader that runs elsewhere (another node owns the partition) or is parked never holds views for long. A view missing for any reason costs its reader a rebuild, never a wrong state.

  • Rebuilding: a reader's rebuild of a state from the snapshot store and the log runs one an aggregate at a time, under the gate (rebuild): the readers that miss the same hot aggregate at once replay its log once, not once each, and then evolve the view the rebuild left.

Constructors

Link copied to clipboard
constructor(codec: EventCodec, readers: Map<String, Set<AggregateType>>, options: SharedStateOptions = SharedStateOptions(), timeSource: TimeSource = TimeSource.Monotonic, gate: ReplayGate = ReplayGate.OPEN)

Properties

Link copied to clipboard
val bytes: Long

The bytes of the states held, two a character.

Link copied to clipboard

How a rebuild replays the log: the node's gate, the query bulkhead of the log's store, so the rebuilds of the subscriptions cannot take every connection the appends draw from; ReplayGate.OPEN runs each at once.

Link copied to clipboard

The readers, by name, with the aggregate types each reads.

Link copied to clipboard

The number of rebuilds that run now: at most one an aggregate.

Link copied to clipboard
val size: Int

The number of views held.

Link copied to clipboard

The aggregate types whose views are recorded: those some reader reads.

Functions

Link copied to clipboard
fun expect(model: AggregateModel<*>, stream: EventStreamRecord, state: CachedState)

Holds the state after stream, which the executor is about to append, as the pending view of its aggregate, when some reader reads model's aggregate type: replaced by the aggregate's next one, made a view by record, dropped by forget.

Link copied to clipboard
fun floor(ref: AggregateRef, version: Int): SerializedState?

The latest view of ref before version, or null when there is none.

Link copied to clipboard

Drops the pending view of ref, if any: its lane is done with the command that expected it.

Link copied to clipboard

The view after stream, a committed stream a reader holds: the one taken at its version, else the pending view expected for that very append, which then becomes a view the other readers get too; null without either.

fun get(ref: AggregateRef, version: Int): SerializedState?

The view of ref taken at version, or null when there is none at that version.

Link copied to clipboard
fun pass(reader: String, ref: AggregateRef, version: Int)

reader is done with ref up to version: the views every reader of the type passed a later version of are evicted. A reader that reads none of the type passes nothing.

Link copied to clipboard

Holds view of ref, when some reader of its type may still read it: a view every reader already passed a later version of is not kept, and one already held at its version is kept as it is.

Link copied to clipboard
suspend fun <T : Any> rebuild(ref: AggregateRef, replay: suspend () -> T): T?

Runs replay, a reader's rebuild of ref's state, under the gate, and returns what it gives, unless another reader's rebuild of ref runs already: then it waits for that one to end, however it ends, and returns null, so the caller looks again for the view that rebuild left, and rebuilds itself only without one. A rebuild that fails, is cancelled or is refused by the gate ends like one that succeeds: one of the readers that waited for it rebuilds next, and the others wait for that one; none fails with it.

Link copied to clipboard

Records the state of committed, when some reader reads model's aggregate type: the pending view of its stream, when one was expected, else the state serialized now.