Malachi. Cluster. SelfHealing
(malachi v0.8.13)
View Source
Closes the self-healing loop for sealed segments: the decision comes from
Malachi.Cluster.Placement and the execution from Malachi.Cluster.Catchup.
Given the current Malachi.Metadata, the set of live brokers, and the replication factor,
heal_sealed/4 finds the sealed segments that are under-replicated (a replica left), picks the
healed replica set with Placement.place/3, and backfills each newly added replica with the
segment's records (copied from a surviving replica via Catchup.run/6). It returns the
:set_segment_replicas commands whose backfill succeeded, for the caller to apply through the
control plane (Malachi.Metadata / the replicated DS-RSM), plus any segments it could not heal.
Only sealed segments are handled here: their offset range [start_offset, start_offset + length) is fixed, so a backfill is a well-defined copy. The active segment grows as it is
written, so a follower that falls behind on it rejoins via the write-path catch-up trigger (a
separate slice) rather than a one-shot backfill.
Brokers are Malachi.Cluster.ReplicationServer references. The live-broker set is supplied by
the caller (membership is a separate concern); a segment whose every replica is dead cannot be
backfilled and is reported as failed rather than silently dropped.
Besides the metadata-level pass, heal_sealed/4 also runs a physical integrity pass over
sealed segments whose replica set looks healthy: a live node can lose a sealed copy without the
metadata noticing (a deleted or truncated file, a swapped disk), leaving the cluster silently
below its replication factor while every replica is "alive". The pass probes each live replica's
stored bytes (Malachi.Cluster.ReplicationServer.stored_bytes/3, a read-only stat that never
opens the log, so steady state costs no descriptors); only a replica whose bytes fall short of
the sealed byte_size is then opened for its exact durable end
(Malachi.Cluster.ReplicationServer.durable_end/4) and re-backfilled from an intact replica via
Malachi.Cluster.Catchup, resuming at the truncation point rather than recopying the segment.
In-place corruption that keeps the byte size is out of this probe's reach by construction, since it
compares sizes: that is what Malachi.Cluster.Scrubber verifies checksums for.
Summary
Functions
Backfills and heals every under-replicated sealed segment. Returns %{applied: commands, failed: [{segment_id, reason}]}, applied are :set_segment_replicas commands to apply
through the control plane; failed segments could not be backfilled (e.g. :no_live_source).
Types
@type result() :: %{ applied: [Malachi.Metadata.command()], failed: [{Malachi.Metadata.segment_id(), term()}], repaired: [{Malachi.Metadata.segment_id(), Malachi.Metadata.broker()}] }
Functions
@spec heal_sealed( Malachi.Metadata.t(), [Malachi.Metadata.broker()], pos_integer(), keyword() ) :: result()
Backfills and heals every under-replicated sealed segment. Returns %{applied: commands, failed: [{segment_id, reason}]}, applied are :set_segment_replicas commands to apply
through the control plane; failed segments could not be backfilled (e.g. :no_live_source).
Options
:batch_size- forwarded toMalachi.Cluster.Catchup.run/6.:spread-{attribute_key, attributes}forwarded toPlacement.place/4so re-replication stays rack/DC-aware. Best-effort only: any:min_domains/:policyis intentionally not forwarded: healing prioritises durability and never fails a re-replication for domain diversity.