[PATCH] localrepo: add optional validation (defaults to off) for incoming changes

Augie Fackler durin42 at gmail.com
Thu Feb 11 16:40:03 CST 2010


# HG changeset patch
# User Augie Fackler <durin42 at gmail.com>
# Date 1265927863 21600
# Node ID 5fc090ba08a6b5bad792f2acd2093039ddfdfa04
# Parent  4cfd0d56be6dcbcfac90bf95e8f8750ab66fd9aa
localrepo: add optional validation (defaults to off) for incoming changes

This verifies that all manifests are present for incoming changes,
and all files for those manifests are also present. This is a simple
first-pass, and could be better, but seems like a valuable thing to
have, as I've seen pushes in the past that propagated revlog corruption.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -2005,6 +2005,16 @@
             # be empty during the pull
             self.manifest.addgroup(chunkiter, revmap, trp)
 
+            needfiles = {}
+            if self.ui.configbool('server', 'validate', default=False):
+                # validate incoming csets have their manifests
+                for cset in xrange(clstart, clend):
+                    mfest = self.changelog.read(self.changelog.node(cset))[0]
+                    mfest = self.manifest.readdelta(mfest)
+                    # store file nodes we must see
+                    for f, n in mfest.iteritems():
+                        needfiles.setdefault(f, set()).add(n)
+
             # process the files
             self.ui.status(_("adding file changes\n"))
             while 1:
@@ -2019,6 +2029,24 @@
                     raise util.Abort(_("received file revlog group is empty"))
                 revisions += len(fl) - o
                 files += 1
+                if f in needfiles:
+                    needs = needfiles[f]
+                    for new in xrange(o, len(fl)):
+                        n = fl.node(new)
+                        if n in needs:
+                            needs.remove(n)
+                    if not needs:
+                        del needfiles[f]
+
+            for f, needs in needfiles.iteritems():
+                fl = self.file(f)
+                for n in needs:
+                    try:
+                        fl.rev(n)
+                    except error.LookupError:
+                        raise util.Abort(
+                            _('missing file data for %s:%s - run hg verify') %
+                            (f, hex(n)))
 
             newheads = len(cl.heads())
             heads = ""
diff --git a/tests/test-push-validation b/tests/test-push-validation
new file mode 100755
--- /dev/null
+++ b/tests/test-push-validation
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+STRIP=`pwd`
+
+hg init test
+cd test
+cat > .hg/hgrc <<EOF
+[server]
+validate=1
+EOF
+echo alpha > alpha
+echo beta > beta
+hg addr
+hg ci -m 1
+
+cd ..
+hg clone test test-clone
+
+cd test-clone
+cp .hg/store/data/beta.i tmp
+echo blah >> beta
+hg ci -m '2 (corrupt)'
+mv tmp .hg/store/data/beta.i
+hg push 2>&1 | sed "s%$STRIP%test-root%"
diff --git a/tests/test-push-validation.out b/tests/test-push-validation.out
new file mode 100644
--- /dev/null
+++ b/tests/test-push-validation.out
@@ -0,0 +1,12 @@
+adding alpha
+adding beta
+updating to branch default
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+pushing to test-root/test
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+transaction abort!
+rollback completed
+abort: missing file data for beta:dddc47b3ba30e54484720ce0f4f768a0f4b6efb9 - run hg verify


More information about the Mercurial-devel mailing list