Malachi.Cluster.PolicyRegistry (malachi v0.22.7)

View Source

The pure state of the cluster's storage policies: the named definitions an administrator writes, replicated by Malachi.Cluster.PolicyMachine over a dedicated ra cluster.

Why they do not live in the metadata

A policy is an administrative object bound to topics, not state a vnode owns. Malachi used to keep the definitions inside each vnode's Malachi.Metadata, which had a defect built into it: a topic moving between vnodes carries the policy NAME it points at, and the definition stayed behind, so after a vnode split the topic silently fell back to the global retention and lost its placement spread. One definition for the cluster removes that by construction rather than by copying it around.

What stays in Malachi.Metadata is the binding, {:bind_topic_policy, topic, name}: which policy a topic points at is a fact about that topic and travels with it.

A definition is validated by Malachi.Cluster.Policy before it is stored, so every replica agrees on what a policy is. Pure: no clock, no config.

Summary

Functions

Every definition, as a map from name to policy. What a retention sweep resolves against once per pass.

Applies a command at the group's effective machine version, returning {new_state, reply}.

Every command shape, mapped to the machine version that introduced it (see Malachi.Cluster.MachineVersion).

The policy named name, or nil when no such policy is defined.

An empty registry.

Types

command()

@type command() ::
  {:define_policy, Malachi.Cluster.Policy.name(), Malachi.Cluster.Policy.t()}
  | {:delete_policy, Malachi.Cluster.Policy.name()}

t()

@type t() :: %Malachi.Cluster.PolicyRegistry{
  policies: %{
    required(Malachi.Cluster.Policy.name()) => Malachi.Cluster.Policy.t()
  }
}

Functions

all(policy_registry)

@spec all(t()) :: %{
  required(Malachi.Cluster.Policy.name()) => Malachi.Cluster.Policy.t()
}

Every definition, as a map from name to policy. What a retention sweep resolves against once per pass.

apply(state, arg2, version)

@spec apply(t(), command(), non_neg_integer()) :: {t(), term()}

Applies a command at the group's effective machine version, returning {new_state, reply}.

:define_policy is last-write-wins on a name, which is what an administrator editing a policy means. The definition is validated against the fields version admits (Malachi.Cluster.Policy.validate/3), never against what this build knows: version is replicated, so every member reaches the same answer while some still run older code. A field above it is refused as {:unsupported_policy_field, name, since, version}, anything else that is not a policy as :invalid_policy.

:delete_policy is idempotent and does not look for topics pointing at the name: a topic whose policy is undefined holds its data (see Malachi.Cluster.Retention.effective/4), and making the delete conditional on a scan of every vnode's topics is not something this registry can do. The admin facade checks for bound topics before it submits one (Malachi.Policies.delete/3).

command_versions()

Every command shape, mapped to the machine version that introduced it (see Malachi.Cluster.MachineVersion).

get(policy_registry, name)

The policy named name, or nil when no such policy is defined.

new()

@spec new() :: t()

An empty registry.