-
Notifications
You must be signed in to change notification settings - Fork 12
Store packfile size metadata. #377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mathieu-plak
wants to merge
2
commits into
main
Choose a base branch
from
mm/store_size_metadata
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 The VERSION bump to 1.2.0 in this PR updates the version dispatch in
MergeState(state.go:262-266) to treat1.0.0as legacy and everything else as the new format, but two sibling dispatch sites in the same file were missed and still gate onver.Equals("1.1.0"). The more serious one isReadHeader(state.go:234) — it is called fromRebuildState/RebuildStateWithCacheas theTopoSortgetParentcallback (repository.go:367, :492), so for every new v1.2.0 state it skips the 32-byte parent header and returnshdr.Parent = NilMac, causingTopoSortto classify every new state as a root and breaking the partial topological ordering state merging relies on.FromStream(state.go:167-175) has the symmetric defect (latent — only test-called today). Fix: mirror theMergeStatedispatch at both sites — treat1.0.0as legacy and everything else as the current format.Extended reasoning...
Bug
This PR bumps
VERSIONfrom1.1.0to1.2.0(state.go:35) and inverts the polarity of the version dispatch inMergeState(state.go:262-266) so that1.0.0routes to the legacydeserializeFromStreamv100and everything else (including the new1.2.0) routes todeserializeFromStream. There are two sibling dispatch sites in the same file that should have been updated in lock-step but were missed:Version.Equalsdoes an exact semver compare, so1.2.0 != 1.1.0and these checks now fall to the wrong branch for any state written by this PR.Why the existing code does not prevent this
SerializeToStream(state.go:~374) writesls.Metadata.Parent[:](32 bytes) at the start of every stream regardless of version, and the matchingdeserializeFromStreamconsumes them. So the on-disk format for1.2.0still has the parent header — but the dispatch that decides whether to read it was never updated for the new version.Impact
ReadHeader(hot path regression):ReadHeaderis called fromRebuildState(repository.go:367) andRebuildStateWithCache(repository.go:492) inside theTopoSortgetParentcallback. Withver=1.2.0, theif ver.Equals("1.1.0")branch is skipped, no parent bytes are consumed, and the returnedhdr.Parentis the zero valueNilMac.TopoSortthen takes theif p == objects.NilMac { S = append(S, stateID) }branch for every new state and classifies all of them as roots. The partial topological ordering that subsequentMergeStatecalls rely on (parents must be merged before children so the implicit parent-setting comment at lines 257-260 holds) degenerates into reverse-insertion order. This affects any deployment that writes more than one v1.2.0 state and then rebuilds — i.e. every repository upgraded past this PR.FromStream(latent): Withver=1.2.0, the else branch routes todeserializeFromStreamv100, which (a) does not consume the 32-byte parent header that the new format writes, and (b) rejects anyET_PACKFILEentry whose length is notPackfileEntrySerializedSizeV1(state.go:907-909). A v1.2.0 stream pushed throughFromStreamwould either mis-frame from the 32-byte offset or hard-error on the first V2 packfile entry. The only current caller isTestFromStream(state_test.go:327) which hardcodes"1.1.0", so the runtime impact today is zero — but it is an exported API on which the just-updatedMergeStateis the obvious reference point, and the divergence is the same half-applied-refactor pattern as theReadHeaderissue.Step-by-step proof for
ReadHeaderPutStatecallsstorage.Serialize(..., versioning.GetCurrentVersion(RT_STATE), ...), which tags the state file with version1.2.0(becauseVERSION = "1.2.0"is the registered current version).SerializeToStreamwritesls.Metadata.Parent[:](32 bytes) at offset 0 — see state.go:374.RebuildStatecallsTopoSort(missingStates, getParent)(repository.go:367) wheregetParentopens the state file, gets backver = 1.2.0fromGetState, and callsstate.ReadHeader(rd, ver).ReadHeader:ver.Equals(versioning.FromString("1.1.0"))evaluates tofalse(semver compare,1.2.0 != 1.1.0). The body is skipped.hdr.Parentremains{0,0,...,0} == objects.NilMac.TopoSort:p == objects.NilMacis true, sostateIDis appended toS(root set). This happens for every v1.2.0 state, even those whose stream actually starts with a non-Nil parent.orderedStatesin reverse insertion order ofmissingStatesrather than parent-before-child order.MergeStateis then called in arbitrary order; the comment at state.go:257-260 ("This implicitely sets the parent ... will set the correct parent") depends on parents being processed first, so the resulting aggregated parent chain is wrong.Addressing the bug_002 refutation
One verifier refuted bug_002 as a duplicate of an internal bug_005 (same root cause and lines). The duplicate observation is correct — both describe the same
FromStreamdefect — and the underlying claim is itself confirmed by that same verifier. It is not a refutation of the bug's validity, only of double-counting. The synthesis-merged report folds bothReadHeader(hot path) andFromStream(latent) into a single review item, which is the right framing: they are two faces of the same incomplete refactor and the fix is identical.Fix
Mirror the updated
MergeStatedispatch at both sites — treat1.0.0as the legacy case (no parent header / v100 deserializer) and everything else as the current format:Adding a regression test that round-trips a v1.2.0 state with a non-Nil parent through
ReadHeader(and ideally feeds two such states with a parent/child relation intoTopoSort) would lock the invariant down.