diff --git a/hgext3rd/fastpartialmatch.py b/hgext3rd/fastpartialmatch.py --- a/hgext3rd/fastpartialmatch.py +++ b/hgext3rd/fastpartialmatch.py @@ -32,6 +32,9 @@ # if fastpartialmatch extension was temporarily disabled then index may miss # some entries. By bumping generationnumber we can force index to be rebuilt generationnumber = 0 + + # internal config setting. Marks index as needed to be rebuilt + rebuild = False ''' from collections import defaultdict @@ -39,6 +42,7 @@ from hgext3rd.generic_bisect import bisect from mercurial import ( + dispatch, error, extensions, localrepo, @@ -80,7 +84,7 @@ _current_version = 1 _tip = 'run `hg debugrebuildpartialindex` to fix the issue' _unsortedthreshold = 1000 -_needrebuildfile = os.path.join(_partialindexdir, 'needrebuild') +_needrebuildfile = 'partialindexneedrebuild' def extsetup(ui): extensions.wrapfunction(revlog.revlog, '_partialmatch', _partialmatch) @@ -97,6 +101,18 @@ _unsortedthreshold = ui.configint('fastpartialmatch', 'unsortedthreshold', _unsortedthreshold) + def _runcommand(orig, lui, repo, cmd, fullargs, ui, *args, **kwargs): + res = orig(lui, repo, cmd, fullargs, ui, *args, **kwargs) + if ui.config('fastpartialmatch', 'rebuild', False): + _markneedsrebuilding(ui, repo) + return res + + extensions.wrapfunction(dispatch, 'runcommand', _runcommand) + # Add _needrebuildfile to the list of files that don't need to be protected + # by wlock. Race conditions on _needrebuildfile are not important because + # at worst it may trigger rebuilding twice or postpone index rebuilding. + localrepo.localrepository._wlockfreeprefix.add(_needrebuildfile) + def reposetup(ui, repo): isbundlerepo = repo.url().startswith('bundle:') if repo.local() and not isbundlerepo: @@ -204,7 +220,7 @@ return 1 generationnum = _readgenerationnum(ui, repo.svfs) ui.write(_('generation number: %d\n') % generationnum) - if _needsrebuilding(repo.svfs): + if _needsrebuilding(repo): ui.write(_('index will be rebuilt on the next pull\n')) indexvfs = vfsmod.vfs(repo.svfs.join(_partialindexdir)) for indexfile in sorted(_iterindexfile(indexvfs)): @@ -257,6 +273,7 @@ vfs.rmtree(tempdir) vfs.mkdir(tempdir) + _unmarkneedsrebuilding(repo) filesdata = defaultdict(list) for rev in repo.changelog: @@ -315,7 +332,7 @@ for rev in xrange(rev_first, rev_last + 1): newhexnodes.append(repo[rev].hex()) - if not vfs.exists(_partialindexdir) or _needsrebuilding(vfs): + if not vfs.exists(_partialindexdir) or _needsrebuilding(repo): _rebuildpartialindex(ui, repo, skiphexnodes=set(newhexnodes)) for i, hexnode in enumerate(newhexnodes): _recordcommit(ui, tr, hexnode, rev_first + i, vfs) @@ -441,7 +458,7 @@ if hexnode.startswith(id): candidates[node] = rev if unsorted >= _unsortedthreshold: - _markneedsrebuilding(ui, vfs) + ui.setconfig('fastpartialmatch', 'rebuild', True) except Exception as e: ui.warn(_('failed to read partial index %s : %s\n') % (fullpath, str(e))) @@ -479,16 +496,19 @@ sortedcount = cls._intpacker.unpack(sortedcount)[0] return cls(sortedcount) -def _needsrebuilding(vfs): - return vfs.exists(_needrebuildfile) +def _needsrebuilding(repo): + return repo.vfs.exists(_needrebuildfile) -def _markneedsrebuilding(ui, vfs): +def _markneedsrebuilding(ui, repo): try: - with vfs(_needrebuildfile, 'w') as fileobj: + with repo.vfs(_needrebuildfile, 'w') as fileobj: fileobj.write('content') # content doesn't matter except IOError as e: ui.warn(_('error happened while triggering rebuild: %s\n') % e) +def _unmarkneedsrebuilding(repo): + repo.vfs.tryunlink(_needrebuildfile) + def _readgenerationnum(ui, vfs): generationnumfile = os.path.join(_partialindexdir, 'generationnum') if not vfs.exists(generationnumfile): diff --git a/tests/test-fastpartialmatch.t b/tests/test-fastpartialmatch.t --- a/tests/test-fastpartialmatch.t +++ b/tests/test-fastpartialmatch.t @@ -325,12 +325,15 @@ $ cd ../cloned2 $ printf '[fastpartialmatch]\nunsortedthreshold=1' >> .hg/hgrc $ hg up -q ac536ed8bde0 + $ [ -f .hg/partialindexneedrebuild ] + [1] $ mkcommit commit $ hg log -r . -T '{node}\n' 587cd78c6d0eb0259484b09a5983bcc2973f2245 Next command should set that cache needs rebuilding $ hg log -r 587cd78c6d0eb0259 > /dev/null + $ [ -f .hg/partialindexneedrebuild ] $ hg debugfastpartialmatchstat generation number: 0 index will be rebuilt on the next pull @@ -368,16 +371,14 @@ file: b7, entries: 1, out of them 1 sorted file: fd, entries: 1, out of them 0 sorted -Make a commit and change partialindex permissions to non-writabble. Then do +Make a commit and change .hg permissions to non-writabble. Then do partial lookup that should write needrebuild file but it couldn't because of permissions. Make sure it doesn't throw and just log the problem $ mkcommit commitpermissionissue - $ chmod u-w .hg/store/partialindex + $ chmod u-w .hg/ $ hg log -r . -T '{node}\n' 2b52832374dd7e499a1fbd172f1d75e13ee32477 $ hg log -r 2b5283237 - error happened while triggering rebuild: [Errno 13] Permission denied: '$TESTTMP/cloned2/.hg/store/partialindex/needrebuild' - error happened while triggering rebuild: [Errno 13] Permission denied: '$TESTTMP/cloned2/.hg/store/partialindex/needrebuild' changeset: 7:2b52832374dd tag: tip parent: 4:587cd78c6d0e @@ -385,7 +386,8 @@ date: Thu Jan 01 00:00:00 1970 +0000 summary: commitpermissionissue - $ chmod u+w .hg/store/partialindex + error happened while triggering rebuild: [Errno 13] Permission denied: '$TESTTMP/cloned2/.hg/partialindexneedrebuild' + $ chmod u+w .hg/ Temporarily disable the fastpartialmatch and make a commit. Bump index generation number version and check that index was deleted after next