Source: src/mcss/file_lock.py · Plain text

src/mcss/file_lock.py

"""Nonblocking advisory process locks for dataset maintenance scripts.

Windows retains the original one-byte msvcrt lock. POSIX uses an exclusive
flock on the open file description. Closing the handle releases either lock;
lock files may remain on disk and can safely be reused after a process exits.
"""

from __future__ import annotations

import os
from typing import BinaryIO


def acquire_file_lock(handle: BinaryIO) -> None:
    """Lock an open, nonempty file without waiting; contention raises OSError."""
    if os.name == "nt":
        import msvcrt

        handle.seek(0)
        msvcrt.locking(handle.fileno(), msvcrt.LK_NBLCK, 1)
    else:
        import fcntl

        fcntl.flock(handle.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)


def release_file_lock(handle: BinaryIO) -> None:
    """Release a previously acquired file lock without deleting its file."""
    if os.name == "nt":
        import msvcrt

        handle.seek(0)
        msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1)
    else:
        import fcntl

        fcntl.flock(handle.fileno(), fcntl.LOCK_UN)