Lockstep.Controller (Lockstep v0.1.0)

Copy Markdown View Source

The scheduler. A GenServer that intercepts every Lockstep sync point and picks the next process to run per the configured strategy.

Invariant: at most one managed process is running locally between sync points. All others are blocked in GenServer.call. A freshly spawned child is unmanaged until it makes its first hello call.

See Lockstep.Strategy for the pluggable scheduling strategies.

Summary

Functions

Returns a specification to start this module under a supervisor.

Look up an ETS table by atom_name on caller_pid's node. Returns the underlying tid (an :ets reference) or :undefined.

Register an ETS tid under atom_name on caller_pid's node. Idempotent — re-registering the same name overwrites.

Remove the ETS-name binding atom_name on caller_pid's node.

Heal all active partitions; drains deferred messages.

Monitor a node from mon_pid. When node goes down, mon_pid receives {:nodedown, node}. Mirrors Node.monitor/2.

Look up the node a managed pid belongs to.

List all registered cluster nodes (always includes :nonode@nohost).

List currently-up nodes (excludes :nonode@nohost).

Add a partition between two groups of nodes. While active, cross-group sends are dropped (:drop) or queued for later delivery (:defer).

Register a notional cluster node by atom name. Subsequent spawns with node: name are tagged accordingly. Idempotent.

Register target_pid under name on target_pid's notional node. Returns :yes on success, {:already, existing} if the name is taken on that node, or {:already, existing} if target_pid is already registered under another name on that node.

List all names registered on caller_pid's node.

Set the virtual net_ticktime (default 15000ms). Determines how long after a partition the cross-partition monitors fire :DOWN with reason :noconnection.

Bring a previously-stopped node back up. Fresh state.

Stop a node: kills all its processes, fires :nodedown to monitors, marks the node as :down.

Unregister name on caller_pid's node. Returns :ok whether or not the name was registered.

Look up name on caller_pid's notional node. Returns the pid or :undefined. Mirrors Process.whereis/1 but per-node.

Look up name on a specific node. Returns the pid or :undefined. Used by Lockstep.send({name, node}, msg) and Lockstep.GenServer.cast({name, node}, msg) to route cross-node by-name sends correctly.

Cluster-wide name registry (mirror of Erlang's :global). Atomic register-or-fail: first caller wins, the rest see :no.

Generic NIF sync point. Used by Lockstep.ETS, Lockstep.Atomics, and Lockstep.PersistentTerm to make NIF-backed shared-state operations interleavable. The wrapper does the actual NIF call after this returns; the sync point itself just yields to the strategy and records a trace event.

Functions

alive?(ctl, caller_pid, target_pid)

await_done(ctl, timeout \\ :infinity)

cancel_timer(ctl, sender, ref)

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

cluster_ets_lookup(ctl, caller_pid, atom_name)

Look up an ETS table by atom_name on caller_pid's node. Returns the underlying tid (an :ets reference) or :undefined.

cluster_ets_register(ctl, caller_pid, atom_name, tid)

Register an ETS tid under atom_name on caller_pid's node. Idempotent — re-registering the same name overwrites.

cluster_ets_unregister(ctl, caller_pid, atom_name)

Remove the ETS-name binding atom_name on caller_pid's node.

cluster_heal(ctl)

Heal all active partitions; drains deferred messages.

cluster_monitor_node(ctl, mon_pid, node)

Monitor a node from mon_pid. When node goes down, mon_pid receives {:nodedown, node}. Mirrors Node.monitor/2.

cluster_node_of(ctl, pid)

Look up the node a managed pid belongs to.

cluster_nodes(ctl)

List all registered cluster nodes (always includes :nonode@nohost).

cluster_nodes_up(ctl)

List currently-up nodes (excludes :nonode@nohost).

cluster_partition(ctl, group_a, group_b, mode \\ :drop)

Add a partition between two groups of nodes. While active, cross-group sends are dropped (:drop) or queued for later delivery (:defer).

cluster_register(ctl, name)

Register a notional cluster node by atom name. Subsequent spawns with node: name are tagged accordingly. Idempotent.

cluster_register_name(ctl, target_pid, name)

Register target_pid under name on target_pid's notional node. Returns :yes on success, {:already, existing} if the name is taken on that node, or {:already, existing} if target_pid is already registered under another name on that node.

cluster_registered_names(ctl, caller_pid)

List all names registered on caller_pid's node.

cluster_set_ticktime(ctl, ms)

Set the virtual net_ticktime (default 15000ms). Determines how long after a partition the cross-partition monitors fire :DOWN with reason :noconnection.

cluster_start_node(ctl, node)

Bring a previously-stopped node back up. Fresh state.

cluster_stop_node(ctl, node)

Stop a node: kills all its processes, fires :nodedown to monitors, marks the node as :down.

cluster_unregister_name(ctl, caller_pid, name)

Unregister name on caller_pid's node. Returns :ok whether or not the name was registered.

cluster_whereis_name(ctl, caller_pid, name)

Look up name on caller_pid's notional node. Returns the pid or :undefined. Mirrors Process.whereis/1 but per-node.

cluster_whereis_on(ctl, node, name)

Look up name on a specific node. Returns the pid or :undefined. Used by Lockstep.send({name, node}, msg) and Lockstep.GenServer.cast({name, node}, msg) to route cross-node by-name sends correctly.

demonitor(ctl, monitor_pid, ref, opts)

exit_msg(ctl, pid, reason)

flag(ctl, caller_pid, flag, value)

global_register_name(ctl, name, pid)

Cluster-wide name registry (mirror of Erlang's :global). Atomic register-or-fail: first caller wins, the rest see :no.

global_registered_names(ctl)

global_unregister_name(ctl, name)

global_whereis_name(ctl, name)

hello(ctl, pid \\ nil)

link(ctl, caller_pid, target_pid)

monitor(ctl, monitor_pid, target_pid)

nif_sync(ctl, pid, kind)

Generic NIF sync point. Used by Lockstep.ETS, Lockstep.Atomics, and Lockstep.PersistentTerm to make NIF-backed shared-state operations interleavable. The wrapper does the actual NIF call after this returns; the sync point itself just yields to the strategy and records a trace event.

kind is a small descriptor (typically {:ets_insert, table_name} or similar) that gets recorded as {:nif, pid, kind} in the trace.

now(ctl, pid \\ nil)

recv_match(ctl, pid, matcher)

recv_msg(ctl, pid)

request_spawn(ctl, parent, fun, opts \\ [])

request_spawn_link(ctl, parent, fun, opts \\ [])

send_after(ctl, sender, target, msg, delay)

send_msg(ctl, from, to, msg)

spawn_root(ctl, fun, timeout \\ :infinity)

start_link(opts)

status(ctl)

trace(ctl)

unlink(ctl, caller_pid, target_pid)