45 lines
1.2 KiB
Python
45 lines
1.2 KiB
Python
"""Lock hierarchy and acquisition ordering.
|
|
|
|
Locks are acquired broad → narrow to prevent deadlocks: never take a broader lock
|
|
while holding a narrower one (concept §16). The coordinator already enforces
|
|
one active job per lock key; this guards multi-lock operations.
|
|
|
|
library lease → stage/job lease → album/folder lease → asset lease
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Iterable
|
|
|
|
# Lower rank = broader scope. Mutating lanes map onto these tiers.
|
|
LOCK_RANK = {
|
|
"library": 0,
|
|
"library_write": 0,
|
|
"rename": 1,
|
|
"upload": 1,
|
|
"archive": 1,
|
|
"album": 2,
|
|
"asset": 3,
|
|
"exif": 3,
|
|
}
|
|
|
|
|
|
class LockOrderError(RuntimeError):
|
|
pass
|
|
|
|
|
|
def rank(lock: str) -> int:
|
|
if lock not in LOCK_RANK:
|
|
raise LockOrderError(f"unknown lock {lock!r}")
|
|
return LOCK_RANK[lock]
|
|
|
|
|
|
def validate_acquisition(held: Iterable[str], acquiring: str) -> None:
|
|
"""Reject acquiring a broader lock than one already held (deadlock risk)."""
|
|
new_rank = rank(acquiring)
|
|
for lock in held:
|
|
if rank(lock) > new_rank:
|
|
raise LockOrderError(
|
|
f"cannot acquire broader lock {acquiring!r} while holding narrower {lock!r}"
|
|
)
|