[PATCH] changegroup: fix file linkrevs during reorders
Pierre-Yves David
pierre-yves.david at ens-lyon.org
Thu Nov 20 19:57:58 CST 2014
On 11/20/2014 05:27 PM, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham at fb.com>
> # Date 1416529857 28800
> # Thu Nov 20 16:30:57 2014 -0800
> # Node ID b4c33f5d506db0880a9b02c63c633d216fdcd87c
> # Parent a179db3db9b96b38c10c491e6e7e7ad5f40a7787
> changegroup: fix file linkrevs during reorders
>
> Previously, if reorder was true during the creation of a changegroup bundle,
> it was possible that the manifest and filelogs would be reordered such that the
> resulting bundle filelog had a linkrev that pointed to a commit that was not
> the earliest instance of the filelog revision. For example:
>
> With commits:
>
> 0<-1<---3<-4
> \ /
> --2<---
>
> if 2 and 3 added the same version of a file, if the manifests of 2 and 3 have
> their order reversed, but the changelog did not, it could produce a filelog with
> linkrevs 0<-3 instead of 0<-2, which meant if commit 3 was stripped, it would
> delete that file data from the repository and commit 2 would be corrupt (as
> would any future pulls that tried to build upon that version of the file).
>
> The fix is to make the linkrev fixup smarter. Previously it considered the first
> manifest that added a file to be the first commit that added that file, which is
> not true. Now, for every file revision we add to the bundle we make sure we
> attach it to the earliest applicable linkrev.
>
> I can only repro this issue in a large internal repo, so I don't have a good
> test case to add a test for (since it depends on the exact commit vs. manifest
> vs. filelog orders).
Any change we can get a test for it? Looks like it would not be too hard
with some --debug output and others debug commands.
>
> diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
> --- a/mercurial/changegroup.py
> +++ b/mercurial/changegroup.py
> @@ -325,6 +325,7 @@ class cg1packer(object):
> # for progress output
> msgbundling = _('bundling')
>
> + clrevorder = {}
> mfs = {} # needed manifests
> fnodes = {} # needed file nodes
> changedfiles = set()
> @@ -334,6 +335,7 @@ class cg1packer(object):
> # Returns the linkrev node (identity in the changelog case).
> def lookupcl(x):
> c = cl.read(x)
> + clrevorder[x] = len(clrevorder)
> changedfiles.update(c[3])
> # record the first changeset introducing this manifest version
> mfs.setdefault(c[0], x)
> @@ -349,13 +351,16 @@ class cg1packer(object):
> # Returns the linkrev node (collected in lookupcl).
> def lookupmf(x):
> clnode = mfs[x]
> - if not fastpathlinkrev:
> + if not fastpathlinkrev or reorder:
> mdata = mf.readfast(x)
> for f, n in mdata.iteritems():
> if f in changedfiles:
> # record the first changeset introducing this filelog
> # version
> - fnodes.setdefault(f, {}).setdefault(n, clnode)
> + fclnodes = fnodes.setdefault(f, {})
> + fclnode = fclnodes.setdefault(n, clnode)
> + if clrevorder[clnode] < clrevorder[fclnode]:
> + fclnodes[n] = clnode
> return clnode
>
> mfnodes = self.prune(mf, mfs, commonrevs, source)
> @@ -368,7 +373,7 @@ class cg1packer(object):
> needed = set(cl.rev(x) for x in clnodes)
>
> def linknodes(filerevlog, fname):
> - if fastpathlinkrev:
> + if fastpathlinkrev and not reorder:
> llr = filerevlog.linkrev
> def genfilenodes():
> for r in filerevlog:
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
>
--
Pierre-Yves David
More information about the Mercurial-devel
mailing list