state

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package state is Atlas's materialized state store: the queryable fold of the event log (ADR-0001), backed by Pebble (ADR-0003).

State is never the source of truth — the WAL is. Durability therefore belongs to the WAL's fsync (ADR-0005), so state transactions commit without their own fsync (NoSync): after a crash the store may trail the log, and recovery replays events from Store.LastAppliedPosition forward to catch up. Because each transaction commits its mutations and the advanced position atomically, state and position can never disagree.

Keys are organized into column-family indexes (see keys.go) so the engine's access patterns — "elements of this instance", "open jobs of this type", "timers due by now" — are prefix or range scans rather than full scans.

A Store is owned by a single partition goroutine (invariant I3); it holds no locks of its own.

Index

Constants

View Source
const (
	ReplayActivated  byte = 1 // the token entered the element
	ReplayCompleted  byte = 2 // the element finished; its successor takes the token
	ReplayTerminated byte = 3 // the element was torn down; the token dies with it
)

The action codes of an ElementReplayValue — what the token did at this element. Completion and termination are deliberately distinct: a completed element hands its token on to a successor, a terminated one (interrupted by a boundary event, torn down with its scope, cancelled) does not, so a replay must not wait for a successor that will never activate (ADR-0136). Codes are persisted, so their numeric values are part of the on-disk history format and must not be reused.

Variables

This section is empty.

Functions

func LocalVariablesMap added in v0.3.0

func LocalVariablesMap(r Reader, scope uint64) (map[string]model.VariableValue, error)

LocalVariablesMap reads one scope's own variables into a map keyed by name, inheriting nothing. It is what an outbound body wants when its task carries input mappings: at activation the activity-local scope holds exactly what those mappings wrote (a job's result is written there only on completion), so the model states what leaves the process rather than spilling every variable it can see (ADR-0174).

func VisibleVariables added in v0.3.0

func VisibleVariables(r Reader, elementInstanceKey uint64, fn func(v *model.VariableValue) error) error

VisibleVariables calls fn with every variable *visible* at an element instance: its own activity-local scope first (the zeebe:ioMapping inputs written on activation), then each enclosing scope up to the process root, with the nearest scope winning when a name is shadowed (ADR-0068). It is the read a job handler wants — the engine binds an activity's own FEEL exactly this way (bindInputsChain) — and reading a single scope instead is how a worker comes to ignore its task's input mappings.

The chain is walked via each scope's element instance's FlowScopeKey; the process-instance root has no element instance, which ends it. An activity with no mappings has an empty local scope, so this degenerates to reading the enclosing scope, exactly as a single-scope read did.

It takes a Reader rather than being a method so every worker shares one implementation of the walk — they used to grow a copy each.

func VisibleVariablesMap added in v0.3.0

func VisibleVariablesMap(r Reader, elementInstanceKey uint64) (map[string]model.VariableValue, error)

VisibleVariablesMap is VisibleVariables collected into a map keyed by name — the shape a worker binds FEEL against, so it resolves the names an expression reads without a per-name store lookup.

Types

type ElementReplayValue

type ElementReplayValue struct {
	ElementID, SourceFlowID                    int32
	ElementInstanceKey, TokenID, ParentTokenID uint64
	Action                                     byte
}

ElementReplayValue is one durable causal token-lifecycle fact.

type ReadView added in v0.3.0

type ReadView struct {
	// contains filtered or unexported fields
}

ReadView is a consistent read-only view of the store as of the moment it was taken. Later writes are invisible to it, so a handler reading an element instance and then its variables sees one coherent state rather than two halves of different ones.

It holds resources in the store's engine, so it must be closed. Take one on the run loop (the store's owner), use it off the loop, close it when the work is done — the same lifetime as the job it was taken for.

func (ReadView) ActivatableJobs added in v0.5.0

func (q ReadView) ActivatableJobs(jobType int32, fn func(jobKey uint64) error) error

ActivatableJobs calls fn with the key of every open job of the given type, via the jobActivatable index — the worker-polling access pattern.

A non-nil error from fn ends the scan and comes back from here, which is how a caller that wants a *page* pays for a page: the index is ordered, so stopping at the nth entry visits n entries whatever the backlog behind it. Returning nil once full and discarding the rest reads the whole slice instead, and that is what made a worker's heartbeat cost grow with the backlog it was there to drain (ADR-0270). Callers that stop deliberately use a sentinel and unwrap it; anything else is a real failure.

func (ReadView) ActivatableJobsDesc added in v0.5.0

func (q ReadView) ActivatableJobsDesc(jobType int32, before uint64, fn func(jobKey uint64) error) error

ActivatableJobsDesc calls fn with the key of every open job of the given type in DESCENDING key order (newest first), starting just below `before` — before == 0 starts from the newest key. It backs the task inbox's newest-first, cursor-paged listing (GET /tasks?before=): a flood parks its oldest tasks at the low keys, so paging from the newest downward surfaces the tasks an operator most likely wants first while still bounding the scan. Worker polling keeps using ActivatableJobs (oldest-first, FIFO) — this is a read-side ordering only.

func (ReadView) ActiveElementInstanceCount added in v0.5.0

func (q ReadView) ActiveElementInstanceCount() (int, error)

ActiveElementInstanceCount returns how many element instances are live.

func (ReadView) ActiveElementInstances added in v0.5.0

func (q ReadView) ActiveElementInstances(fn func(key uint64, v *model.ElementInstanceValue) error) error

ActiveElementInstances calls fn with the key and value of every live element instance. Each carries the BPMN element (as a compiled-graph index) it sits on, which the live diagram overlay maps back to a diagram element.

func (ReadView) ActiveInstancesOfDefDesc added in v0.5.0

func (q ReadView) ActiveInstancesOfDefDesc(procDefKey, before uint64, fn func(key uint64, v *model.ProcessInstanceValue) error) error

ActiveInstancesOfDefDesc calls fn with every live instance of one definition in DESCENDING key order — newest first — starting just below `before`; before == 0 starts from the newest. It reads the by-definition index, so its cost is the page it yields plus one point read per row, not the size of the store: a version with three running instances costs three reads whether the engine holds a thousand instances or a million.

It is the definition-scoped counterpart of [queries.ActiveProcessInstancesDesc], and it takes a cursor rather than only a limit because a version's list is paged rather than truncated. The caller stops a page by returning a sentinel from fn, exactly as the task inbox pages ActivatableJobsDesc; the key of the last row it kept is the cursor for the next (older) page.

func (ReadView) ActiveProcessInstance added in v0.5.0

func (q ReadView) ActiveProcessInstance(key uint64) (*model.ProcessInstanceValue, bool, error)

ActiveProcessInstance returns the live process instance for key and whether one exists, as a point read of the active family alone.

It is deliberately narrower than [queries.ProcessInstance], which also answers from history: a caller asking "may I cancel this?" must not be told yes about an instance that already finished. Existence checks used to walk the whole active family looking for one key — O(instances) to answer a question a single lookup answers, and on the run loop at that.

func (ReadView) ActiveProcessInstanceCount added in v0.5.0

func (q ReadView) ActiveProcessInstanceCount() (int, error)

ActiveProcessInstanceCount returns how many process instances are live.

func (ReadView) ActiveProcessInstances added in v0.5.0

func (q ReadView) ActiveProcessInstances(fn func(key uint64, v *model.ProcessInstanceValue) error) error

ActiveProcessInstances calls fn with the key and value of every live process instance, via the process-instance column family — the operator "list running instances" access pattern.

func (ReadView) ActiveProcessInstancesDesc added in v0.5.0

func (q ReadView) ActiveProcessInstancesDesc(limit int, fn func(key uint64, v *model.ProcessInstanceValue) error) (more bool, err error)

ActiveProcessInstancesDesc calls fn with live process instances in descending key order — newest first, since keys are allocated in creation order — and stops after limit of them, reporting whether more remained.

It is the bounded form of [queries.ActiveProcessInstances], for the read paths that only ever show the newest page: collecting every instance and sorting afterwards costs O(instances) in time and memory to display O(limit) rows, which is the shape ADR-0080 removed from the runtime views. A limit of zero or less scans nothing.

func (ReadView) AllActivatableJobs added in v0.5.0

func (q ReadView) AllActivatableJobs(fn func(jobKey uint64) error) error

AllActivatableJobs calls fn with the key of every open job of ANY type, via the same jobActivatable index — the whole column family rather than one job type's slice. It backs the read side of the operator complete/fail affordance (listing the jobs an instance is parked on); worker polling still uses the type-scoped ActivatableJobs.

func (ReadView) AllElementReplay added in v0.5.0

func (q ReadView) AllElementReplay(fn func(piKey uint64, ts int64, pos uint64, v ElementReplayValue) error) error

AllElementReplay scans every retained token-lifecycle fact in the store, in instance order and in time order within an instance, naming the instance each fact belongs to.

ElementReplayHistory answers "what happened in this case"; this answers "what happened at all", which is the question a whole-run analysis asks — how often each element and each sequence flow carried a token. Doing it as one iteration matters: a scan per case over fifty thousand cases is fifty thousand iterators, and the caller wanted a single number per element.

func (ReadView) ChildInstancesOfParent added in v0.5.0

func (q ReadView) ChildInstancesOfParent(callElKey uint64, fn func(childPiKey uint64) error) error

ChildInstancesOfParent calls fn with the process instance key of every live child a call-activity element instance started (ADR-0076), via the childByParent index.

The alternative — the one this replaced — is a walk of every live instance comparing ParentElementInstanceKey, which the engine performed *per call activity* when tearing one down. Cancelling a parent holding many children was therefore quadratic in the instance population.

func (*ReadView) Close added in v0.3.0

func (v *ReadView) Close() error

Close releases the view. A view left open holds back the compaction of everything written since it was taken, so it must not outlive the work it was taken for.

func (ReadView) CompensablesOfScope added in v0.5.0

func (q ReadView) CompensablesOfScope(scope uint64, fn func(v *model.CompensableValue) error) error

CompensablesOfScope calls fn with every completed compensable activity retained under the given scope, in completion order (ADR-0103). Used to surface a scope's pending compensations to operators and by tests to assert the index is cleaned when a scope tears down. Mirrors VariablesOfScope (committed reads only).

func (ReadView) CompletedProcessInstances added in v0.5.0

func (q ReadView) CompletedProcessInstances(fn func(key uint64, v *model.ProcessInstanceValue) error) error

CompletedProcessInstances calls fn with the key and value of every process instance that has reached a terminal state, via the history column family — the operator "list finished instances" access pattern (ADR-0017). Each value carries its terminal State and CompletedAt.

func (ReadView) CompletedProcessInstancesDesc added in v0.5.0

func (q ReadView) CompletedProcessInstancesDesc(limit int, fn func(key uint64, v *model.ProcessInstanceValue) error) (more bool, err error)

