Mercurial > hg-stable
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'' |