34 lines
1.6 KiB
Python
34 lines
1.6 KiB
Python
"""Блокировка файла БД: гарантирует, что с одной файловой БД работает не больше одного процесса
|
|||
|
|
(семафор задач, _sync_lock, кэш бакета и счётчики неудачных паролей — состояние процесса, не БД).
|
||
|
|
Берётся в lifespan до init_db, снимается при остановке."""
|
||
|
|
import fcntl
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
_lock_file = None # открытый дескриптор блокировки текущего процесса (None — не бралась)
|
||
|
|
|
||
|
|
|
||
|
|
def acquire(database_url: str) -> None:
|
||
|
|
global _lock_file
|
||
|
|
if not (database_url.startswith("sqlite:///") and ":memory:" not in database_url):
|
||
|
|
return # :memory: и не-SQLite URL — блокировка не нужна
|
||
|
|
db_path = Path(database_url.removeprefix("sqlite:///"))
|
||
|
|
db_path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
|
lock_path = db_path.with_name(db_path.name + ".lock")
|
||
|
|
f = open(lock_path, "w")
|
||
|
|
try:
|
||
|
|
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||
|
|
except OSError:
|
||
|
|
f.close()
|
||
|
|
raise RuntimeError(
|
||
|
|
f"БД {db_path} уже используется другим процессом ros_control: "
|
||
|
|
"поддерживается только один процесс (--workers 1)"
|
||
|
|
) from None
|
||
|
|
_lock_file = f
|
||
|
|
|
||
|
|
|
||
|
|
def release() -> None:
|
||
|
|
global _lock_file
|
||
|
|
if _lock_file is not None:
|
||
|
|
fcntl.flock(_lock_file, fcntl.LOCK_UN)
|
||
|
|
_lock_file.close()
|
||
|
|
_lock_file = None
|