CompletedProcessInstancesDesc is [queries.ActiveProcessInstancesDesc] over the terminal-history family: finished instances, newest first, bounded.

func (ReadView) CompletedProcessInstancesFrom added in v0.5.0

func (q ReadView) CompletedProcessInstancesFrom(startKey uint64, limit int, fn func(key uint64, v *model.ProcessInstanceValue) error) (next uint64, more bool, err error)

CompletedProcessInstancesFrom scans finished instances in key order starting at startKey, invoking fn for up to limit of them, and returns the key to resume from next and whether the window filled (more may remain). It gives the retention sweep a bounded, resumable window so one tick never scans the whole history family on the run loop (ADR-0115, honoring the ADR-0085 no-full-scan rule). When the scan reaches the end, more is false and the caller restarts from genesis.

func (ReadView) DataObjectSnapshotHistory added in v0.5.0

func (q ReadView) DataObjectSnapshotHistory(scopeKey uint64, fn func(ts int64, pos uint64, v *model.DataObjectValue) error) error

DataObjectSnapshotHistory folds the retained data-object state changes of one scope, calling fn with each change's event timestamp, log position, and the object's new state in the order they occurred (ADR-0053). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence a caller folds by position — the event-sourced data-state timeline and the basis for lineage. Mirrors VariableSnapshotHistory (ADR-0048).

func (ReadView) DataObjectsOfScope added in v0.5.0

func (q ReadView) DataObjectsOfScope(scope uint64, fn func(v *model.DataObjectValue) error) error

DataObjectsOfScope calls fn with every data object owned by the given scope, via the data-object column family — the current value of each. Used to surface an instance's data to operators and, later, to build a FEEL scope for data associations (ADR-0053). Mirrors VariablesOfScope.

func (ReadView) DecisionEvaluationHistory added in v0.5.0

func (q ReadView) DecisionEvaluationHistory(scopeKey uint64, fn func(ts int64, pos uint64, v *model.DecisionEvaluationValue) error) error

DecisionEvaluationHistory folds the retained DMN decision evaluations of one scope (a process instance), calling fn with each evaluation's event timestamp, log position, and its frozen record (decision id, inputs, outputs, trace) in the order they occurred (ADR-0066). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence — the same ordering as the variable and element-step timelines, so a business rule task's decision reasoning lines up with the step at which it ran. Used to surface how a decision was made to operators, both live and after the instance has finished.

func (ReadView) DefCompletedCount added in v0.5.0

func (q ReadView) DefCompletedCount(procDefKey uint64) (int, error)

DefCompletedCount returns how many instances of one definition have finished (completed or terminated), from the maintained counter in O(1) rather than scanning the history (ADR-0083).

func (ReadView) DefInstanceCount added in v0.5.0

func (q ReadView) DefInstanceCount(procDefKey uint64) (int, error)

DefInstanceCount returns how many instances of one definition are live, read from the maintained per-definition counter in O(1) rather than scanning every instance (ADR-0080).

func (ReadView) DefLastActivity added in v0.5.0

func (q ReadView) DefLastActivity(procDefKey uint64) (int64, error)

DefLastActivity returns the unix-nano timestamp of a definition's most recent instance lifecycle event (0 if it has had none), read in O(1) (ADR-0083).

func (ReadView) DueHistoryExpiries added in v0.5.0

func (q ReadView) DueHistoryExpiries(now int64, limit int, fn func(dueDate int64, piKey uint64) error) (more bool, err error)

DueHistoryExpiries calls fn with the purge due date and instance key of every finished instance whose history TTL has elapsed by now, in due-date order, for up to limit of them; it reports whether the window filled (more may be due). This is the retention sweep's candidate set (ADR-0146): a range scan bounded by now, so a tick costs what is due rather than what the history holds — the property the key-order scan lacked, and the one ADR-0085 built the due-timer index for. An idle server pays one empty scan.

func (ReadView) DueTimers added in v0.5.0

func (q ReadView) DueTimers(now int64, fn func(timerKey uint64, v *model.TimerValue) error) error

DueTimers calls fn for every timer whose due date is at or before now, in due order. Because the due date is the index prefix, this is a range scan from the start of the timer family up to now — no scheduler structure, no full scan.

func (ReadView) EachDecisionEvaluation added in v0.5.0

func (q ReadView) EachDecisionEvaluation(fn func(scopeKey uint64, ts int64, v *model.DecisionEvaluationValue) error) error

EachDecisionEvaluation folds every retained DMN decision evaluation across all process instances, calling fn with the owning scope (process instance) key, the evaluation's event timestamp, and its frozen record (ADR-0066). It scans the whole decision-evaluation column family — the global "which decisions ran, and how often" access pattern the Operations decisions overview uses, as opposed to DecisionEvaluationHistory, which folds a single instance's evaluations. The scan order is scope then timestamp then position; a caller that only aggregates by decision id does not depend on it.

func (ReadView) ElementInstancesOfProcess added in v0.5.0

func (q ReadView) ElementInstancesOfProcess(procKey uint64, fn func(elKey uint64) error) error

ElementInstancesOfProcess calls fn with the key of every element instance belonging to the given process instance, via the elByProc index.

func (ReadView) ElementLiveTokens added in v0.5.0

func (q ReadView) ElementLiveTokens(procDefKey uint64, fn func(elementId int32, count int64) error) error

ElementLiveTokens calls fn with each of a definition's elements that currently holds live tokens and how many — one prefix scan over the per-element token counters, so it is O(elements), not O(instances) (ADR-0080).

func (ReadView) ElementReplayHistory added in v0.5.0

func (q ReadView) ElementReplayHistory(piKey uint64, fn func(ts int64, pos uint64, v ElementReplayValue) error) error

ElementReplayHistory scans causal token lifecycle facts in deterministic order.

func (ReadView) ElementStepHistory added in v0.5.0

func (q ReadView) ElementStepHistory(piKey uint64, fn func(ts int64, pos uint64, elementId int32) error) error

ElementStepHistory folds the retained element-activation steps of one process instance, calling fn with each step's event timestamp, log position, and the activated element's compiled-graph index in the order they occurred (the step-by-step replay timeline, ADR-0046). Because the key sorts by timestamp then position, an instance-wide scan yields a monotonic sequence. The caller resolves the element index to a diagram id via the instance's compiled process.

func (ReadView) ElementTerminationHistory added in v0.5.0

func (q ReadView) ElementTerminationHistory(procDefKey, instanceFilter uint64, fn func(elementId int32, count int64) error) error

ElementTerminationHistory folds the token-termination counters for a process definition, calling fn with each element index and how many tokens were cancelled on it — the same scan shape as ElementVisitHistory, over the same key layout, so the two halves of "a token was here and left" are read identically. instanceFilter == 0 aggregates the definition's instances; a non-zero one isolates that instance.

func (ReadView) ElementTerminationTotals added in v0.5.0

func (q ReadView) ElementTerminationTotals(procDefKey uint64, fn func(elementId int32, count int64) error) error

ElementTerminationTotals calls fn with each of a definition's elements and how many tokens left it cancelled rather than completed — the counterpart of ElementVisitTotals, read the same way in O(elements) from a maintained counter (ADR-0080, ADR-0249). An element nothing was ever cancelled on is absent, so a caller that folds this over the visit totals leaves it at zero.

func (ReadView) ElementVisitHistory added in v0.5.0

func (q ReadView) ElementVisitHistory(procDefKey, instanceFilter uint64, fn func(elementId int32, count int64) error) error

ElementVisitHistory folds the token-visit counters for a process definition, calling fn with each visited element index and how many tokens have passed through it. With instanceFilter == 0 it aggregates every instance of the definition (the heatmap the live overlay draws in gray); with a non-zero instanceFilter it reports only that one instance's visits. Because the key ends with the element index and the same element sits under a distinct instance-key prefix per instance, a definition-wide scan can report the same element index once per instance — the caller sums the counts. Pebble folds the merge deltas for each key, so raw carries the current total for that key.

func (ReadView) ElementVisitTotals added in v0.5.0

func (q ReadView) ElementVisitTotals(procDefKey uint64, fn func(elementId int32, count int64) error) error

ElementVisitTotals calls fn with each of a definition's elements and its cumulative visit count — the aggregate heatmap, read in O(elements) from the maintained per-element visit counter instead of summing every instance's visit history (ADR-0080, aggregating ADR-0022).

func (ReadView) FinishedInstancesOfDefDesc added in v0.5.0

func (q ReadView) FinishedInstancesOfDefDesc(procDefKey uint64, beforeCompletedAt int64, beforeKey uint64, fn func(key uint64, v *model.ProcessInstanceValue) error) error

FinishedInstancesOfDefDesc calls fn with every finished instance of one definition in DESCENDING completion order — most recently finished first — starting just below the (beforeCompletedAt, beforeKey) cursor; a zero cursor starts from the most recent. It is the history counterpart of [queries.ActiveInstancesOfDefDesc], and it gets that order from the index key rather than by sorting the history in memory — which is what [queries.CompletedProcessInstancesDesc] cannot do, since the history family is in key order and an instance started first can finish last.

The cursor is a pair for that same reason. fn receives the value, whose CompletedAt together with the key forms the cursor for the next page.

func (ReadView) GetElementInstance added in v0.3.0

func (q ReadView) GetElementInstance(key uint64) (*model.ElementInstanceValue, bool, error)

GetElementInstance returns the committed element instance for key, reporting whether it was present. Like GetJob it reads outside a transaction, for consumers such as the in-process DMN worker resolving the decision an activatable business-rule job belongs to.

func (ReadView) GetIncident added in v0.5.0

func (q ReadView) GetIncident(elKey uint64) (*model.IncidentValue, error)

GetIncident returns the committed incident on an element instance, or nil if there is none. It reads outside a transaction, for the resolve endpoint's existence check (ADR-0061).

func (ReadView) GetJob added in v0.5.0

func (q ReadView) GetJob(key uint64) (*model.JobValue, bool, error)

GetJob returns the committed job for key, reporting whether it was present. Unlike Tx.GetJob it reads outside a transaction, for queries such as a worker runner pulling activatable jobs.

func (ReadView) IncidentCount added in v0.5.0

func (q ReadView) IncidentCount() (int, error)

IncidentCount returns how many unresolved incidents exist — how many tokens are parked waiting for an operator (ADR-0061). Counted from state by walking the incident family's keys, not from a maintained counter: an incident leaves state two ways, resolved by an operator *and* dropped with the element instance it sits on (an instance cancel or an interrupting boundary event, which announce no resolution), so a maintained number would drift while a scan cannot. The family holds one key per stuck token, which is the population an operator is expected to keep near zero.

func (ReadView) Incidents added in v0.5.0

func (q ReadView) Incidents(fn func(elementKey uint64, v *model.IncidentValue) error) error

Incidents calls fn with the element-instance key and value of every unresolved incident — the operator "list incidents" access pattern (ADR-0061).

func (ReadView) InstancesByVariable added in v0.5.0

