Bedrock.DataPlane.Log.Shale.Pushing (bedrock v0.6.0)

View Source

Predecessor scheduling and WAL appends, expressed as one uniform transition.

This module owns WAL and resource state only. It never replies to a caller, never forwards to the Demux, and never notifies a puller — every push/4 returns the same transition shape, and Shale.Server interprets it exactly once:

  • state — the resulting WAL state.
  • appended — the append events, in predecessor-chain order. Each is {version, encoded_transaction} (the exact bytes written), which is everything Demux delivery and puller notification need.
  • replies — ordered {token, result} instructions. Tokens are the opaque values callers were parked or presented with; this module never looks inside them and never invokes anything.
  • parked? — whether the current request was stored to wait for its predecessor (no reply owed yet).

The tuple-arity protocol this replaces encoded whether replies had already been sent in the shape of the return value; the server had to know which shapes had which side effects. Now the effects are data.

Summary

Functions

The single-entry, effect-free WAL append primitive.

Schedules one live push and returns the resulting transition.

Types

append_event()

reply_instruction()

@type reply_instruction() :: {reply_token(), :ok | {:error, term()}}

reply_token()

@type reply_token() :: term()

transition()

@type transition() :: %{
  state: Bedrock.DataPlane.Log.Shale.State.t(),
  appended: [append_event()],
  replies: [reply_instruction()],
  parked?: boolean()
}

wal_limit_error()

@type wal_limit_error() ::
  {:recovery_required,
   {:wal_limit_exceeded,
    %{
      commit_version: Bedrock.version(),
      min_durable_version: Bedrock.version(),
      last_version: Bedrock.version(),
      lag_us: pos_integer(),
      limit_us: non_neg_integer()
    }}}

Functions

append_transaction(t, encoded_transaction)

The single-entry, effect-free WAL append primitive.

Appends one encoded transaction — allocating or rolling segments as needed — and returns the new state with the append event, or the error with the caller's state intact. The WAL acknowledgement boundary is here: a returned event means the bytes and their sync completed. No caller reply, no Demux cast, no puller notification.

Recovery replays through this directly: its source stream is already validated and strictly ordered, so it needs the append, not the scheduler.

push(t, expected_version, encoded_transaction, token)

Schedules one live push and returns the resulting transition.

Covers immediate success, parking behind a missing predecessor, rejection (locked, oversized, stale, backpressured), ordered multi-entry drains of the pending queue, and partial-drain failure — all in the same shape.