comparison mercurial/util.py @ 51966:bc9ed92d4753

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
author Matt Harbison <matt_harbison@yahoo.com>
date Tue, 01 Oct 2024 15:00:39 -0400
parents cbd01bf33802
children 2d51b0cf707c
comparison
equal deleted inserted replaced
51965:93d872a06132 51966:bc9ed92d4753
483 # rather than "zero bytes", so special case that. 483 # rather than "zero bytes", so special case that.
484 return b'' 484 return b''
485 elif size is None: 485 elif size is None:
486 size = 0 486 size = 0
487 fd = getattr(fp, 'fileno', lambda: fp)() 487 fd = getattr(fp, 'fileno', lambda: fp)()
488 flags = mmap.MAP_PRIVATE 488
489 bg_populate = hasattr(osutil, "background_mmap_populate") 489 if pycompat.iswindows:
490 if pre_populate and not bg_populate: 490 _mmap = lambda fd, size: mmap.mmap(fd, size, access=mmap.ACCESS_READ)
491 flags |= getattr(mmap, 'MAP_POPULATE', 0) 491 else:
492 flags = mmap.MAP_PRIVATE
493 bg_populate = hasattr(osutil, "background_mmap_populate")
494
495 if pre_populate and not bg_populate:
496 flags |= getattr(mmap, 'MAP_POPULATE', 0)
497
498 def _mmap(fd, size) -> mmap.mmap:
499 m = mmap.mmap(fd, size, flags=flags, prot=mmap.PROT_READ)
500 if pre_populate and bg_populate:
501 osutil.background_mmap_populate(m)
502 return m
503
492 try: 504 try:
493 m = mmap.mmap(fd, size, flags=flags, prot=mmap.PROT_READ) 505 return _mmap(fd, size)
494 if pre_populate and bg_populate:
495 osutil.background_mmap_populate(m)
496 return m
497 except ValueError: 506 except ValueError:
498 # Empty files cannot be mmapped, but mmapread should still work. Check 507 # Empty files cannot be mmapped, but mmapread should still work. Check
499 # if the file is empty, and if so, return an empty buffer. 508 # if the file is empty, and if so, return an empty buffer.
500 if os.fstat(fd).st_size == 0: 509 if os.fstat(fd).st_size == 0:
501 return b'' 510 return b''