aeat.core.locks module

Cross-platform exclusive file locking.

The helper exposes exclusive_file_lock(), a context manager that acquires an OS-level exclusive lock on a sidecar file alongside a protected resource. Two operating-system primitives back the helper:

  • POSIX (Linux, macOS): fcntl.flock() with LOCK_EX | LOCK_NB.

  • Windows: msvcrt.locking() with LK_NBLCK against a one-byte region of the lock file.

The wait loop is identical across platforms: try the non-blocking acquire, sleep for a small backoff interval, retry until the timeout elapses. On timeout the helper raises LockAcquisitionError (category LOCKED in the error registry).

The lock file is created adjacent to the protected path by appending the suffix .lock. The lock fd is held for the duration of the context. The lock file itself is left on disk after release; cleanup of stale lock files is the consumer’s responsibility because deleting the file while another process is racing to acquire it would create a TOCTOU window.

This primitive is deliberately metadata-free. It does not write a PID, hostname, profile id, timeout stamp, or secure-storage custody state into the sidecar file, and it does not perform stale-lock recovery. Consumers that need recoverable lock records, bucket ownership, or auth-acquisition TTL semantics own those protocols above this OS-lock layer.

DEFAULT_LOCK_TIMEOUT: Final[_DefaultLockTimeout]

Sentinel for exclusive_file_lock() timeout; resolves at call time.

fsync_parent_dir(target)[source]

Best-effort fsync of the directory containing target.

POSIX-only — Windows does not support fsync against a directory handle (os.O_DIRECTORY is not defined), and on Windows the directory entry is updated atomically with os.replace anyway.

Used after an os.replace swap-in to ensure the directory entry update is durable across power loss. Without this, a crash between os.replace and the next directory flush could leave the entry in an inconsistent state on POSIX filesystems where file fsync does not imply directory fsync (ext4, xfs, etc.).

The function never raises — directory fsync is a best-effort durability hardening, not a correctness gate. Callers that hit a sandboxed-/read-only-/non-directory FD path should not see a spurious failure on top of an otherwise-successful atomic replace.

This helper hardens file-system durability after callers perform their own atomic write/replace sequence. It does not acquire a lock, validate payload contents, or convert a plaintext file into secure storage.

Return type:

None

Parameters:

target (Path)

exclusive_file_lock(target, *, timeout=DEFAULT_LOCK_TIMEOUT, retry_backoff=DEFAULT_LOCK_TIMEOUT)[source]

Acquire an OS-level exclusive lock on a sidecar lock file.

The sidecar lock file is created alongside target with the suffix .lock. The caller is expected to use the lock to coordinate concurrent access to target. The lock is released when the context manager exits, whether normally or via exception. The lock file itself is left on disk so a racing acquirer never sees a transient missing-file state.

On Windows msvcrt.locking enforces a mandatory lock against a single byte of the lock file. On POSIX fcntl.flock is advisory — readers that do not also acquire the lock can still observe the protected resource mid-write. Callers MUST treat the lock as advisory across the whole file regardless of the underlying primitive.

The sidecar carries no ownership metadata and is not deleted on release. This is a generic local coordination primitive for atomic file updates; higher-level bucket lockfiles, auth acquisition locks, and secure-object sessions provide their own holder records, TTLs, custody checks, and recovery rules.

Parameters:
  • target (Path) – Path to the resource being protected. The lock sidecar is created at <target>.lock. The parent directory must exist before the call.

  • timeout (float | _DefaultLockTimeout) – Maximum time in seconds to wait for the lock. Defaults to DEFAULT_LOCK_TIMEOUT. 0 requests a single non- blocking attempt.

  • retry_backoff (float | _DefaultLockTimeout) – Sleep interval between non-blocking attempts. Tests may shorten this; defaults to 0.05.

Yields:

The Path of the acquired lock sidecar.

Raises:

LockAcquisitionError – If the lock cannot be acquired within timeout seconds, or if timeout is negative. The error category is LOCKED and retryable is True. The retryable flag means “another acquirer may release shortly and the operation could succeed on retry”; consumers that retry MUST bound the retry budget themselves.

Return type:

Iterator[Path]