func (q ReadView) InstancesByVariable(name, value string, prefix bool, fn func(piKey uint64) error) error

InstancesByVariable calls fn with the key of every process instance holding the given variable value — a seek into the value index, not a walk of the instances. It is the answer to the operator's real question ("where is MT-1998?"), and its cost is the number of matches plus a seek, whatever the engine holds.

prefix asks the other question an ordered index can answer: every value starting with value, rather than equal to it. Both are the same scan over a different bound — see [variableIndexExactPrefix] for why the exact one needs a terminator.

Only writes the instance's process declared searchable are in the index, and only since the declaration existed, so a caller that must not miss an older instance falls back to a content walk. The index never reports an instance that does not hold the value.

func (ReadView) InstancesOnElementDesc added in v0.5.0

func (q ReadView) InstancesOnElementDesc(procDefKey uint64, elementId int32, before uint64, fn func(key uint64, v *model.ProcessInstanceValue) error) error

InstancesOnElementDesc calls fn with every live instance of one definition that currently holds a token on the given element, in DESCENDING instance-key order — newest first — starting just below `before`; before == 0 starts from the newest.

It reads the piByEl index, so its cost is the answer and not the version: an element five instances are waiting on costs five reads whether the definition holds five instances or five hundred thousand. That is the whole point of the index — the alternative is testing every live instance of the version for a token on one element, which is a walk that grows with the population and would run on every poll of the Operations view (ADR-0080's rule, applied to a filter).

An instance is yielded once however many tokens it holds on the element: a loop or a multi-instance activity puts several there, and "which instances are on this task" is a question about instances. The entries of one instance are adjacent, so the de-duplication is a comparison with the previous key rather than a set.

fn may stop the walk early by returning a sentinel error, exactly as the by-definition walks do; the key of the last row it kept is the cursor for the next (older) page.

func (ReadView) JobOfElement added in v0.5.0

func (q ReadView) JobOfElement(elKey uint64) (uint64, bool, error)

JobOfElement returns the key of the job held by the given element instance, or ok=false if it holds none. It is the read-side counterpart of Tx.JobOfElement, used to resolve one instance's open jobs through the element→job reverse index rather than scanning the global activatable index.

func (ReadView) LastAppliedPosition added in v0.5.0

func (q ReadView) LastAppliedPosition() (uint64, error)

LastAppliedPosition returns the highest log position folded into committed state, or 0 if none has been applied yet (genesis).

func (ReadView) MessageFlowHistory added in v0.5.0

func (q ReadView) MessageFlowHistory(receiverDefKey uint64, fn func(ts int64, pos uint64, v *model.MessageFlowValue) error) error

MessageFlowHistory folds the retained message flows a definition received, calling fn with each flow's event timestamp, log position, and payload in the order they occurred (the replay timeline). Because the key sorts by timestamp then position, a definition-wide scan yields a monotonic sequence. The caller resolves the receiver element index to a diagram id via the compiled process.

func (ReadView) MessageSubscriptions added in v0.5.0

func (q ReadView) MessageSubscriptions() (int64, error)

MessageSubscriptions is how many message subscriptions are currently waiting to correlate, engine-wide.

func (ReadView) OpenJobs added in v0.5.0

func (q ReadView) OpenJobs() (int64, error)

OpenJobs is how many jobs are currently waiting for a worker, engine-wide, read from the maintained counter rather than by scanning the job family (ADR-0142).

func (ReadView) OperatorActionHistory added in v0.5.0

func (q ReadView) OperatorActionHistory(piKey uint64, fn func(ts int64, pos uint64, v *model.OperatorActionValue) error) error

OperatorActionHistory folds the retained operator interventions of one process instance, calling fn with each action's event timestamp, log position, and its frozen record (who acted, on which element, and why) in the order they occurred (ADR-0159). Like VariableAuditHistory the key sorts by timestamp then position, so the trail lines up with the step at which each intervention happened, and it surfaces both live and after the instance has finished since the records are append-only history.

func (ReadView) PendingTimers added in v0.5.0

func (q ReadView) PendingTimers() (int64, error)

PendingTimers is how many timers are currently waiting to fire, engine-wide.

func (ReadView) ProcessInstance added in v0.5.0

func (q ReadView) ProcessInstance(key uint64) (*model.ProcessInstanceValue, bool, error)

ProcessInstance returns the process instance for key and whether it was found, looking first in the active family and then in the terminal-history family (ADR-0017). It lets a query resolve an instance's definition whether it is still running or already finished — the lookup the single-process replay uses.

func (ReadView) StartTimers added in v0.5.0

func (q ReadView) StartTimers(fn func(timerKey uint64, v *model.TimerValue) error) error

StartTimers calls fn for every armed start timer — one whose owning process instance key is zero, so it instantiates a definition on fire rather than continuing a waiting element (ADR-0051). It is a full scan of the timer family, used only when a definition is (re)deployed (off the hot path), so arming can be idempotent and can supersede a prior version's schedule.

func (ReadView) TotalActiveInstances added in v0.5.0

func (q ReadView) TotalActiveInstances() (int64, error)

TotalActiveInstances is how many process instances are live across every definition, summed from the maintained per-definition counters (ADR-0080) rather than by walking the instance records.

The distinction is the whole point: the authoritative Store.ActiveProcessInstanceCount scans the runtime set, so it costs more the busier the engine is — fine for a request, wrong for something a Prometheus scrape takes every fifteen seconds. This sum reads one key per **deployed definition**, a number that changes only when someone deploys (ADR-0142).

One honest qualification, measured rather than assumed (BenchmarkTotalActiveInstances): these are *merge* counters, so a read also folds in whatever operands Pebble has not compacted yet — right after a burst of starts the sum costs O(recent writes), not O(definitions). A flush collapses them, after which the sum is flat regardless of how many instances are running: 2,000 instances read as fast as 100. Flushes happen on their own, and the ADR-0131 checkpoint cadence forces one every few minutes, so the backlog is bounded in a running engine. Even un-compacted it stays cheaper than the scan it replaces.

func (ReadView) TotalLiveTokens added in v0.5.0

func (q ReadView) TotalLiveTokens() (int64, error)

TotalLiveTokens is how many element instances hold live tokens across every definition, summed from the maintained per-definition-element counters (ADR-0080). Bounded by the number of deployed *elements* — design-time size, not runtime population — for the same reason as Store.TotalActiveInstances.

func (ReadView) VariableAuditHistory added in v0.5.0

func (q ReadView) VariableAuditHistory(piKey uint64, fn func(ts int64, pos uint64, v *model.VariableAuditValue) error) error

VariableAuditHistory folds the retained external variable overrides of one process instance, calling fn with each override's event timestamp, log position, and its frozen record (who set which variable, on which scope, to what value) in the order they occurred (ADR-0098). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence — the same ordering as the variable and decision timelines — so the "who changed it" trail lines up with the step at which each override happened. It surfaces to operators both live and after the instance has finished, since the records are append-only history.

func (ReadView) VariableSnapshotHistory added in v0.5.0

func (q ReadView) VariableSnapshotHistory(scopeKey uint64, fn func(ts int64, pos uint64, v *model.VariableValue) error) error

VariableSnapshotHistory folds the retained variable changes of one scope (a process instance), calling fn with each change's event timestamp, log position, and the variable's new state in the order they occurred (ADR-0048). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence a caller folds by position to reconstruct the variables as of any step.

func (ReadView) VariablesOfScope added in v0.3.0

func (q ReadView) VariablesOfScope(scope uint64, fn func(v *model.VariableValue) error) error

VariablesOfScope calls fn with every variable owned by the given scope, via the variable column family. Used to build a FEEL evaluation scope and to surface an instance's variables to operators.

func (ReadView) VisibleVariablesOfScope added in v0.5.0

func (q ReadView) VisibleVariablesOfScope(scope uint64, fn func(v *model.VariableValue) error) error

VisibleVariablesOfScope calls fn with every variable *visible* at the given scope: the scope's own variables plus those inherited from each enclosing scope, walking up the FlowScopeKey chain to the process root, with the nearest scope winning when a name is shadowed. This mirrors the engine's variable visibility (ResolveVariable / bindInputsChain, ADR-0068): a token at an activity-local scope sees its locals over anything inherited. Passing the process-instance root key yields exactly the root's variables (it has no enclosing scope), so callers reading a root instance are unaffected.

It is the Reader-level VisibleVariables under a name that reads better at a call site holding a *Store; the walk itself lives there, shared with the worker workers.

type Reader added in v0.3.0

type Reader interface {
	GetElementInstance(key uint64) (*model.ElementInstanceValue, bool, error)
	VariablesOfScope(scope uint64, fn func(v *model.VariableValue) error) error
}

Reader is the read surface a job handler needs: the element instance its job sits on, and the variables in scope there.

It exists so a handler can be given a *consistent* view instead of the live store. An in-process handler used to run on the single-writer goroutine, where its several reads could not interleave with a write; moving it off that goroutine (ADR-0149 option 3, ADR-0157 step 6) takes that guarantee away, and a ReadView gives it back. Both *Store and *ReadView satisfy it, so a handler neither knows nor needs to know which it holds.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store wraps a Pebble database. It embeds [queries], so every read the store serves is the same code a ReadView serves — see that type's comment for why there are two ways in.

func Open

func Open(dir string) (*Store, error)

Open opens (creating if needed) the state store rooted at dir.

func (Store) ActivatableJobs

func (q Store) ActivatableJobs(jobType int32, fn func(jobKey uint64) error) error

ActivatableJobs calls fn with the key of every open job of the given type, via the jobActivatable index — the worker-polling access pattern.

A non-nil error from fn ends the scan and comes back from here, which is how a caller that wants a *page* pays for a page: the index is ordered, so stopping at the nth entry visits n entries whatever the backlog behind it. Returning nil once full and discarding the rest reads the whole slice instead, and that is what made a worker's heartbeat cost grow with the backlog it was there to drain (ADR-0270). Callers that stop deliberately use a sentinel and unwrap it; anything else is a real failure.

func (Store) ActivatableJobsDesc

func (q Store) ActivatableJobsDesc(jobType int32, before uint64, fn func(jobKey uint64) error) error

ActivatableJobsDesc calls fn with the key of every open job of the given type in DESCENDING key order (newest first), starting just below `before` — before == 0 starts from the newest key. It backs the task inbox's newest-first, cursor-paged listing (GET /tasks?before=): a flood parks its oldest tasks at the low keys, so paging from the newest downward surfaces the tasks an operator most likely wants first while still bounding the scan. Worker polling keeps using ActivatableJobs (oldest-first, FIFO) — this is a read-side ordering only.

func (Store) ActiveElementInstanceCount

func (q Store) ActiveElementInstanceCount() (int, error)

ActiveElementInstanceCount returns how many element instances are live.

func (Store) ActiveElementInstances

func (q Store) ActiveElementInstances(fn func(key uint64, v *model.ElementInstanceValue) error) error

ActiveElementInstances calls fn with the key and value of every live element instance. Each carries the BPMN element (as a compiled-graph index) it sits on, which the live diagram overlay maps back to a diagram element.

func (Store) ActiveInstancesOfDefDesc added in v0.5.0

func (q Store) ActiveInstancesOfDefDesc(procDefKey, before uint64, fn func(key uint64, v *model.ProcessInstanceValue) error) error

ActiveInstancesOfDefDesc calls fn with every live instance of one definition in DESCENDING key order — newest first — starting just below `before`; before == 0 starts from the newest. It reads the by-definition index, so its cost is the page it yields plus one point read per row, not the size of the store: a version with three running instances costs three reads whether the engine holds a thousand instances or a million.

It is the definition-scoped counterpart of [queries.ActiveProcessInstancesDesc], and it takes a cursor rather than only a limit because a version's list is paged rather than truncated. The caller stops a page by returning a sentinel from fn, exactly as the task inbox pages ActivatableJobsDesc; the key of the last row it kept is the cursor for the next (older) page.

func (Store) ActiveProcessInstance added in v0.5.0

func (q Store) ActiveProcessInstance(key uint64) (*model.ProcessInstanceValue, bool, error)

ActiveProcessInstance returns the live process instance for key and whether one exists, as a point read of the active family alone.

It is deliberately narrower than [queries.ProcessInstance], which also answers from history: a caller asking "may I cancel this?" must not be told yes about an instance that already finished. Existence checks used to walk the whole active family looking for one key — O(instances) to answer a question a single lookup answers, and on the run loop at that.

func (Store) ActiveProcessInstanceCount

func (q Store) ActiveProcessInstanceCount() (int, error)

ActiveProcessInstanceCount returns how many process instances are live.

func (Store) ActiveProcessInstances

func (q Store) ActiveProcessInstances(fn func(key uint64, v *model.ProcessInstanceValue) error) error

ActiveProcessInstances calls fn with the key and value of every live process instance, via the process-instance column family — the operator "list running instances" access pattern.

func (Store) ActiveProcessInstancesDesc added in v0.5.0

func (q Store) ActiveProcessInstancesDesc(limit int, fn func(key uint64, v *model.ProcessInstanceValue) error) (more bool, err error)

ActiveProcessInstancesDesc calls fn with live process instances in descending key order — newest first, since keys are allocated in creation order — and stops after limit of them, reporting whether more remained.

It is the bounded form of [queries.ActiveProcessInstances], for the read paths that only ever show the newest page: collecting every instance and sorting afterwards costs O(instances) in time and memory to display O(limit) rows, which is the shape ADR-0080 removed from the runtime views. A limit of zero or less scans nothing.

func (Store) AllActivatableJobs

func (q Store) AllActivatableJobs(fn func(jobKey uint64) error) error

AllActivatableJobs calls fn with the key of every open job of ANY type, via the same jobActivatable index — the whole column family rather than one job type's slice. It backs the read side of the operator complete/fail affordance (listing the jobs an instance is parked on); worker polling still uses the type-scoped ActivatableJobs.

func (Store) AllElementReplay added in v0.5.0

func (q Store) AllElementReplay(fn func(piKey uint64, ts int64, pos uint64, v ElementReplayValue) error) error

AllElementReplay scans every retained token-lifecycle fact in the store, in instance order and in time order within an instance, naming the instance each fact belongs to.

ElementReplayHistory answers "what happened in this case"; this answers "what happened at all", which is the question a whole-run analysis asks — how often each element and each sequence flow carried a token. Doing it as one iteration matters: a scan per case over fifty thousand cases is fifty thousand iterators, and the caller wanted a single number per element.

func (Store) ChildInstancesOfParent added in v0.5.0

func (q Store) ChildInstancesOfParent(callElKey uint64, fn func(childPiKey uint64) error) error

ChildInstancesOfParent calls fn with the process instance key of every live child a call-activity element instance started (ADR-0076), via the childByParent index.

The alternative — the one this replaced — is a walk of every live instance comparing ParentElementInstanceKey, which the engine performed *per call activity* when tearing one down. Cancelling a parent holding many children was therefore quadratic in the instance population.

func (*Store) Close

func (s *Store) Close() error

Close flushes and closes the store.

func (Store) CompensablesOfScope

func (q Store) CompensablesOfScope(scope uint64, fn func(v *model.CompensableValue) error) error

CompensablesOfScope calls fn with every completed compensable activity retained under the given scope, in completion order (ADR-0103). Used to surface a scope's pending compensations to operators and by tests to assert the index is cleaned when a scope tears down. Mirrors VariablesOfScope (committed reads only).

func (Store) CompletedProcessInstances

func (q Store) CompletedProcessInstances(fn func(key uint64, v *model.ProcessInstanceValue) error) error

CompletedProcessInstances calls fn with the key and value of every process instance that has reached a terminal state, via the history column family — the operator "list finished instances" access pattern (ADR-0017). Each value carries its terminal State and CompletedAt.

func (Store) CompletedProcessInstancesDesc added in v0.5.0

func (q Store) CompletedProcessInstancesDesc(limit int, fn func(key uint64, v *model.ProcessInstanceValue) error) (more bool, err error)

CompletedProcessInstancesDesc is [queries.ActiveProcessInstancesDesc] over the terminal-history family: finished instances, newest first, bounded.

func (Store) CompletedProcessInstancesFrom added in v0.2.0

func (q Store) CompletedProcessInstancesFrom(startKey uint64, limit int, fn func(key uint64, v *model.ProcessInstanceValue) error) (next uint64, more bool, err error)

CompletedProcessInstancesFrom scans finished instances in key order starting at startKey, invoking fn for up to limit of them, and returns the key to resume from next and whether the window filled (more may remain). It gives the retention sweep a bounded, resumable window so one tick never scans the whole history family on the run loop (ADR-0115, honoring the ADR-0085 no-full-scan rule). When the scan reaches the end, more is false and the caller restarts from genesis.

func (Store) DataObjectSnapshotHistory

func (q Store) DataObjectSnapshotHistory(scopeKey uint64, fn func(ts int64, pos uint64, v *model.DataObjectValue) error) error

DataObjectSnapshotHistory folds the retained data-object state changes of one scope, calling fn with each change's event timestamp, log position, and the object's new state in the order they occurred (ADR-0053). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence a caller folds by position — the event-sourced data-state timeline and the basis for lineage. Mirrors VariableSnapshotHistory (ADR-0048).

func (Store) DataObjectsOfScope

func (q Store) DataObjectsOfScope(scope uint64, fn func(v *model.DataObjectValue) error) error

DataObjectsOfScope calls fn with every data object owned by the given scope, via the data-object column family — the current value of each. Used to surface an instance's data to operators and, later, to build a FEEL scope for data associations (ADR-0053). Mirrors VariablesOfScope.

func (Store) DecisionEvaluationHistory

func (q Store) DecisionEvaluationHistory(scopeKey uint64, fn func(ts int64, pos uint64, v *model.DecisionEvaluationValue) error) error

DecisionEvaluationHistory folds the retained DMN decision evaluations of one scope (a process instance), calling fn with each evaluation's event timestamp, log position, and its frozen record (decision id, inputs, outputs, trace) in the order they occurred (ADR-0066). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence — the same ordering as the variable and element-step timelines, so a business rule task's decision reasoning lines up with the step at which it ran. Used to surface how a decision was made to operators, both live and after the instance has finished.

func (Store) DefCompletedCount

func (q Store) DefCompletedCount(procDefKey uint64) (int, error)

DefCompletedCount returns how many instances of one definition have finished (completed or terminated), from the maintained counter in O(1) rather than scanning the history (ADR-0083).

func (Store) DefInstanceCount

func (q Store) DefInstanceCount(procDefKey uint64) (int, error)

DefInstanceCount returns how many instances of one definition are live, read from the maintained per-definition counter in O(1) rather than scanning every instance (ADR-0080).

func (Store) DefLastActivity

func (q Store) DefLastActivity(procDefKey uint64) (int64, error)

DefLastActivity returns the unix-nano timestamp of a definition's most recent instance lifecycle event (0 if it has had none), read in O(1) (ADR-0083).

func (Store) DueHistoryExpiries added in v0.2.0

func (q Store) DueHistoryExpiries(now int64, limit int, fn func(dueDate int64, piKey uint64) error) (more bool, err error)

DueHistoryExpiries calls fn with the purge due date and instance key of every finished instance whose history TTL has elapsed by now, in due-date order, for up to limit of them; it reports whether the window filled (more may be due). This is the retention sweep's candidate set (ADR-0146): a range scan bounded by now, so a tick costs what is due rather than what the history holds — the property the key-order scan lacked, and the one ADR-0085 built the due-timer index for. An idle server pays one empty scan.

func (Store) DueTimers

func (q Store) DueTimers(now int64, fn func(timerKey uint64, v *model.TimerValue) error) error

DueTimers calls fn for every timer whose due date is at or before now, in due order. Because the due date is the index prefix, this is a range scan from the start of the timer family up to now — no scheduler structure, no full scan.

func (Store) EachDecisionEvaluation

func (q Store) EachDecisionEvaluation(fn func(scopeKey uint64, ts int64, v *model.DecisionEvaluationValue) error) error

EachDecisionEvaluation folds every retained DMN decision evaluation across all process instances, calling fn with the owning scope (process instance) key, the evaluation's event timestamp, and its frozen record (ADR-0066). It scans the whole decision-evaluation column family — the global "which decisions ran, and how often" access pattern the Operations decisions overview uses, as opposed to DecisionEvaluationHistory, which folds a single instance's evaluations. The scan order is scope then timestamp then position; a caller that only aggregates by decision id does not depend on it.

func (Store) ElementInstancesOfProcess

func (q Store) ElementInstancesOfProcess(procKey uint64, fn func(elKey uint64) error) error

ElementInstancesOfProcess calls fn with the key of every element instance belonging to the given process instance, via the elByProc index.

func (Store) ElementLiveTokens

func (q Store) ElementLiveTokens(procDefKey uint64, fn func(elementId int32, count int64) error) error

ElementLiveTokens calls fn with each of a definition's elements that currently holds live tokens and how many — one prefix scan over the per-element token counters, so it is O(elements), not O(instances) (ADR-0080).

func (Store) ElementReplayHistory

func (q Store) ElementReplayHistory(piKey uint64, fn func(ts int64, pos uint64, v ElementReplayValue) error) error

ElementReplayHistory scans causal token lifecycle facts in deterministic order.

func (Store) ElementStepHistory

func (q Store) ElementStepHistory(piKey uint64, fn func(ts int64, pos uint64, elementId int32) error) error

ElementStepHistory folds the retained element-activation steps of one process instance, calling fn with each step's event timestamp, log position, and the activated element's compiled-graph index in the order they occurred (the step-by-step replay timeline, ADR-0046). Because the key sorts by timestamp then position, an instance-wide scan yields a monotonic sequence. The caller resolves the element index to a diagram id via the instance's compiled process.

func (Store) ElementTerminationHistory added in v0.5.0

func (q Store) ElementTerminationHistory(procDefKey, instanceFilter uint64, fn func(elementId int32, count int64) error) error

ElementTerminationHistory folds the token-termination counters for a process definition, calling fn with each element index and how many tokens were cancelled on it — the same scan shape as ElementVisitHistory, over the same key layout, so the two halves of "a token was here and left" are read identically. instanceFilter == 0 aggregates the definition's instances; a non-zero one isolates that instance.

func (Store) ElementTerminationTotals added in v0.5.0

func (q Store) ElementTerminationTotals(procDefKey uint64, fn func(elementId int32, count int64) error) error

ElementTerminationTotals calls fn with each of a definition's elements and how many tokens left it cancelled rather than completed — the counterpart of ElementVisitTotals, read the same way in O(elements) from a maintained counter (ADR-0080, ADR-0249). An element nothing was ever cancelled on is absent, so a caller that folds this over the visit totals leaves it at zero.

func (Store) ElementVisitHistory

func (q Store) ElementVisitHistory(procDefKey, instanceFilter uint64, fn func(elementId int32, count int64) error) error

ElementVisitHistory folds the token-visit counters for a process definition, calling fn with each visited element index and how many tokens have passed through it. With instanceFilter == 0 it aggregates every instance of the definition (the heatmap the live overlay draws in gray); with a non-zero instanceFilter it reports only that one instance's visits. Because the key ends with the element index and the same element sits under a distinct instance-key prefix per instance, a definition-wide scan can report the same element index once per instance — the caller sums the counts. Pebble folds the merge deltas for each key, so raw carries the current total for that key.

func (Store) ElementVisitTotals

func (q Store) ElementVisitTotals(procDefKey uint64, fn func(elementId int32, count int64) error) error

ElementVisitTotals calls fn with each of a definition's elements and its cumulative visit count — the aggregate heatmap, read in O(elements) from the maintained per-element visit counter instead of summing every instance's visit history (ADR-0080, aggregating ADR-0022).

func (Store) FinishedInstancesOfDefDesc added in v0.5.0

func (q Store) FinishedInstancesOfDefDesc(procDefKey uint64, beforeCompletedAt int64, beforeKey uint64, fn func(key uint64, v *model.ProcessInstanceValue) error) error

FinishedInstancesOfDefDesc calls fn with every finished instance of one definition in DESCENDING completion order — most recently finished first — starting just below the (beforeCompletedAt, beforeKey) cursor; a zero cursor starts from the most recent. It is the history counterpart of [queries.ActiveInstancesOfDefDesc], and it gets that order from the index key rather than by sorting the history in memory — which is what [queries.CompletedProcessInstancesDesc] cannot do, since the history family is in key order and an instance started first can finish last.

The cursor is a pair for that same reason. fn receives the value, whose CompletedAt together with the key forms the cursor for the next page.

func (Store) GetElementInstance

func (q Store) GetElementInstance(key uint64) (*model.ElementInstanceValue, bool, error)

GetElementInstance returns the committed element instance for key, reporting whether it was present. Like GetJob it reads outside a transaction, for consumers such as the in-process DMN worker resolving the decision an activatable business-rule job belongs to.

func (Store) GetIncident

func (q Store) GetIncident(elKey uint64) (*model.IncidentValue, error)

GetIncident returns the committed incident on an element instance, or nil if there is none. It reads outside a transaction, for the resolve endpoint's existence check (ADR-0061).

func (Store) GetJob

func (q Store) GetJob(key uint64) (*model.JobValue, bool, error)

GetJob returns the committed job for key, reporting whether it was present. Unlike Tx.GetJob it reads outside a transaction, for queries such as a worker runner pulling activatable jobs.

func (Store) IncidentCount added in v0.3.0

func (q Store) IncidentCount() (int, error)

IncidentCount returns how many unresolved incidents exist — how many tokens are parked waiting for an operator (ADR-0061). Counted from state by walking the incident family's keys, not from a maintained counter: an incident leaves state two ways, resolved by an operator *and* dropped with the element instance it sits on (an instance cancel or an interrupting boundary event, which announce no resolution), so a maintained number would drift while a scan cannot. The family holds one key per stuck token, which is the population an operator is expected to keep near zero.

func (Store) Incidents

func (q Store) Incidents(fn func(elementKey uint64, v *model.IncidentValue) error) error

Incidents calls fn with the element-instance key and value of every unresolved incident — the operator "list incidents" access pattern (ADR-0061).

func (*Store) InjectCorruptDataObject added in v0.5.0

func (s *Store) InjectCorruptDataObject(scope uint64, name string) error

InjectCorruptDataObject writes an undecodable record under a scope's data object, and InjectCorruptDataObjectSnapshot one under its retained state trail. Like the injectors above they are test/tooling affordances only: they let a caller exercise the decode-error branches of DataObjectsOfScope and DataObjectSnapshotHistory, which the instance Data view depends on to report a 500 rather than serve a datum with a hole in its history — a trail missing its middle reads as a value that never passed through a state it did. Production writes data objects through Tx.PutDataObject and Tx.RecordDataObjectSnapshot, never these.

func (*Store) InjectCorruptDataObjectSnapshot added in v0.5.0

func (s *Store) InjectCorruptDataObjectSnapshot(scope uint64, ts int64, pos uint64) error

func (*Store) InjectCorruptElementInstance

func (s *Store) InjectCorruptElementInstance(key uint64) error

InjectCorruptElementInstance writes an undecodable record under an element instance's key. Like InjectCorruptProcessInstance it is a test/tooling affordance only — it lets a caller in another package exercise the decode-error path of a GetElementInstance read (e.g. the set-variables handler's scope validation). Production code writes element instances through Tx.PutElementInstance, never this.

