diff -r 308e843f24b1 -r 0fb328bb2459 mercurial/repair.py --- a/mercurial/repair.py Fri Aug 06 16:17:17 2021 -0400 +++ b/mercurial/repair.py Fri Aug 06 16:27:17 2021 -0400 @@ -441,7 +441,7 @@ yield repo.manifestlog.getstorage(dir) -def rebuildfncache(ui, repo): +def rebuildfncache(ui, repo, only_data=False): """Rebuilds the fncache file from repo history. Missing entries will be added. Extra entries will be removed. @@ -465,28 +465,40 @@ newentries = set() seenfiles = set() - progress = ui.makeprogress( - _(b'rebuilding'), unit=_(b'changesets'), total=len(repo) - ) - for rev in repo: - progress.update(rev) + if only_data: + # Trust the listing of .i from the fncache, but not the .d. This is + # much faster, because we only need to stat every possible .d files, + # instead of reading the full changelog + for f in fnc: + if f[:5] == b'data/' and f[-2:] == b'.i': + seenfiles.add(f[5:-2]) + newentries.add(f) + dataf = f[:-2] + b'.d' + if repo.store._exists(dataf): + newentries.add(dataf) + else: + progress = ui.makeprogress( + _(b'rebuilding'), unit=_(b'changesets'), total=len(repo) + ) + for rev in repo: + progress.update(rev) - ctx = repo[rev] - for f in ctx.files(): - # This is to minimize I/O. - if f in seenfiles: - continue - seenfiles.add(f) + ctx = repo[rev] + for f in ctx.files(): + # This is to minimize I/O. + if f in seenfiles: + continue + seenfiles.add(f) - i = b'data/%s.i' % f - d = b'data/%s.d' % f + i = b'data/%s.i' % f + d = b'data/%s.d' % f - if repo.store._exists(i): - newentries.add(i) - if repo.store._exists(d): - newentries.add(d) + if repo.store._exists(i): + newentries.add(i) + if repo.store._exists(d): + newentries.add(d) - progress.complete() + progress.complete() if requirements.TREEMANIFEST_REQUIREMENT in repo.requirements: # This logic is safe if treemanifest isn't enabled, but also