Purging of excess diffs.#657
Merged
Merged
Conversation
Also: - Fix: signed_restore() was not using the actual persisted paths but was constructing them from assumptions. - Fix: persist with signed diffs the unsigned diff serial that it relates to, rather than hoping that the unsigned diff at a particular offset in the unsigned diff collection is the right one. - Fix: serve IXFR responses based on actually fetching the right diffs by soa serial, walking from serial to serial without gaps.
- Added policy setting server.outbound.max-diffs, default 5 like NSD. - Added output of new policy setting to cascade policy show. - Documented the new setting in the policy template. - Extended the persist-zone integration test to exercise diff purging. - Numbered some step names in the integration test to ease diagnostics. - Used dig +qid in some integration step tests to ease diagnostics. - Added a new Compacter that compacts persisted diffs in the background. - Added purging of in-memory diffs prior to storing a new signed diff. - Extracted persist_to_file() to persist_to_file_from_parts() for use by compaction. - Updated persist_to_file_from_parts() to do atomic writes like util::write_file(). - Added field restore_base_idx and logic to use it when applying new diffs after compaction. - Added logic to purge excess diffs on policy reload in case max-diffs was reduced.
ximon18
force-pushed
the
prune-diffs-take-two
branch
from
June 18, 2026 07:45
8f8d787 to
1b1dc02
Compare
ximon18
changed the base branch from
main
to
persist-zone-fixes-and-improvements
June 18, 2026 07:45
Other methods are pub, so make len() pub too.
…ersistence related state of the zone.
…post review. (fixes #825)
Co-authored-by: Terts Diepraam <terts.diepraam@gmail.com>
tertsdiepraam
left a comment
Contributor
There was a problem hiding this comment.
Some comment suggestions to help explain how the restoration works.
…scriptions slightly.
…dule level. Also update discard_excess_diffs() to follow the changes introduced by #877.
Ensuring before storing would allow the to-be-stored diff to then take us over the configured limits.
…e addressed in future.
tertsdiepraam
approved these changes
Jul 15, 2026
Co-authored-by: Terts Diepraam <terts.diepraam@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #804.
The problem
In #550 when a zone is first loaded and is approved it is persisted to disk as a loaded snapshot. Once it is signed and approved a signed snapshot is written to disk (as an AXFR payload in wire format). On process restart the snapshots are restored allowing the published zone to be served as it was before shutdown. Every time thereafter that the zone changes, either due to changes to the loaded zone via reloaded from disk or incoming XFR, or due to changes in the signed zone due to signing loaded record changes and/or (incremental) re-signing to account for DNSKEY changes and/or to avoid signature expiration, that results in loaded and/or signed diffs.
Those diffs are persisted to disk (as IXFR payloads in wire format) in order to be replayed on top of the zone snapshot after process restart, and stored in memory to be served as IXFR out diffs.
The persistence of diffs in #550 is unbounded, both in-memory and on-disk.
Challenges to overcome
Excess IXFR in-memory diffs can just be forgotten, but excess on-disk diffs cannot just be deleted because they form part of the snapshot+diff history of the zone that is replayed on process restart to restore the published zone. Removing a diff would break restoration as the next available diff would not apply correctly to the snapshot.
What this PR provides
This PR sets an upper limit on the number of diffs to keep, adds
PersistentDiffManager,CompacterandIxfrZoneDiffs:PersistentDiffManagermanages the set of paths to persistent diffs on disk. It tracks thenext_idxto use to generate a unique filename for the next diff to write (this could perhaps be avoided by using UUIDs or something). It also keeps track of therestore_base_idxwhich indicates the offset into the set of persisted diffs at which replay during restore should restart.Compacterreplaces the persisted snapshots for a zone with new versions containing records from the in-memory copy of the currently published zone, as this represents the existing snapshot with all existing diffs applied, and updatesrestore_base_idxaccordingly. Writing out the entire zone to disk is a time consuming operation for a large zone and so we look for zones needing compaction once a minute. I'm not at all sure what strategy should be used here, this is just an initial attempt to avoid persisting to disk on every single change but instead to batch the changes together less frequently.IxfrZoneDiffsstores diffs for use byServicewhen responding to IXFR requests to the publication server. It also provides the logic to look up the diffs needed to answer a query, and "trimming" functionality to keep in-memory diff sizes within configurable limits.New policy settings
server.outbound.max-diffsserver.outbound.max-diffs-sizeFeatures NOT included in this PR
Known issues
PersistentStateandPersistentDiffManagerhave no reference toCenterfrom which they can gain thezone-statepath config value) nor can it be passed in via a constructor as the parent hierarchy usesDefault. Likewise the persistent state relates to a single zone but has no concept of which zone that is as when it is created, as well as the Default problem mentioned, it is created as part of the zone so it can't take a reference to something which isn't constructed yet.Tasks remaining
src/persistence/mod.rs)zone statusmay show the zone as restoring or thatpolicy showprints the purging related policy settings, or something in the high level zone transfers page about limiting of diffs kept?If you are changing Rust code or integration tests (
Cargo.*,crates/,etc/,integration-tests/,src/):actthrough theact-wrapper(as described inTESTING.md)?If you are modifying man pages: