sapling/eden/scm/tests/test-fb-hgext-fixcorrupt.t
Jun Wu febe96048e doctor: integrate fixcorrupt logic to repair changelog
Summary:
Reuse utilities in the fixcorrupt extension to repair changelog.

This is better than fixcorrupt because `hg doctor` does not require a repo
object. Some messages are updated so they become more consistent with the
rest of `hg doctor`.

The main motivation is to get changelog fixed early, so other repair logic can
check if a commit hash is known by changelog or not.

Reviewed By: markbt

Differential Revision: D19864418

fbshipit-source-id: 6f95c6c6191d7db2a474a07a5278a857cf41d8e2
2020-02-18 09:41:31 -08:00

145 lines
4.0 KiB
Perl

#require py2
#chg-compatible
$ disable treemanifest
$ SKIPREMOTEFILELOGCHECK=1
$ export SKIPREMOTEFILELOGCHECK
The fixcorrupt extension fixes pure revlog-based changelog. It is incompatible
with zstore-baked changelog.d:
$ setconfig format.use-zstore-commit-data=false
$ cat > noinline.py << EOF
> from edenscm.mercurial import revlog
> revlog.REVLOG_DEFAULT_FLAGS = 0
> revlog.REVLOG_DEFAULT_VERSION = revlog.REVLOG_DEFAULT_FORMAT
> EOF
$ cat >> $HGRCPATH << EOF
> [extensions]
> noinline=$TESTTMP/noinline.py
> fixcorrupt=
> EOF
$ rebuildrepo() {
> cd $TESTTMP
> [ -d repo ] && rm -rf repo
> hg init repo
> cd repo
> for i in 1 2 3 4 5; do
> echo $i > $i
> hg commit -m $i -A $i
> done
> }
$ cat > rewrite.py <<EOF
> # change (sys.argv[2]) bytes at the end of (sys.argv[1]) file to zeros
> import sys
> path = sys.argv[1]
> n = int(sys.argv[2])
> with open(path, 'rb+') as f:
> f.seek(0, 2)
> filesize = f.tell()
> n = min(n, filesize)
> f.seek(filesize - n)
> f.write(b'\0' * n)
> EOF
$ corrupt() {
> $PYTHON $TESTTMP/rewrite.py .hg/store/"$1" "$2"
> }
Nothing wrong
$ rebuildrepo
$ hg debugfixcorrupt
changelog: looks okay
manifest: looks okay
nothing to do
[1]
Changelog corruption
$ corrupt 00changelog.d 150
$ hg verify -q 2>&1 | grep error
15 integrity errors encountered!
$ hg debugfixcorrupt --no-dryrun
changelog: corrupted at rev 2 (linkrev=2)
manifest: marked corrupted at rev 2 (linkrev=2)
changelog: will lose 3 revisions
truncating 00changelog.d from 275 to 110 bytes
truncating 00changelog.i from 320 to 128 bytes
manifest: will lose 3 revisions
truncating 00manifest.d from 264 to 99 bytes
truncating 00manifest.i from 320 to 128 bytes
fix completed. re-run to check more revisions.
$ hg verify -q 2>&1 | grep error
[1]
Manifest corruption
$ rebuildrepo
$ corrupt 00manifest.d 150
$ cp -R .hg/store .hg/store.bak
$ hg debugfixcorrupt --no-dryrun
changelog: looks okay
manifest: corrupted at rev 2 (linkrev=2)
changelog: will lose 3 revisions
truncating 00changelog.d from 275 to 110 bytes
truncating 00changelog.i from 320 to 128 bytes
manifest: will lose 3 revisions
truncating 00manifest.d from 264 to 99 bytes
truncating 00manifest.i from 320 to 128 bytes
fix completed. re-run to check more revisions.
$ hg verify -q 2>&1 | grep error
[1]
Verify backups
$ cat > sha256.py << EOF
> import hashlib, sys
> # PY3-compat
> stdin = sys.stdin.buffer if sys.version_info[0] >= 3 else sys.stdin
> s = hashlib.sha256()
> s.update(stdin.read())
> sys.stdout.write('%s' % s.hexdigest()[:8])
> EOF
$ ls .hg/store/truncate-backups | sort
*-00changelog.d.backup-byte-110-to-275 (glob)
*-00changelog.i.backup-byte-128-to-320 (glob)
*-00manifest.d.backup-byte-99-to-264 (glob)
*-00manifest.i.backup-byte-128-to-320 (glob)
$ wc -c .hg/store/00changelog* .hg/store/00manifest* | sort
*99 .hg/store/00manifest.d (glob)
*110 .hg/store/00changelog.d (glob)
*128 .hg/store/00changelog.i (glob)
*128 .hg/store/00manifest.i (glob)
*465 total (glob)
$ for i in 00changelog.i 00changelog.d 00manifest.i 00manifest.d; do
> printf '%s: before fix: ' $i
> cat .hg/store.bak/$i | $PYTHON sha256.py
> printf ', restored from backup: '
> cat .hg/store/$i .hg/store/truncate-backups/*-$i.backup* | $PYTHON sha256.py
> printf '\n'
> done
00changelog.i: before fix: cd8b27c9, restored from backup: cd8b27c9
00changelog.d: before fix: 873f2076, restored from backup: 873f2076
00manifest.i: before fix: 1fbd16af, restored from backup: 1fbd16af
00manifest.d: before fix: 46207222, restored from backup: 46207222
Changelog.i ends with 0s
$ rebuildrepo
>>> with open('.hg/store/00changelog.i', 'ab') as f:
... f.write(b'\0' * 128)
$ hg debugfixcorrupt
changelog: corrupted at rev 5 (linkrev=0)
manifest: looks okay
changelog: will lose 2 revisions
truncating 00changelog.i from 448 to 320 bytes
re-run with --no-dryrun to fix.