# HG changeset patch # User Pierre-Yves David # Date 2023-06-08 12:28:21 # Node ID 12f13b13f414c668bb18291b905908671cec3881 # Parent 978ffa09910b19a29f155d7a184e85b9f7beed93 revlog: avoid possible collision between directory and temporary index Since 6.4, we create a temporary index file to write the split data without overwriting the inline version too early. However, the store encoding does not prevent these new `.i.s` file to collide with a directory with the same name. While the odds for such a collision to happens are fairly low, the collision would prevent Mercurial from working. The store encoding have a mitigation solution in place to prevent such collisions from happening for `.i` and `.d` files, but not for other extensions. We cannot update this encoding scheme to solve the issue since it would diverge from older version of Mercurial. Instead, we create an alternative directory tree dedicated to such files. The use of the `.i` extension combined with store encoding will prevent collisions there. diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -2026,7 +2026,15 @@ class revlog: The file will only exist if a splitting operation is in progress, but it is always expected at the same location.""" - return self.radix + b'.i.s' + parts = os.path.split(self.radix) + if len(parts) > 1: + # adds a '-s' prefix to the ``data/` or `meta/` base + head = parts[0] + b'-s' + return os.path.join(head, *parts[1:]) + else: + # the revlog is stored at the root of the store (changelog or + # manifest), no risk of collision. + return self.radix + b'.i.s' def _enforceinlinesize(self, tr, side_write=True): """Check if the revlog is too big for inline and convert if so. diff --git a/tests/test-transaction-rollback-on-revlog-split.t b/tests/test-transaction-rollback-on-revlog-split.t --- a/tests/test-transaction-rollback-on-revlog-split.t +++ b/tests/test-transaction-rollback-on-revlog-split.t @@ -84,6 +84,8 @@ setup a repository for tests > Directory_With,Special%Char/Complex_File.babar > foo/bar/babar_celeste/foo > 1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/f + > some_dir/sub_dir/foo_bar + > some_dir/sub_dir/foo_bar.i.s/tutu > " $ for f in $files; do > mkdir -p `dirname $f` @@ -112,7 +114,7 @@ setup a repository for tests Reference size: $ f -s file file: size=135168 - $ f -s .hg/store/data/file* + $ f -s .hg/store/data*/file* .hg/store/data/file.d: size=267307 .hg/store/data/file.i: size=320 @@ -140,7 +142,7 @@ but truncate the index and the data to r Reference size: $ f -s file file: size=1024 - $ f -s .hg/store/data/file* + $ f -s .hg/store/data*/file* .hg/store/data/file.i: size=1174 $ cat > .hg/hgrc < .hg/hgrc < .hg/hgrc <