Skip to content

refactor(heal): remove the dead MRF heal-type path - #6275

Merged
houseme merged 4 commits into
mainfrom
pr8-remove-dead-mrf-path
Aug 19, 2026
Merged

refactor(heal): remove the dead MRF heal-type path#6275
houseme merged 4 commits into
mainfrom
pr8-remove-dead-mrf-path

Conversation

@houseme

@houseme houseme commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Related Issues

N/A (follow-up of the backlog#1862 heal/scanner audit review)

Summary of Changes

Removes ~930 lines of dead heal path: the HealType::MRF task kind ("metadata repair file", a #1664-era construct) and the whole event.rs HealEvent pipeline. HealType::MRF's only production constructor lived in the HealEvent-to-HealRequest converter, and the HealEvent/HealEventHandler queue itself had zero production references — both were superseded by the MrfIntent pipeline (mrf_queue.rs), whose consumer produces Object/Metadata/ECDecode requests and never an MRF task. The dead path nevertheless carried the entire event.rs module (683 lines), the heal_mrf executor, a dedup-key arm, an overlap arm with the \u{0}mrf sentinel-bucket hack, per-kind labels, two event-name constants, an empty MrfRuntime::record_accept shell, and four event-only tests. This also resolves the in-crate naming clash where "MRF" denoted both the dead task kind and the live mission-repair-feed loop; the loop stays, the task kind goes.

Deletion is compile-time-safe: HealType has no serde derive, the protos wire enums carry no heal-type discriminant (the receiver rebuilds the type from HealChannelRequest fields, which cannot express MRF), the MRF journal encodes MrfKind (1/2/3) whose consumers never construct an MRF task, and the scanner pending-heal ledger uses its own kind enum. All verified by adversarial review (all seven roles, High-risk tier).

Verification

  • cargo fmt --all
  • cargo test -p rustfs-heal — 310 passed lib (was 328; the 18 deleted tests covered only the removed path) + all integration targets, 0 failed, including the untouched mrf_pipeline tests
  • cargo check -p rustfs — clean
  • make pre-pr — passes (fmt + architecture guards + clippy + tests)

Adversarial review (High risk — quorum/heal, all seven roles): correctness verified zero remaining references (grep) and that HealPriority::Urgent keeps live users; compatibility verified all four wire/persistence claims by hand; security/concurrency/performance null reports; test-skeptic verified the 18 deleted tests pinned only the dead path and is_per_object now pins all seven surviving variants.

Impact

No behavior change — the removed code was unreachable in production. Binary size shrinks slightly; the heal-crate public API loses the event module (zero workspace consumers). Rollback is a clean revert.

Additional Notes

Dated audit documents under docs/operations reference the removed symbols with line numbers; they are historical snapshots that already describe this path as dead and are left as-is.

HealType::MRF (a #1664-era "metadata repair file" task kind) had no
production construction site left: its only builder lived in the
HealEvent -> HealRequest converter, and the HealEvent/HealEventHandler
queue itself had zero production references — both were superseded by
the MrfIntent pipeline (mrf_queue.rs), which produces Object/Metadata/
ECDecode requests and never an MRF task. The dead path nevertheless
carried ~700 lines: the whole event.rs module, the heal_mrf executor,
a dedup-key arm, an overlap arm with the "\u{0}mrf" sentinel bucket
hack, per-kind labels, and an empty MrfRuntime::record_accept shell.

Deleting the variant is compile-time safe: HealType has no Serialize
derive, the protos wire enums carry no heal-type discriminant (the
receiver rebuilds it from HealChannelRequest fields), the MRF journal
encodes MrfKind (1/2/3), and the scanner pending-heal ledger uses its
own kind enum — none of them can name an MRF task.

Also resolves the in-crate naming clash where "MRF" denoted both the
dead task kind and the live mission-repair-feed loop; the loop stays,
the task kind goes.

Co-Authored-By: heihutu <heihutu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

CLA requirements are satisfied for this pull request.

houseme and others added 3 commits August 19, 2026 20:54
The consumer's flush tick rewrote the full journal snapshot to every
local disk whenever `new_since_flush > 0 || queue.depth() > 0` held —
which is permanently true for a backlog waiting out an admission
backoff (manager full). Because the journal lives in the meta bucket,
each rewrite goes through the strict durability pin and fsyncs the file
plus parent directory on every disk: a steady-state backlog paid a full
re-encode + rewrite + fsync storm twice a second for a snapshot whose
bytes had not changed.

Gate the rewrite on a dirty flag that is set when the pending set
actually changes (channel push, dispatch pop, or an attempts bump that
alters the encoded record) and cleared on a flush that persisted to at
least one disk — a total write failure keeps the flag set so the next
tick retries the persist, preserving the periodic-retry self-healing a
non-empty queue used to provide. The tick decision is extracted into a
pure `tick_action(dirty, depth, journal_on_disk)` table — Flush / Retry
/ DeleteJournal / Idle — so a clean backlog skips the rewrite but keeps
draining (an expired backoff retries on time), and the delete-journal
branch only fires when nothing is pending. After replay arms the queue
at startup the flag is set whenever intents remain, so the
crash-recovery guarantee ("whatever the journal held is re-persisted")
is preserved. The channel-closed final flush still runs for a dirty or
non-empty state (the shutdown retry the unconditional flush used to
provide), and a dropped intent (queue ceiling hit) no longer counts
toward the flush threshold. The journal codec, format, and per-record
CRC are untouched.

Co-authored-by: heihutu <heihutu@gmail.com>
request_for_dedup_key answered "which queued request holds this key"
by linearly scanning the BinaryHeap and rebuilding every candidate's
dedup key with format! — on the submit path, so every heal submission
from the MRF consumer, the scanner, and read repair paid an O(queue)
string-allocation scan, which matters in mass-recovery scenarios where
the queue holds thousands of entries.

The queue already maintained a dedup_keys index but only for existence
checks. Upgrade its value from a bare refcount to DedupKeyEntry
{ refcount, representative_request_id }: the first request that opens a
key names the representative (captured before the request moves into
the heap), and both call sites — which only ever consumed queued.id —
now read it back in O(1) via queued_request_id_for_dedup_key. Push,
pop, displace, and remove keep the index consistent exactly as before.

Representative lifetime: the scheduler pop path deliberately keeps the
opener's name — the popped request surfaces in active_heals under that
same id, and the duplicate pre-check consults active heals before the
queue, so the named id always resolves. When a holder instead leaves
the queue without becoming active (canceled by id, or displaced under
queue pressure) and other holders survive — only reachable through
forced duplicates — refresh_dedup_representative re-elects a still-
queued holder so a merge receipt never names an id that resolves
nowhere. The re-election scan runs only on that rare admin path; the
per-submit lookup stays O(1).

The active/retrying dedup lookups stay linear on purpose: they are
bounded by the concurrency cap and single-digit retry sets, and O(1)
there would need a second cross-lock index for no measurable gain.

Co-authored-by: heihutu <heihutu@gmail.com>
@houseme
houseme merged commit be7f684 into main Aug 19, 2026
17 of 19 checks passed
@houseme
houseme deleted the pr8-remove-dead-mrf-path branch August 19, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant