Skip to content

⚡ perf(ha): bound the ownership snapshot - #2029

Merged
gaborbernat merged 1 commit into
mainfrom
perf/bound-ownership-snapshot-1584
Aug 31, 2026
Merged

⚡ perf(ha): bound the ownership snapshot#2029
gaborbernat merged 1 commit into
mainfrom
perf/bound-ownership-snapshot-1584

Conversation

@gaborbernat

Copy link
Copy Markdown
Member

OwnershipState grew with every move the group applied, not with the authorities it still homed. Each committed RecordTransfer pushed a TransferRecord onto the authority's record and no command removed one, so a repository deleted a year ago still contributed its record, its epoch, and each move it ever made. At the population #1584 describes, 200,000 authorities each moved eight times during rolling restarts, OwnershipState::snapshot() measured 97,800,047 bytes. 73,200,000 of that was move history, 45.75 bytes per transfer. build_snapshot serialized and cloned the whole buffer on every build, and a follower rejoining after a disk replacement downloaded all of it before it could apply a new entry. The same population now measures 24,600,047 bytes, 123 bytes per live authority.

Nothing read the trail. OwnershipState::transfers and TransferRecord had no caller outside this crate's own tests, and no command consulted record.transfers to reach a decision: assign_home reads home and epoch, transfer and advance_epoch read home and writes. A bounded window would have held a partial copy of something that already exists, since commit_transfer persists a TransferAudit carrying the authority, source, target, actor, reason, barrier, epoch, and commit index to the MetaStore, which the planned transfer contract names as the record an operator and reconciliation answer from. Keeping the last N moves in consensus would still charge every follower that downloads a snapshot while leaving the history too incomplete to audit from, so the replicated map now holds live state only: home, epoch, assignment provenance, and outstanding write leases. That is the shape #2023 took rather than the table split in #2011, because a durable record already owns the history.

ControlCommand::ForgetAuthority removes a retired repository from the map. Operators send it to the existing POST /availability/v1/commands endpoint, so there is no new route, and it applies inside the same decision that records its receipt, as transfer_authority and advance_epoch do. It commits as no_change when the state homes nothing under the authority, which makes a retry after a committed forget safe, and consensus refuses it while a write lease is live, because the lease holder still stamps work with the epoch it drops. Publishing to a forgotten authority assigns it again at epoch one.

One copy per snapshot build remains. TypeConfig fixes openraft's SnapshotData to Cursor<Vec<u8>>, so build_snapshot has to hand its caller an owned Vec, and removing that copy would mean changing the openraft contract. Dropping the growth term bounds that copy, which now scales with live authorities instead of with every move the group has applied.

#1584 lists #1451 as a blocker, which this change does not stand on. The durable audit table exists on main today and takes a row on every committed planned transfer, while #1451 covers recovering an audit whose write failed after the ownership commit. The replicated trail could not have served that recovery, because TransferRecord carried none of the actor, reason, barrier, or commit index the audit answers with.

Closes #1584

Every committed RecordTransfer pushed a TransferRecord onto the authority's
record in replicated state and nothing ever removed one, so the snapshot grew
with the number of moves the group had applied rather than with the authorities
it still homed. At 200,000 authorities each moved eight times the snapshot
measured 97,800,047 bytes, 73,200,000 of which was move history at 45.75 bytes
per transfer. Every build serialized and cloned that whole buffer, and a
follower rejoining after a disk replacement downloaded all of it, deleted
repositories included, before it could apply a new entry.

Nothing read the trail. OwnershipState::transfers and TransferRecord had no
caller outside the crate's own tests, and no command consulted record.transfers
to decide anything, so no cross-transaction reader broke by dropping them. A
bounded window would have been a lossy partial copy of a record that already
exists: commit_transfer persists a TransferAudit carrying the actor, reason,
barrier, and commit index to the MetaStore, which the planned-transfer contract
already names the record operators answer from. Keeping the last N moves in
consensus would be too incomplete to audit from and still charge every snapshot
transfer, so the replicated state now keeps live state only.

ForgetAuthority gives a retired repository a way out of that state. It rides the
existing operator command endpoint, applies in the same decision that records its
receipt, commits as no_change when nothing is homed under the authority, and is
refused while a write lease is live, since the lease holder still stamps work
with the epoch it drops.
@gaborbernat gaborbernat added the enhancement New feature or request label Aug 31, 2026
@read-the-docs-community

Copy link
Copy Markdown

@codspeed-hq

codspeed-hq Bot commented Aug 31, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 29 untouched benchmarks
⏩ 133 skipped benchmarks1


Comparing perf/bound-ownership-snapshot-1584 (24e0112) with main (68a4b98)

Open in CodSpeed

Footnotes

  1. 133 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@gaborbernat
gaborbernat enabled auto-merge (squash) August 31, 2026 23:06
@gaborbernat
gaborbernat merged commit cd64014 into main Aug 31, 2026
26 checks passed
@gaborbernat
gaborbernat deleted the perf/bound-ownership-snapshot-1584 branch August 31, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bound the ownership state a snapshot carries

1 participant