[PATCH 2 of 2] branchmap: recover from out of sync revs and names cache (issue5058)
Gregory Szorc
gregory.szorc at gmail.com
Sat Mar 12 20:18:50 EST 2016
It appears Mads and I were working on the same thing and patchbombed within
minutes of each other! I like his series much better. Please drop this one.
On Sat, Mar 12, 2016 at 5:13 PM, Gregory Szorc <gregory.szorc at gmail.com>
wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1457831565 28800
> # Sat Mar 12 17:12:45 2016 -0800
> # Node ID 0f9104a35c8614eaff672dc9e10badb318db09f6
> # Parent cd89ed3be2b6f5db1d716bc0ffea4ee5480619ac
> branchmap: recover from out of sync revs and names cache (issue5058)
>
> There was a bug report of an IndexError during self._names[branchidx].
> This could happen if the revs cache contained a reference to a name
> at an index that doesn't exist in the names cache. Whether this can
> happen reliably or whether it requires filesystem or similar
> corruption, I'm not sure.
>
> This patch catches the IndexError and clears the cache.
>
> It feels like blowing away both caches is appropriate because if
> one entry in the revs cache points to an invalid entry in the names
> cache, then there is no telling how out of sync the two caches are.
> It's possible the names cache is completely unrelated to the revs
> cache (as unlikely as this hopefully is).
>
> The added test reproduces the stack reported on the bug without the
> corresponding code change.
>
> diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
> --- a/mercurial/branchmap.py
> +++ b/mercurial/branchmap.py
> @@ -403,17 +403,32 @@ class revbranchcache(object):
> cachenode, branchidx = unpack(
> _rbcrecfmt, buffer(self._rbcrevs, rbcrevidx, _rbcrecsize))
> close = bool(branchidx & _rbccloseflag)
> if close:
> branchidx &= _rbcbranchidxmask
> if cachenode == '\0\0\0\0':
> pass
> elif cachenode == reponode:
> - return self._names[branchidx], close
> + try:
> + return self._names[branchidx], close
> + except IndexError:
> + # If the names list is out of sync with the revs cache,
> + # all bets are off. Blow away both caches.
> + self._repo.ui.debug('revbranch cache references unknown
> name '
> + 'index; resetting\n')
> + self._names = []
> + self._rbcnamescount = 0
> + self._rbcsnameslen = 0
> + self._namesreverse = {}
> + self._rbcrevs = array('c')
> + self._rbcrevs.extend('\0' * (rev * _rbcrecsize))
> + self._rbcrevslen = 0
> +
> + return self._branchinfo(rev)
> else:
> # rev/node map has changed, invalidate the cache from here up
> truncate = rbcrevidx + _rbcrecsize
> del self._rbcrevs[truncate:]
> self._rbcrevslen = min(self._rbcrevslen, truncate)
>
> # fall back to slow path and make sure it will be written to disk
> return self._branchinfo(rev)
> diff --git a/tests/test-branches.t b/tests/test-branches.t
> --- a/tests/test-branches.t
> +++ b/tests/test-branches.t
> @@ -618,15 +618,43 @@ contain the branch name even though it n
> 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
> 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
> 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
> 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
> 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._ at a.
> ....|
> 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
> 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
> 0070: f8 94 c2 56 80 00 00 03 |...V....|
> +
> +recovery when rbc-names cache is missing entries
> +
> + $ echo "a" > .hg/cache/rbc-names-v1
> +
> + $ hg log -r 'branch(a)' -T '{rev}\n' --debug
> + revbranch cache references unknown name index; resetting
> + 1
> + 2
> + 5
> + truncating cache/rbc-revs-v1 to 0
> + $ f --size --hexdump .hg/cache/rbc-*
> + .hg/cache/rbc-names-v1: size=79
> + 0000: 61 00 62 00 63 00 61 20 62 72 61 6e 63 68 20 6e |a.b.c.a branch n|
> + 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
> + 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
> + 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
> + 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches|
> + .hg/cache/rbc-revs-v1: size=120
> + 0000: 00 00 00 00 00 00 00 00 dd 6b 44 0d 00 00 00 00 |.........kD.....|
> + 0010: 88 1f e2 b9 00 00 00 00 ac 22 03 33 00 00 00 01 |.........".3....|
> + 0020: ae e3 9c d1 00 00 00 01 d8 cb c6 1d 00 00 00 00 |................|
> + 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
> + 0040: ee bb 94 44 00 00 00 01 5f 40 61 bb 00 00 00 01 |...D...._ at a.
> ....|
> + 0050: bf be 84 1b 00 00 00 01 d3 f1 63 45 80 00 00 01 |..........cE....|
> + 0060: e3 d4 9c 05 80 00 00 01 e2 3b 55 05 00 00 00 01 |.........;U.....|
> + 0070: f8 94 c2 56 80 00 00 02 |...V....|
> +
> cache is updated/truncated when stripping - it is thus very hard to get
> in a
> situation where the cache is out of sync and the hash check detects it
> $ hg --config extensions.strip= strip -r tip --nob
> $ f --size .hg/cache/rbc-revs*
> .hg/cache/rbc-revs-v1: size=112
>
> $ cd ..
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20160312/33da619b/attachment.html>
More information about the Mercurial-devel
mailing list