Skip to content

Mutation

Mutations in Actionbase allow you to insert, update, and delete edges in your graph. The mutation process ensures data consistency, durability, and write-time optimization.

For the conceptual foundation, see Core Concepts.

The complete mutation process:

flowchart TD
    Request([Mutation Request
with Event, Operation]) --> WAL[Write WAL] WAL --> Lock[Acquire Lock] Lock --> Read[Read State
from datastore] Read --> Modify{State exists?} Modify -->|Yes| ApplyEvent[Apply Event] Modify -->|No| InitialState[Initial State] InitialState --> ApplyEvent ApplyEvent --> ComputeAdditionalInfo[Compute Index, Count
based on changed States] ComputeAdditionalInfo --> Write[Write State with AdditionalInfo
to datastore] Write --> Release[Release Lock] Release --> CDC[Write CDC] CDC --> Response([Response])

A mutation request contains:

  • Event: The data change to be applied (e.g., new property values, edge creation)
  • Operation: The type of operation:
    • Insert: Create a new edge
    • Update: Modify an existing edge
    • Delete: Remove an edge

Before any changes are made to the datastore, the mutation is written to the Write-Ahead Log (WAL). This ensures durability and enables recovery in case of failures.

In production, Actionbase uses Kafka as the WAL backend. The WAL can be replayed to restore the final state, even if events arrive out of order.

To prevent concurrent modifications, Actionbase acquires a lock on the specific edge being mutated:

  • Unique edges: Locks based on (source, target) pair
  • Multi edges: Locks based on edge ID

The current state of the edge is read from the datastore, including all existing properties, timestamps, and metadata.

The event is applied to the state, transitioning it based on the operation type:

  • INSERT: Updates createdAt timestamp and sets properties. The state becomes active when createdAt > deletedAt.
  • UPDATE: Updates only the specified properties without changing timestamps.
  • DELETE: Updates deletedAt timestamp and marks properties as deleted. The state becomes inactive when deletedAt >= createdAt.

The transition respects version ordering—newer versions override older ones.

Based on the changed state, Actionbase computes additional structures for fast reads:

  • Indexes: Old indexes are deleted, new indexes are created based on the changed state
  • Counters: Counts are incremented or decremented

This write-time optimization ensures read queries can be answered quickly without expensive computations.

The modified state along with indexes and counters is written atomically to the datastore.

Once the write is complete, the lock is released.

The mutation is recorded in the CDC system for downstream systems. In production, Actionbase uses Kafka as the CDC backend.

CDC stores the resulting state after processing, enabling synchronization to external systems (e.g., Iceberg, MPP, Trino) for analytics.

Clients attach timestamps to events (typically millisecond or nanosecond precision). Even if network delays cause events to arrive out of order, Actionbase uses the original timestamps to compute the correct final state.

Example: If ON/OFF events arrive as ON, OFF, ON, OFF but were originally ON, ON, OFF, OFF, Actionbase ensures the final state is correct based on timestamps.

This mechanism ensures eventual consistency—the final state is always correct regardless of event arrival order.

During mutations, Actionbase pre-computes:

StructurePurposeQuery Type
EdgeStateCurrent edge stateGet
EdgeIndexSorted index entriesScan
EdgeCounterAggregated countsCount

Benefits:

  • Fast Reads: No query-time computation needed
  • Consistent Performance: Read latency remains low regardless of data size
  • Efficient Storage: Indexes and counters are maintained incrementally

By computing at write time, Actionbase shifts computational cost from reads to writes—ideal for read-heavy workloads.

The mutation process ensures consistency through:

MechanismGuarantee
LockingPrevents concurrent modifications
Atomic WritesState and indexes written together
WALDurability and recovery
Read-Modify-WriteMutations based on latest state
Timestamp OrderingCorrect final state despite out-of-order events