Fief.Vnode.Agent (Fief v0.1.0)

Copy Markdown View Source

One gen_statem per owned vnode (implementation.md §6.3): registered under the bounded-atom name minted by Fief.Seam.vnode_name/2 (the manager mints it in its own — sim-bound — process and passes it in), holding {impl_module, impl_state} and running impl callbacks in-process. A vnode serializes at its agent; impl exceptions crash the agent and the manager's restart cold-starts it (implementation.md §2).

States: :serving, :donor (lost ownership, open session, impl draining). The impl state persists across handoff transitions within one agent lifetime; handoff_out/handoff_in are delivered in authoritative-observation order.

What this process enforces (implementation.md §6.2)

  • Ownership validation before every handle_message: an ETS read of Fief.Node's published state plus the cached table row — the node's own last-observed truth. The gates, in order: no provable live lease (lease_live? false — the arbiter said :expired, or the node fenced) → the message is dropped silently, a fencing node must be inert; live lease but not (row.owner == me and :serving) → reply {:moved, epoch, delta}. What this deliberately does NOT catch: an authority-side move this node has not yet observed — the old owner keeps serving until it observes the bump (hint, poll, or first peer message). That is design §6.3's flip window (freeze happens on observation, step 2), bounded by the live-lease gate, and per-key authority during the window is the impl's obligation via the session protocol. The epoch in :msg envelopes is diagnostics, never an equality check (design §5.4).
  • The session envelope: handle_peer payloads are delivered only when the session matches the agent's authoritative view — the session recorded at its last handoff observation. A lower-epoch session is dropped outright; an unknown session forces an authority re-read (hints accelerate, never authorize — design §6.3 step 3), and only an authoritative match delivers. A donor that first learns of the transfer from a verified peer message freezes right there: handoff_out runs before the impl sees the payload (the spec's ServePull refresh-and-freeze). Dropped messages are never acknowledged — the transport half of ⊨ rule 6.
  • Settle only via Fief.Vnode.report_drained/1 — relayed to the settle-relay name; see Fief.Vnode.
  • Fencing: {:fief_fence, deadline_ms} from the manager runs the advisory handle_fence/2; if it returns, the agent stops normally — the manager's deadline kill (:brutal_kill) happens regardless and is the only bounded mechanism.
  • The impl-message channel (M6 contract change): non-framework messages — impl-process reports, :DOWN for impl-held monitors, the impl's own seam-timer {:timeout, ref, msg}s — are delivered to the impl's optional handle_info/2 under the same checkpoint discipline; see Fief.Vnode.handle_info/2 for the exact routing rule.

Follows THE M3 process discipline: sim context bound at init, every event handling ends with the :handled checkpoint via try/after, no :next_event, no raw timers, stale-timer catch-all.

Summary

Functions

child_spec(opts)

start_link(opts)