Mercurial > public > mercurial-scm > hg
diff mercurial/branching/rev_cache.py @ 51901:c564be351754
rev-branch-cache: stop truncating cache file
Truncating the file prevent the safe use of mmap. So instead of overwrite the
existing data. If more than 20% of the file is to be overwritten, we rewrite the
whole file instead.
Such whole rewrite is done by replacing the old one with a new one, so mmap of
the old file would be affected.
This prepare a more aggressive use of mmap in later patches.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Tue, 24 Sep 2024 00:16:23 +0200 |
parents | 7032da075572 |
children | 0f26ee69cf36 |
line wrap: on
line diff
--- a/mercurial/branching/rev_cache.py Tue Sep 24 00:16:04 2024 +0200 +++ b/mercurial/branching/rev_cache.py Tue Sep 24 00:16:23 2024 +0200 @@ -4,6 +4,7 @@ # GNU General Public License version 2 or any later version. from __future__ import annotations +import os import struct from ..node import ( @@ -39,6 +40,10 @@ _rbccloseflag = 0x80000000 +# with atomic replacement. +REWRITE_RATIO = 0.2 + + class rbcrevs: """a byte string consisting of an immutable prefix followed by a mutable suffix""" @@ -345,19 +350,44 @@ def _writerevs(self, repo, start): """write the new revs to revbranchcache""" revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize) + + end = revs * _rbcrecsize if self._force_overwrite: start = 0 - with repo.cachevfs.open(_rbcrevs, b'ab') as f: + + with repo.cachevfs.open(_rbcrevs, b'a+b') as f: + pass # this make sure the file exist… + with repo.cachevfs.open(_rbcrevs, b'r+b') as f: + f.seek(0, os.SEEK_END) current_size = f.tell() if current_size < start: start = 0 if current_size != start: - msg = b"truncating cache/%s to %d\n" - msg %= (_rbcrevs, start) - repo.ui.debug(msg) + threshold = current_size * REWRITE_RATIO + if (max(end, current_size) - start) < threshold: + # end affected, let overwrite the bad value + dbg = b"overwriting %d bytes from %d in cache/%s" + dbg %= (current_size - start, start, _rbcrevs) + if end < current_size: + extra = b" leaving (%d trailing bytes)" + extra %= current_size - end + dbg += extra + dbg += b'\n' + repo.ui.debug(dbg) + else: + start = 0 + dbg = b"resetting content of cache/%s\n" % _rbcrevs + repo.ui.debug(dbg) + if start > 0: f.seek(start) - f.truncate() - end = revs * _rbcrecsize - f.write(self._rbcrevs.slice(start, end)) + f.write(self._rbcrevs.slice(start, end)) + else: + f.close() + with repo.cachevfs.open( + _rbcrevs, + b'wb', + atomictemp=True, + ) as rev_file: + rev_file.write(self._rbcrevs.slice(start, end)) self._rbcrevslen = revs self._force_overwrite = False