Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a private _PEX_FILE_LOCK_STYLE knob. #1962

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions pex/atomic_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,26 @@ class Value(Enum.Value):
POSIX = Value("posix")


def _is_bsd_lock(lock_style=None):
# type: (Optional[FileLockStyle.Value]) -> bool

# The atomic_directory file locking has used POSIX locks since inception. These have maximum
# compatibility across OSes and stand a decent chance of working over modern NFS. With the
# introduction of `pex3 lock ...` a limited set of atomic_directory uses started asking for BSD
# locks since they operate in a thread pool. Only those uses actually pass an explicit value for
# `lock_style` to atomic_directory. In order to allow experimenting with / debugging possible
# file locking bugs, we allow a `_PEX_FILE_LOCK_STYLE` back door private ~API to upgrade all
# locks to BSD style locks. This back door can be removed at any time.
file_lock_style = lock_style or FileLockStyle.for_value(
os.environ.get("_PEX_FILE_LOCK_STYLE", FileLockStyle.POSIX.value)
)
return file_lock_style is FileLockStyle.BSD


@contextmanager
def atomic_directory(
target_dir, # type: str
lock_style=FileLockStyle.POSIX, # type: FileLockStyle.Value
lock_style=None, # type: Optional[FileLockStyle.Value]
source=None, # type: Optional[str]
):
# type: (...) -> Iterator[AtomicDirectory]
Expand Down Expand Up @@ -125,7 +141,7 @@ def atomic_directory(

lock_api = cast(
"Callable[[int, int], None]",
fcntl.flock if lock_style is FileLockStyle.BSD else fcntl.lockf,
fcntl.flock if _is_bsd_lock(lock_style) else fcntl.lockf,
)

def unlock():
Expand Down
28 changes: 28 additions & 0 deletions tests/test_atomic_directory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from pex.atomic_directory import FileLockStyle, _is_bsd_lock
from pex.testing import environment_as


def test_is_bsd_lock():
# type: () -> None

assert not _is_bsd_lock(
lock_style=None
), "Expected the default lock style to be POSIX for maximum compatibility."
assert not _is_bsd_lock(lock_style=FileLockStyle.POSIX)
assert _is_bsd_lock(lock_style=FileLockStyle.BSD)

# The hard-coded default is already POSIX, so setting the env var default changes nothing.
with environment_as(_PEX_FILE_LOCK_STYLE="posix"):
assert not _is_bsd_lock(lock_style=None)
assert not _is_bsd_lock(lock_style=FileLockStyle.POSIX)
assert _is_bsd_lock(lock_style=FileLockStyle.BSD)

with environment_as(_PEX_FILE_LOCK_STYLE="bsd"):
assert _is_bsd_lock(
lock_style=None
), "Expected the default lock style to be taken from the environment when defined."
assert not _is_bsd_lock(lock_style=FileLockStyle.POSIX)
assert _is_bsd_lock(lock_style=FileLockStyle.BSD)