func (*Store) InjectCorruptIncident

func (s *Store) InjectCorruptIncident(elKey uint64) error

InjectCorruptIncident writes an undecodable record under an incident's key — the incident-list counterpart of InjectCorruptProcessInstance. It lets a caller exercise the decode-error branch of the incident scan (Incidents), which the operator "what's stuck" list depends on to surface a 500 rather than silently drop rows. Test/tooling only; production writes incidents through Tx.PutIncident.

func (*Store) InjectCorruptProcessInstance

func (s *Store) InjectCorruptProcessInstance(key uint64) error

InjectCorruptProcessInstance writes an undecodable record under a process instance's key. It is a test/tooling affordance only — it lets a caller in another package exercise the decode-error path of the active-instance scan (ActiveProcessInstances) that operator read/admin handlers depend on. Production code writes process instances through Tx.PutProcessInstance, never this.

func (Store) InstancesByVariable added in v0.5.0

func (q Store) InstancesByVariable(name, value string, prefix bool, fn func(piKey uint64) error) error

InstancesByVariable calls fn with the key of every process instance holding the given variable value — a seek into the value index, not a walk of the instances. It is the answer to the operator's real question ("where is MT-1998?"), and its cost is the number of matches plus a seek, whatever the engine holds.

prefix asks the other question an ordered index can answer: every value starting with value, rather than equal to it. Both are the same scan over a different bound — see [variableIndexExactPrefix] for why the exact one needs a terminator.

