# HG changeset patch # User Pierre-Yves David # Date 1727129783 -7200 # Node ID c564be351754fbc33e7077d19a865ab201cc68a9 # Parent 7032da07557221da9af6af04a56baf5318c43027 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. diff -r 7032da075572 -r c564be351754 mercurial/branching/rev_cache.py --- 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 diff -r 7032da075572 -r c564be351754 tests/test-acl.t --- a/tests/test-acl.t Tue Sep 24 00:16:04 2024 +0200 +++ b/tests/test-acl.t Tue Sep 24 00:16:23 2024 +0200 @@ -202,7 +202,7 @@ bundle2-input-part: "phase-heads" supported bundle2-input-part: total payload size * (glob) bundle2-input-bundle: 5 parts total - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 updating the branch cache added 3 changesets with 3 changes to 3 files bundle2-output-bundle: "HG20", 1 parts total @@ -280,7 +280,7 @@ bundle2-input-part: "phase-heads" supported bundle2-input-part: total payload size * (glob) bundle2-input-bundle: 5 parts total - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 updating the branch cache added 3 changesets with 3 changes to 3 files bundle2-output-bundle: "HG20", 1 parts total @@ -355,7 +355,7 @@ bundle2-input-bundle: 5 parts total transaction abort! rollback completed - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374") no rollback information available 0:6675d58eff77 @@ -879,7 +879,7 @@ bundle2-input-bundle: 7 parts total transaction abort! rollback completed - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 abort: acl: user "fred" denied on bookmark "moving-bookmark" (changeset "ef1ea85a6374b77d6da9dcda9541f498f2d17df7") no rollback information available 0:6675d58eff77 @@ -1048,7 +1048,7 @@ bundle2-input-bundle: 5 parts total transaction abort! rollback completed - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae") no rollback information available 0:6675d58eff77 @@ -1380,7 +1380,7 @@ bundle2-input-part: "phase-heads" supported bundle2-input-part: total payload size * (glob) bundle2-input-bundle: 5 parts total - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 updating the branch cache added 3 changesets with 3 changes to 3 files bundle2-output-bundle: "HG20", 1 parts total @@ -1464,7 +1464,7 @@ bundle2-input-bundle: 5 parts total transaction abort! rollback completed - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8") no rollback information available 0:6675d58eff77 @@ -1632,7 +1632,7 @@ bundle2-input-bundle: 5 parts total transaction abort! rollback completed - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8") no rollback information available 0:6675d58eff77 diff -r 7032da075572 -r c564be351754 tests/test-branches.t --- a/tests/test-branches.t Tue Sep 24 00:16:04 2024 +0200 +++ b/tests/test-branches.t Tue Sep 24 00:16:23 2024 +0200 @@ -835,9 +835,9 @@ $ echo >> .hg/cache/rbc-revs-v1 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug 5 - truncating cache/rbc-revs-v1 to 160 + overwriting 2 bytes from 160 in cache/rbc-revs-v1 leaving (2 trailing bytes) $ f --size .hg/cache/rbc-revs* - .hg/cache/rbc-revs-v1: size=160 + .hg/cache/rbc-revs-v1: size=162 recovery from invalid cache file with partial last record $ mv .hg/cache/rbc-revs-v1 . @@ -846,7 +846,7 @@ .hg/cache/rbc-revs-v1: size=119 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug 5 - truncating cache/rbc-revs-v1 to 112 + resetting content of cache/rbc-revs-v1 $ f --size .hg/cache/rbc-revs* .hg/cache/rbc-revs-v1: size=160 @@ -869,10 +869,10 @@ $ hg log -r 'branch(.)' -T '{rev} ' --debug history modification detected - truncating revision branch cache to revision * (glob) history modification detected - truncating revision branch cache to revision 1 - 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8 + 3 4 8 9 10 11 12 13 resetting content of cache/rbc-revs-v1 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug 5 - truncating cache/rbc-revs-v1 to 104 + resetting content of cache/rbc-revs-v1 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs* .hg/cache/rbc-revs-v1: size=160 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....| @@ -893,7 +893,7 @@ .hg/cache/rbc-names-v1: size=111 $ grep "i-will-regret-this" .hg/cache/rbc-names-* > /dev/null $ f --size .hg/cache/rbc-revs-* - .hg/cache/rbc-revs-v1: size=160 + .hg/cache/rbc-revs-v1: size=168 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 diff -r 7032da075572 -r c564be351754 tests/test-rebase-conflicts.t --- a/tests/test-rebase-conflicts.t Tue Sep 24 00:16:04 2024 +0200 +++ b/tests/test-rebase-conflicts.t Tue Sep 24 00:16:23 2024 +0200 @@ -319,14 +319,14 @@ bundle2-input-part: "phase-heads" supported bundle2-input-part: total payload size 24 bundle2-input-bundle: 3 parts total - truncating cache/rbc-revs-v1 to 0 + resetting content of cache/rbc-revs-v1 added 2 changesets with 2 changes to 1 files updating the branch cache invalid branch cache (served): tip differs history modification detected - truncating revision branch cache to revision 1 invalid branch cache (served.hidden): tip differs rebase completed - truncating cache/rbc-revs-v1 to 8 + resetting content of cache/rbc-revs-v1 Test minimization of merge conflicts $ hg up -q null diff -r 7032da075572 -r c564be351754 tests/test-strip.t --- a/tests/test-strip.t Tue Sep 24 00:16:04 2024 +0200 +++ b/tests/test-strip.t Tue Sep 24 00:16:23 2024 +0200 @@ -913,7 +913,7 @@ saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/6625a5168474-345bb43d-backup.hg updating the branch cache invalid branch cache (served): tip differs - truncating cache/rbc-revs-v1 to 0 + resetting content of cache/rbc-revs-v1 $ hg log -G o changeset: 2:5c51d8d6557d | tag: tip