util: make `mmapread()` work on Windows again
522b4d729e89 started referencing `mmap.MAP_PRIVATE`, but that's not available on
Windows, so `hg version` worked, but `make local` did not. That commit also
started calling the constructor with the fine-grained `flags` and `prot` args,
but those aren't available on Windows either[1] (though the backing C code
doesn't seem conditionalized to disallow usage of them).
I assume the change away from from the `access` arg was to provide the same
options, plus `MAP_POPULATE`. Looking at the source code[2], they're not quite
the same- `ACCESS_READ` is equivalent to `flags = MAP_SHARED` and `prot = PROT_READ`.
`MAP_PRIVATE` is only used with `ACCESS_COPY`, which allows read and write.
Therefore, we can't quite get the same baseline flags on Windows, but this was
the status quo ante and `MAP_POPULATE` is a Linux thing, so presumably it works.
I realize that typically the OS differences are abstracted into the platform
modules, but I'm leaving it here so that it is obvious what the differences are
between the platforms.
[1] https://docs.python.org/3/library/mmap.html#mmap.mmap
[2] https://github.com/python/cpython/blob/
5e0abb47886bc665eefdcc19fde985f803e49d4c/Modules/mmapmodule.c#L1539
--- a/mercurial/util.py Fri Sep 27 12:30:37 2024 -0400
+++ b/mercurial/util.py Tue Oct 01 15:00:39 2024 -0400
@@ -485,15 +485,24 @@
elif size is None:
size = 0
fd = getattr(fp, 'fileno', lambda: fp)()
- flags = mmap.MAP_PRIVATE
- bg_populate = hasattr(osutil, "background_mmap_populate")
- if pre_populate and not bg_populate:
- flags |= getattr(mmap, 'MAP_POPULATE', 0)
+
+ if pycompat.iswindows:
+ _mmap = lambda fd, size: mmap.mmap(fd, size, access=mmap.ACCESS_READ)
+ else:
+ flags = mmap.MAP_PRIVATE
+ bg_populate = hasattr(osutil, "background_mmap_populate")
+
+ if pre_populate and not bg_populate:
+ flags |= getattr(mmap, 'MAP_POPULATE', 0)
+
+ def _mmap(fd, size) -> mmap.mmap:
+ m = mmap.mmap(fd, size, flags=flags, prot=mmap.PROT_READ)
+ if pre_populate and bg_populate:
+ osutil.background_mmap_populate(m)
+ return m
+
try:
- m = mmap.mmap(fd, size, flags=flags, prot=mmap.PROT_READ)
- if pre_populate and bg_populate:
- osutil.background_mmap_populate(m)
- return m
+ return _mmap(fd, size)
except ValueError:
# Empty files cannot be mmapped, but mmapread should still work. Check
# if the file is empty, and if so, return an empty buffer.