Only writes the instance's process declared searchable are in the index, and only since the declaration existed, so a caller that must not miss an older instance falls back to a content walk. The index never reports an instance that does not hold the value.

func (Store) InstancesOnElementDesc added in v0.5.0

func (q Store) InstancesOnElementDesc(procDefKey uint64, elementId int32, before uint64, fn func(key uint64, v *model.ProcessInstanceValue) error) error

InstancesOnElementDesc calls fn with every live instance of one definition that currently holds a token on the given element, in DESCENDING instance-key order — newest first — starting just below `before`; before == 0 starts from the newest.

It reads the piByEl index, so its cost is the answer and not the version: an element five instances are waiting on costs five reads whether the definition holds five instances or five hundred thousand. That is the whole point of the index — the alternative is testing every live instance of the version for a token on one element, which is a walk that grows with the population and would run on every poll of the Operations view (ADR-0080's rule, applied to a filter).

An instance is yielded once however many tokens it holds on the element: a loop or a multi-instance activity puts several there, and "which instances are on this task" is a question about instances. The entries of one instance are adjacent, so the de-duplication is a comparison with the previous key rather than a set.

fn may stop the walk early by returning a sentinel error, exactly as the by-definition walks do; the key of the last row it kept is the cursor for the next (older) page.

func (Store) JobOfElement

func (q Store) JobOfElement(elKey uint64) (uint64, bool, error)

JobOfElement returns the key of the job held by the given element instance, or ok=false if it holds none. It is the read-side counterpart of Tx.JobOfElement, used to resolve one instance's open jobs through the element→job reverse index rather than scanning the global activatable index.

func (Store) LastAppliedPosition

func (q Store) LastAppliedPosition() (uint64, error)

LastAppliedPosition returns the highest log position folded into committed state, or 0 if none has been applied yet (genesis).

func (Store) MessageFlowHistory

func (q Store) MessageFlowHistory(receiverDefKey uint64, fn func(ts int64, pos uint64, v *model.MessageFlowValue) error) error

MessageFlowHistory folds the retained message flows a definition received, calling fn with each flow's event timestamp, log position, and payload in the order they occurred (the replay timeline). Because the key sorts by timestamp then position, a definition-wide scan yields a monotonic sequence. The caller resolves the receiver element index to a diagram id via the compiled process.

func (Store) MessageSubscriptions added in v0.2.0

func (q Store) MessageSubscriptions() (int64, error)

MessageSubscriptions is how many message subscriptions are currently waiting to correlate, engine-wide.

func (*Store) NewTransaction

func (s *Store) NewTransaction() *Tx

NewTransaction starts a transaction. Reads through it see its own pending writes (it is an indexed batch). Mutations become visible only on Commit. The underlying batch is drawn from the store's cache when available, so steady- state processing does not allocate one (invariant I1).

func (Store) OpenJobs added in v0.2.0

func (q Store) OpenJobs() (int64, error)

OpenJobs is how many jobs are currently waiting for a worker, engine-wide, read from the maintained counter rather than by scanning the job family (ADR-0142).

func (Store) OperatorActionHistory added in v0.3.0

func (q Store) OperatorActionHistory(piKey uint64, fn func(ts int64, pos uint64, v *model.OperatorActionValue) error) error

OperatorActionHistory folds the retained operator interventions of one process instance, calling fn with each action's event timestamp, log position, and its frozen record (who acted, on which element, and why) in the order they occurred (ADR-0159). Like VariableAuditHistory the key sorts by timestamp then position, so the trail lines up with the step at which each intervention happened, and it surfaces both live and after the instance has finished since the records are append-only history.

func (Store) PendingTimers added in v0.2.0

func (q Store) PendingTimers() (int64, error)

PendingTimers is how many timers are currently waiting to fire, engine-wide.

func (Store) ProcessInstance

func (q Store) ProcessInstance(key uint64) (*model.ProcessInstanceValue, bool, error)

ProcessInstance returns the process instance for key and whether it was found, looking first in the active family and then in the terminal-history family (ADR-0017). It lets a query resolve an instance's definition whether it is still running or already finished — the lookup the single-process replay uses.

func (*Store) ReadView added in v0.3.0

func (s *Store) ReadView() *ReadView

ReadView takes a consistent read-only view. The caller owns it and must Close it.

This is deliberately not called Snapshot: Store.Snapshot already means the on-disk backup checkpoint (ADR-0107), and conflating a durable copy of the whole store with an in-memory read view would be a genuinely dangerous ambiguity.

func (*Store) Snapshot added in v0.2.0

func (s *Store) Snapshot(destDir string) error

Snapshot writes a consistent, durable snapshot of the store into destDir, which must not already exist (Pebble creates it). It is the state half of an engine recovery checkpoint (ADR-0131).

The memtable is flushed first, on purpose: ordinary transactions commit pebble.NoSync (ADR-0005) because the WAL's fsync is the durability point, so without the flush a snapshot could inherit that same trailing property and silently omit recently applied state. Flushing means the snapshot's files provably contain every write committed up to the caller's applied position.

Like every other Store method it is called on the owning partition goroutine (invariant I3) — for a checkpoint, at a batch boundary.

func (Store) StartTimers

func (q Store) StartTimers(fn func(timerKey uint64, v *model.TimerValue) error) error

StartTimers calls fn for every armed start timer — one whose owning process instance key is zero, so it instantiates a definition on fire rather than continuing a waiting element (ADR-0051). It is a full scan of the timer family, used only when a definition is (re)deployed (off the hot path), so arming can be idempotent and can supersede a prior version's schedule.

func (Store) TotalActiveInstances added in v0.2.0

func (q Store) TotalActiveInstances() (int64, error)

TotalActiveInstances is how many process instances are live across every definition, summed from the maintained per-definition counters (ADR-0080) rather than by walking the instance records.

The distinction is the whole point: the authoritative Store.ActiveProcessInstanceCount scans the runtime set, so it costs more the busier the engine is — fine for a request, wrong for something a Prometheus scrape takes every fifteen seconds. This sum reads one key per **deployed definition**, a number that changes only when someone deploys (ADR-0142).

One honest qualification, measured rather than assumed (BenchmarkTotalActiveInstances): these are *merge* counters, so a read also folds in whatever operands Pebble has not compacted yet — right after a burst of starts the sum costs O(recent writes), not O(definitions). A flush collapses them, after which the sum is flat regardless of how many instances are running: 2,000 instances read as fast as 100. Flushes happen on their own, and the ADR-0131 checkpoint cadence forces one every few minutes, so the backlog is bounded in a running engine. Even un-compacted it stays cheaper than the scan it replaces.

func (Store) TotalLiveTokens added in v0.2.0

func (q Store) TotalLiveTokens() (int64, error)

TotalLiveTokens is how many element instances hold live tokens across every definition, summed from the maintained per-definition-element counters (ADR-0080). Bounded by the number of deployed *elements* — design-time size, not runtime population — for the same reason as Store.TotalActiveInstances.

func (Store) VariableAuditHistory

func (q Store) VariableAuditHistory(piKey uint64, fn func(ts int64, pos uint64, v *model.VariableAuditValue) error) error

VariableAuditHistory folds the retained external variable overrides of one process instance, calling fn with each override's event timestamp, log position, and its frozen record (who set which variable, on which scope, to what value) in the order they occurred (ADR-0098). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence — the same ordering as the variable and decision timelines — so the "who changed it" trail lines up with the step at which each override happened. It surfaces to operators both live and after the instance has finished, since the records are append-only history.

func (Store) VariableSnapshotHistory

func (q Store) VariableSnapshotHistory(scopeKey uint64, fn func(ts int64, pos uint64, v *model.VariableValue) error) error

VariableSnapshotHistory folds the retained variable changes of one scope (a process instance), calling fn with each change's event timestamp, log position, and the variable's new state in the order they occurred (ADR-0048). Because the key sorts by timestamp then position, a scope-wide scan yields a monotonic sequence a caller folds by position to reconstruct the variables as of any step.

func (Store) VariablesOfScope

func (q Store) VariablesOfScope(scope uint64, fn func(v *model.VariableValue) error) error

VariablesOfScope calls fn with every variable owned by the given scope, via the variable column family. Used to build a FEEL evaluation scope and to surface an instance's variables to operators.

func (Store) VisibleVariablesOfScope added in v0.2.0

func (q Store) VisibleVariablesOfScope(scope uint64, fn func(v *model.VariableValue) error) error

VisibleVariablesOfScope calls fn with every variable *visible* at the given scope: the scope's own variables plus those inherited from each enclosing scope, walking up the FlowScopeKey chain to the process root, with the nearest scope winning when a name is shadowed. This mirrors the engine's variable visibility (ResolveVariable / bindInputsChain, ADR-0068): a token at an activity-local scope sees its locals over anything inherited. Passing the process-instance root key yields exactly the root's variables (it has no enclosing scope), so callers reading a root instance are unaffected.

It is the Reader-level VisibleVariables under a name that reads better at a call site holding a *Store; the walk itself lives there, shared with the worker workers.

type Tx

type Tx struct {
	// contains filtered or unexported fields
}

Tx is a state transaction: a set of mutations that commit atomically. It is an indexed Pebble batch, so reads through it observe its own pending writes.

func (*Tx) ActiveChildren

func (t *Tx) ActiveChildren(scope uint64) (int32, error)

ActiveChildren returns the active-child count for scope (0 if none). This read folds the merged deltas, so it is used only where the current count is needed (e.g. detecting a finished scope), not on every increment.

func (*Tx) ActiveStartKeyCount

func (t *Tx) ActiveStartKeyCount(defKey uint64, correlationKey string) (int32, error)

ActiveStartKeyCount returns how many live instances of defKey began with correlationKey (0 if none). It folds the merged deltas, so it is read only where the current count is needed — the singleton-start gate (ADR-0094), not on every merge.

func (*Tx) ChildInstancesOfParent added in v0.5.0

func (t *Tx) ChildInstancesOfParent(callElKey uint64, fn func(childPiKey uint64) error) error

ChildInstancesOfParent calls fn with the process instance key of every live child a call-activity element instance has started, as visible in this transaction — committed rows plus this batch's own writes.

The transactional view is the point. A caller and the child it starts can be created in one batch, and a cancellation arriving in that same batch has to tear down a child whose activation is applied but not yet committed. Reading the committed store there would report no children and leave the child running with no live caller. This is the same reason ElementInstancesOfProcess reads through the batch, and it stays deterministic for exactly the same reason: what the transaction has applied is a function of the records processed so far, not of when the commit happens.

The committed-store form on queries remains, as the off-loop and state-level query — it is what a test asserting the index's maintenance wants to read.

func (*Tx) Close

func (t *Tx) Close() error

Close releases the transaction, returning its batch to the store for reuse. Safe to call after Commit. The Tx must not be used afterward.

func (*Tx) Commit

func (t *Tx) Commit() error

Commit applies the transaction. It does not fsync: durability is the WAL's responsibility (ADR-0005), and the store is rebuildable by replay, so a state commit lost to a crash is simply re-derived on recovery.

func (*Tx) CompensablesOfScopeDesc

func (t *Tx) CompensablesOfScopeDesc(scopeKey uint64, fn func(seq uint64, v *model.CompensableValue) error) error

CompensablesOfScopeDesc calls fn for every completed compensable activity recorded under scopeKey, newest first (reverse completion order) — the order a compensation throw runs handlers in (ADR-0103). It reads through the in-flight batch, so it observes records written earlier in the same batch. seq is the record's key sequence (log position), which the caller carries on the consume event to delete it.

func (*Tx) CorrelatableSubscriptions

func (t *Tx) CorrelatableSubscriptions(name, correlationKey string, fn func(elKey uint64, v *model.MessageSubscriptionValue) error) error

CorrelatableSubscriptions calls fn for every open subscription matching the given (message name, correlation key), via a prefix scan — the publish access pattern. It reads through the in-flight batch, so it observes subscriptions created earlier in the same batch (ADR-0020).

func (*Tx) DecDefInstanceCount

func (t *Tx) DecDefInstanceCount(procDefKey uint64) error

func (*Tx) DecElementToken

func (t *Tx) DecElementToken(procDefKey uint64, elementId int32) error

func (*Tx) DecMessageSubscriptions added in v0.2.0

func (t *Tx) DecMessageSubscriptions() error

func (*Tx) DecOpenJobs added in v0.2.0

func (t *Tx) DecOpenJobs() error

func (*Tx) DecPendingTimers added in v0.2.0

func (t *Tx) DecPendingTimers() error

func (*Tx) DecrementActiveChildren

func (t *Tx) DecrementActiveChildren(scope uint64) error

DecrementActiveChildren removes one active child from scope. A scope that returns to zero leaves a zero-valued counter entry rather than being deleted; completion checks treat absent and zero alike.

func (*Tx) DecrementActiveStartKey

func (t *Tx) DecrementActiveStartKey(defKey uint64, correlationKey string) error

func (*Tx) DeleteCanceling

func (t *Tx) DeleteCanceling(txKey uint64) error

DeleteCanceling drops the cancelling marker for txKey when the transaction tears down (ADR-0108). Idempotent — a transaction that was never cancelled, or a plain subprocess that never carried a marker, is a no-op.

func (*Tx) DeleteChildByParent added in v0.5.0

func (t *Tx) DeleteChildByParent(callElKey, childPiKey uint64) error

DeleteChildByParent drops the reverse link when the child instance ends. Written on the child's terminal event, alongside dropping its active record, so a completed child never lingers in the index. Idempotent, like every delete here.

func (*Tx) DeleteCompensable

func (t *Tx) DeleteCompensable(scopeKey, seq uint64) error

DeleteCompensable removes one compensable record (its activity has been compensated), located by its scope and sequence — both carried on the consume event, so recovery deletes the identical entry. Idempotent.

func (*Tx) DeleteCompensablesOfScope

func (t *Tx) DeleteCompensablesOfScope(scopeKey uint64) error

DeleteCompensablesOfScope drops every compensable record held under a scope, called when the scope tears down (its subprocess container or process instance completes or is terminated) so uncompensated records never leak past the scope (ADR-0103). Keys are collected before deleting so the scan is not disturbed. Idempotent — a scope with none is a no-op.

func (*Tx) DeleteElementInstance

func (t *Tx) DeleteElementInstance(key uint64, v *model.ElementInstanceValue) error

DeleteElementInstance removes the element instance and its index entry. The value is required to locate the elByProc entry; on recovery it comes from the event payload.

func (*Tx) DeleteIncident

func (t *Tx) DeleteIncident(elKey uint64) error

DeleteIncident removes the incident attached to an element instance. Deleting one that is absent is a harmless no-op — how terminating an element clears any incident it carried without first reading it (ADR-0061).

func (*Tx) DeleteJob

func (t *Tx) DeleteJob(key uint64, v *model.JobValue) error

DeleteJob removes the job, its activatable index entry, and the reverse element→job entry. Errors are accumulated across the three batch deletes (first non-nil wins), keeping every delete on the same covered path.

func (*Tx) DeleteMessageSubscription

func (t *Tx) DeleteMessageSubscription(v *model.MessageSubscriptionValue) error

DeleteMessageSubscription removes a subscription. The value supplies the name, correlation key, and element-instance key that locate its index entry; on recovery they come from the event payload.

func (*Tx) DeleteProcessInstance

func (t *Tx) DeleteProcessInstance(key, procDefKey uint64) error

DeleteProcessInstance removes the process instance and its live by-definition index entry. The definition key is passed rather than read back from the record because every caller already holds the value it is retiring — the terminal fold builds the history record from it — so the index stays in step without a second read on the path an instance finishes on.

func (*Tx) DeleteSignalSubscription

func (t *Tx) DeleteSignalSubscription(v *model.SignalSubscriptionValue) error

DeleteSignalSubscription removes a signal subscription. The value supplies the name and element-instance key that locate its index entry; on recovery they come from the event payload.

func (*Tx) DeleteTimer

func (t *Tx) DeleteTimer(key uint64, v *model.TimerValue) error

DeleteTimer removes the timer. The value supplies the due date that locates its index key; on recovery it comes from the event payload.

func (*Tx) DeleteVariable

func (t *Tx) DeleteVariable(scope uint64, name string) error

DeleteVariable removes a variable from its scope by name. It is idempotent — deleting an absent variable is a no-op — and is used to drop an activity-local variable scope when the activity completes (ADR-0068).

func (*Tx) DropInstanceByElement added in v0.5.0

func (t *Tx) DropInstanceByElement(procDefKey uint64, elementId int32, piKey, elKey uint64) error

DropInstanceByElement removes one piByEl entry by the coordinates it was written under. It exists for migration, which re-puts an element instance under a different (definition, element) pair: the new entry is written by the re-put, and the old one has to be named to be dropped, because the record no longer carries where it used to be.

func (*Tx) ElementInstancesOfProcess

func (t *Tx) ElementInstancesOfProcess(procKey uint64, fn func(elKey uint64, v *model.ElementInstanceValue) error) error

ElementInstancesOfProcess calls fn for every element instance of a process instance visible in this transaction — committed rows plus this batch's own writes — via the elByProc index. A parallel join uses it to count how many tokens have arrived on its incoming flows, including one activated earlier in the same batch (which a committed-only store scan would miss).

func (*Tx) GetDataObject

func (t *Tx) GetDataObject(scope uint64, name string) (*model.DataObjectValue, error)

GetDataObject returns a scope's data object by name, or nil if absent.

func (*Tx) GetElementInstance

func (t *Tx) GetElementInstance(key uint64) (*model.ElementInstanceValue, error)

GetElementInstance returns the element instance, or nil if absent.

func (*Tx) GetElementInstanceInto

func (t *Tx) GetElementInstanceInto(key uint64, dst *model.ElementInstanceValue) (bool, error)

GetElementInstanceInto decodes the element instance into dst without allocating, reporting whether it was present.

func (*Tx) GetIncident

func (t *Tx) GetIncident(elKey uint64) (*model.IncidentValue, error)

GetIncident returns the incident attached to an element instance, or nil.

func (*Tx) GetJob

func (t *Tx) GetJob(key uint64) (*model.JobValue, error)

GetJob returns the job, or nil if absent.

func (*Tx) GetJobInto

func (t *Tx) GetJobInto(key uint64, dst *model.JobValue) (bool, error)

GetJobInto decodes the job into dst without allocating, reporting whether it was present.

func (*Tx) GetProcessInstance

func (t *Tx) GetProcessInstance(key uint64) (*model.ProcessInstanceValue, error)

GetProcessInstance returns the process instance, or nil if absent.

func (*Tx) GetProcessInstanceInto

func (t *Tx) GetProcessInstanceInto(key uint64, dst *model.ProcessInstanceValue) (bool, error)

GetProcessInstanceInto decodes the process instance into dst without allocating, reporting whether it was present.

func (*Tx) GetVariable

func (t *Tx) GetVariable(scope uint64, name string) (*model.VariableValue, error)

GetVariable returns a scope's variable by name, or nil if absent.

func (*Tx) InboundHighWater

func (t *Tx) InboundHighWater(sourceID string) (uint64, error)

InboundHighWater returns the last-applied sequence for a source, or 0 if the source has no mark yet. It reads through the in-flight batch, so a guard sees a mark written earlier in the same batch.

func (*Tx) IncDefCompletedCount

func (t *Tx) IncDefCompletedCount(procDefKey uint64) error

IncDefCompletedCount bumps a definition's finished-instance count by one, on each process-instance completion or termination. Monotonic (never decremented) — the count of finished instances only grows — so the summary's "finished" column reads in O(1) instead of scanning the history, which draining active instances only makes larger (ADR-0083).

func (*Tx) IncDefInstanceCount

func (t *Tx) IncDefInstanceCount(procDefKey uint64) error

IncDefInstanceCount and DecDefInstanceCount move a definition's active-instance count by one, on process-instance creation and termination.

func (*Tx) IncElementTerminationAgg added in v0.5.0

func (t *Tx) IncElementTerminationAgg(procDefKey uint64, elementId int32) error

IncElementTerminationAgg bumps a definition-element cumulative-termination count when a token leaves the element cancelled instead of completed. Never decremented — it is the retained historical half of the heatmap that says a token got here and then did *not* go on (ADR-0249).

func (*Tx) IncElementToken

func (t *Tx) IncElementToken(procDefKey uint64, elementId int32) error

IncElementToken and DecElementToken move a definition-element live-token count by one, on element-instance activation and completion/termination.

func (*Tx) IncElementVisitAgg

func (t *Tx) IncElementVisitAgg(procDefKey uint64, elementId int32) error

IncElementVisitAgg bumps a definition-element cumulative-visit count on activation. Never decremented — it is the retained historical heatmap.

func (*Tx) IncMessageSubscriptions added in v0.2.0

func (t *Tx) IncMessageSubscriptions() error

IncMessageSubscriptions and DecMessageSubscriptions move the count of subscriptions waiting to correlate, on subscription creation and on correlation.

func (*Tx) IncOpenJobs added in v0.2.0

func (t *Tx) IncOpenJobs() error

IncOpenJobs and DecOpenJobs move the count of jobs waiting for a worker, on job creation and on completion or cancellation. Re-putting a job (assigned, failed with a decremented retry count) moves nothing: the job was already open and still is.

func (*Tx) IncPendingTimers added in v0.2.0

func (t *Tx) IncPendingTimers() error

IncPendingTimers and DecPendingTimers move the count of timers waiting to fire, on timer creation and on trigger or cancellation.

func (*Tx) IncrementActiveChildren

func (t *Tx) IncrementActiveChildren(scope uint64) error

IncrementActiveChildren adds one active child to scope. It is a write-only merge (no read), so it does not allocate on the hot path (invariant I1).

func (*Tx) IncrementActiveStartKey

func (t *Tx) IncrementActiveStartKey(defKey uint64, correlationKey string) error

IncrementActiveStartKey / DecrementActiveStartKey maintain the count of live message-start instances of a definition that began with a correlation key (ADR-0094). Like the active-children counter they are write-only composing merges, so they neither read nor allocate beyond the reused scratch buffer, and rebuild identically on replay (I4/I6).

func (*Tx) IsCanceling

func (t *Tx) IsCanceling(txKey uint64) (bool, error)

IsCanceling reports whether the transaction scope txKey was marked cancelling by a cancel end event (ADR-0108). It reads through the in-flight batch, so it observes a mark written earlier in the same batch.

func (*Tx) JobOfElement

func (t *Tx) JobOfElement(elKey uint64) (uint64, bool, error)

JobOfElement returns the key of the job held by the given element instance, or ok=false if it holds none. Used to cancel a host activity's job when an interrupting boundary event terminates it.

func (*Tx) MigrateInstance added in v0.3.0

func (t *Tx) MigrateInstance(v *model.ProcessMigrationValue) error

MigrateInstance rebinds a running instance from one deployed version of its process to another (ADR-0162): the definition key it is bound to, and every element index its live records carry, translated through the mapping the migration event froze at command time. It is the whole fold — everything it touches, it touches here — so the live path and recovery replay produce the identical result (invariant I4).

Element instance keys are not translated and never change. That is the design, not an omission: variables, data objects, jobs, the active-children counts and the entire scope tree are keyed by element instance key, so preserving those keys is what lets all of them ride through a migration untouched.

What is rewritten is exactly what execution reads by *index*:

  • the instance's ProcessDefKey, and its per-definition active-instance counter;
  • each element instance's ProcessDefKey and ElementId, and the per-definition live-token counter that follows it (ADR-0080);
  • the correlation-key counter of a message-start instance (ADR-0094);
  • each incident's ElementId, which is what an operator surface resolves to a diagram element and, since ADR-0160, to the worker behind it;
  • each compensable record's ProcessDefKey, ElementId and HandlerNode — the handler node is dereferenced against the definition when compensation fires, so a stale one would activate an element from the version the instance has left.

Timers and message/signal subscriptions are deliberately *not* rewritten. Their element ids never drive execution: a due timer resolves its element through GetElementInstance(ElementInstanceKey) and a correlated message completes m.elKey's element instance, so both already follow the element instance this fold does rewrite. A recurring timer re-derives TargetElementId from the element instance the next time it arms, so it heals itself; and a subscription's ProcessDefKey and ElementId are copied together into the retained message-flow row, where the pair truthfully records the element as it was in the version the catch was armed under. Rewriting them would need a scan of all timers and all subscriptions per instance, which would make a batch migration quadratic, for values nothing reads to decide anything.

A mapping that does not cover an element index leaves that record alone rather than guessing: validation at command time is what guarantees no *live* record carries an uncovered index, and a fold that invented a target would be the one way this corrupts an instance beyond repair.

func (*Tx) PurgeInstanceHistory added in v0.2.0

func (t *Tx) PurgeInstanceHistory(piKey, procDefKey uint64, purgeDueDate int64) error

PurgeInstanceHistory hard-deletes a finished instance from the state store: the terminal history record and every per-instance history/live family addressable from the instance key (and its definition key), so no orphaned rows outlive it (ADR-0115). It touches no per-definition counter — the active count was already decremented at termination and the finished count is monotonic (ADR-0083). Every delete is idempotent (an absent key is a no-op), so a replayed or re-enqueued purge is safe. Called only from applyToState(IntentPurged), so it replays identically on recovery (I4/I6).

Not swept (by design, see ADR-0115): message-flow history (keyed by receiver definition, not instance) and incidents (an element key; a finished instance holds no live incident). Sub-scope variables/data objects that outlived their activity are not reached — a finished instance's live state is root-scoped (== the instance key) in practice.

func (*Tx) PutChildByParent added in v0.5.0

func (t *Tx) PutChildByParent(callElKey, childPiKey uint64) error

PutChildByParent records that a call-activity element instance started a child process instance (ADR-0076). It is the reverse of the child's own ParentElementInstanceKey: that field answers "who started me", this index answers "what did I start", which is the direction the engine needs when a call activity is terminated and must tear its child down with it.

Written from applyToState on the child's activation, from the child's own record, so replay rebuilds it identically (I4/I6).

func (*Tx) PutDataObject

func (t *Tx) PutDataObject(v *model.DataObjectValue) error

PutDataObject writes (upserts) a data object under its scope and name — the current value, mirroring PutVariable. The live store keeps only the latest; the whole state history lives in the snapshot family (ADR-0053).

func (*Tx) PutElementInstance

func (t *Tx) PutElementInstance(key uint64, v *model.ElementInstanceValue) error

PutElementInstance writes the element instance and its two index entries: the elByProc one (this instance's tokens) and the piByEl one (this element's instances). The second is the reverse direction, and it is what lets an operator ask "which instances are sitting on this task?" without walking the version.

func (*Tx) PutHistoryExpiry added in v0.2.0

func (t *Tx) PutHistoryExpiry(dueDate int64, piKey uint64) error

PutHistoryExpiry schedules a finished instance's hard delete at its purge due date (ADR-0146): CompletedAt + the definition's atlas:historyTtl, frozen on the terminal event and carried by it, so replay writes the identical entry. The entry has no value — the due date and the instance key are the key, and the instance's history record holds everything the purge needs. Written from applyToState only.

func (*Tx) PutInboundHighWater

func (t *Tx) PutInboundHighWater(sourceID string, seq uint64) error

PutInboundHighWater upserts an external event source's last-applied sequence. It writes the absolute sequence (not a delta), so a replayed IntentInbound- DeliveryApplied rebuilds the identical mark (invariant I4). Reads through the batch see it immediately, so the guard in the same batch observes it.

func (*Tx) PutIncident

func (t *Tx) PutIncident(v *model.IncidentValue) error

PutIncident writes an incident, keyed by the element instance it is attached to.

func (*Tx) PutJob

func (t *Tx) PutJob(key uint64, v *model.JobValue) error

PutJob writes the job, its activatable index entry, and the reverse element→job entry (so an interrupting boundary event can find the host's job). The writes go to one in-memory batch; their errors are accumulated (first non-nil wins) rather than checked one at a time, which keeps every write on the same covered path.

A job is on the activatable index iff it has retries left (Retries > 0): a job whose retries are exhausted stays stored — an incident points at it — but is never handed to a worker until an operator resolves the incident and restores a positive retry count (ADR-0061).

func (*Tx) PutMessageSubscription

func (t *Tx) PutMessageSubscription(v *model.MessageSubscriptionValue) error

PutMessageSubscription writes an open message subscription, keyed by its (name, correlationKey) match pair plus its element-instance key.

func (*Tx) PutProcessInstance

func (t *Tx) PutProcessInstance(key uint64, v *model.ProcessInstanceValue) error

PutProcessInstance writes the process instance and indexes it under its definition, so a version's running instances are a range scan rather than a filtered walk of every instance in the store.

The index entry is derived from the value's own ProcessDefKey, so it cannot disagree with the record, and writing it is an idempotent Set — a re-put of the same instance rewrites the same entry. An instance whose definition *changes* (a migration) is the one case that also needs the old entry dropped, and Tx.MigrateInstance does that where it moves the counters.

func (*Tx) PutProcessInstanceHistory

func (t *Tx) PutProcessInstanceHistory(key uint64, v *model.ProcessInstanceValue) error

PutProcessInstanceHistory records a terminal (completed/terminated) process instance in the history index. Written from applyToState when an instance ends, from the event alone, so it replays identically on recovery (ADR-0017).

func (*Tx) PutSignalSubscription

func (t *Tx) PutSignalSubscription(v *model.SignalSubscriptionValue) error

PutSignalSubscription writes an open signal subscription, keyed by its signal name plus its element-instance key. A signal has no correlation key — it matches by name alone (ADR-0088).

func (*Tx) PutTimer

func (t *Tx) PutTimer(key uint64, v *model.TimerValue) error

PutTimer writes the timer into the due-date index, which is its primary store.

func (*Tx) PutVariable

func (t *Tx) PutVariable(v *model.VariableValue) error

PutVariable writes (upserts) a process variable under its scope and name.

func (*Tx) RecordCompensable

func (t *Tx) RecordCompensable(pos uint64, v *model.CompensableValue) error

RecordCompensable retains one completed compensable activity under its scope, keyed by the completion event's log position so a scope scan yields completion order. pos comes from the event header; the value carries the scope, the compensated activity, and its compensation handler.

func (*Tx) RecordDataObjectSnapshot

func (t *Tx) RecordDataObjectSnapshot(ts int64, pos uint64, v *model.DataObjectValue) error

RecordDataObjectSnapshot retains one data-object state change under its scope, keyed in change order. ts and pos come from the event header; the value is the object's new state (name, data state, value). Written only from applyToState, from the event alone, so it rebuilds identically on replay (invariant I4); a plain Set on a unique (position-bearing) key, never overwritten (ADR-0053).

func (*Tx) RecordDecisionEvaluation

func (t *Tx) RecordDecisionEvaluation(ts int64, pos uint64, v *model.DecisionEvaluationValue) error

RecordDecisionEvaluation retains one decision evaluation under its owning process instance, keyed in evaluation order. ts and pos come from the event header; the value carries the decision id, input context, outputs, and trace.

func (*Tx) RecordElementReplay

func (t *Tx) RecordElementReplay(piKey uint64, ts int64, pos uint64, elementID int32, elementKey, tokenID, parentTokenID uint64, sourceFlowID int32, action byte) error

RecordElementReplay retains an activation or consumption with its durable token lineage. It is derived only from the lifecycle event by applyToState. action is one of ReplayActivated / ReplayCompleted / ReplayTerminated.

func (*Tx) RecordElementStep

func (t *Tx) RecordElementStep(piKey uint64, ts int64, pos uint64, elementId int32) error

RecordElementStep retains one element activation of a process instance under its instance key, keyed in time order. ts and pos come from the event header; the value is the activated element's compiled-graph index.

func (*Tx) RecordElementTermination added in v0.5.0

func (t *Tx) RecordElementTermination(procDefKey, piKey uint64, elementId int32) error

RecordElementTermination adds one to the termination counter for an element instance's element. Called from applyToState when an element instance is terminated — the losing branch of an event-based gateway, a scope torn down, an activity interrupted by a boundary event — so the retained heatmap can tell a token that completed here from one that was cancelled here. A write-only Merge like the visit counter beside it, so it neither reads nor allocates on the hot path (I1) and rebuilds identically on replay (I4).

func (*Tx) RecordElementVisit

func (t *Tx) RecordElementVisit(procDefKey, piKey uint64, elementId int32) error

RecordElementVisit adds one to the visit counter for an element instance's element. Called from applyToState when an element instance is activated.

func (*Tx) RecordMessageFlow

func (t *Tx) RecordMessageFlow(ts int64, pos uint64, v *model.MessageFlowValue) error

RecordMessageFlow retains one delivered message flow under its receiver definition, keyed in time order. ts and pos come from the event header.

func (*Tx) RecordOperatorAction added in v0.3.0

func (t *Tx) RecordOperatorAction(ts int64, pos uint64, v *model.OperatorActionValue) error

RecordOperatorAction retains one operator intervention under its owning process instance, keyed in the order it happened (ADR-0159). ts and pos come from the event header; the value carries who acted, on which element, and why. Written only from applyToState, from the event alone, so it rebuilds identically on replay (invariant I4); a plain Set on a unique (position-bearing) key, never overwritten.

func (*Tx) RecordVariableAudit

func (t *Tx) RecordVariableAudit(ts int64, pos uint64, v *model.VariableAuditValue) error

RecordVariableAudit retains one external variable override under its owning process instance, keyed in change order (ADR-0098). ts and pos come from the event header; the value carries who set the variable, on which scope, and to what value. Written only from applyToState, from the event alone, so it rebuilds identically on replay (invariant I4); a plain Set on a unique (position-bearing) key, never overwritten.

func (*Tx) RecordVariableSnapshot

func (t *Tx) RecordVariableSnapshot(ts int64, pos uint64, v *model.VariableValue) error

RecordVariableSnapshot retains one variable change under its scope, keyed in change order. ts and pos come from the event header; the value is the variable's new state (name, kind, value).

func (*Tx) SetCanceling

func (t *Tx) SetCanceling(txKey uint64) error

SetCanceling marks the transaction scope txKey as cancelling: a cancel end event fired in it, so when its scope drains the transaction routes out its cancel boundary rather than completing normally (ADR-0108). It is derived in applyToState from the cancel end event's committed Completed event, so it rebuilds identically on replay (I4/I6). The value is a single non-empty byte; only presence is meaningful.

func (*Tx) SetDefLastActivity

func (t *Tx) SetDefLastActivity(procDefKey uint64, unixNano int64) error

SetDefLastActivity records a definition's most recent instance-event timestamp by overwrite (ADR-0083). The processor's event timestamps are non-decreasing in log order, so the last write is the latest and replay rebuilds the identical value (invariant I4). Write-only, no read.

func (*Tx) SetLastAppliedPosition

func (t *Tx) SetLastAppliedPosition(pos uint64) error

SetLastAppliedPosition records, within this transaction, the highest log position folded into state. Committed atomically with the mutations so state and position never diverge.

func (*Tx) SubscribedSignals

func (t *Tx) SubscribedSignals(name string, fn func(elKey uint64, v *model.SignalSubscriptionValue) error) error

SubscribedSignals calls fn for every open subscription waiting on the given signal name, via a name-only prefix scan — the broadcast access pattern. Like CorrelatableSubscriptions it reads through the in-flight batch, so it observes subscriptions created earlier in the same batch (ADR-0088).

func (*Tx) VariablesOfScope

func (t *Tx) VariablesOfScope(scope uint64, fn func(v *model.VariableValue) error) error

VariablesOfScope calls fn with every variable owned by scope, via a prefix scan over the variable column family. It reads through the in-flight batch, so it observes variables written earlier in the same batch. A message throw event uses it to gather the payload it publishes (ADR-0035).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL