Skip to content

Locking

A database-wide write lock with two layers: an in-process threading.RLock and a cross-process portalocker RLock on tinystore.lock.

locking

Locking for TinyStore.

Two layers, behind a single :class:LockManager abstraction:

  • Layer 1: an in-process :class:threading.RLock (reentrant within the process).
  • Layer 2: an inter-process OS-level file lock on tinystore.lock using portalocker.

Important: the mere existence of the tinystore.lock file does not imply that a lock is held. Only a successful acquire() call on the OS handle constitutes ownership of the lock. The file may persist on disk after use; that is harmless.

LockHandle

Bases: ABC

An acquired lock. Releasing is mandatory.

LockManager

Bases: ABC

Abstraction over the database-wide write lock.

acquire abstractmethod

acquire(*, timeout: float | None = None) -> LockHandle

Acquire the lock, raising :class:LockTimeoutError on timeout.

FileLockManager

FileLockManager(
    lock_file: Path, *, default_timeout: float = 30.0
)

Bases: LockManager

Default :class:LockManager using threading.RLock + portalocker.

Reentrant within a single process (the RLock allows the same thread to acquire multiple times). Across processes, portalocker provides the OS-level mutual exclusion.

The in-process RLock is shared across all :class:FileLockManager instances that point at the same lock path, so two :class:Database objects opened on the same directory within one process are still mutually excluded.