Extract LockDict class

This commit is contained in:
Unrud 2021-12-12 19:36:19 +01:00
parent 91c06041f8
commit 90bd33f466

View File

@ -20,7 +20,7 @@ The multifilesystem backend without file-based locking.
import threading import threading
from collections import deque from collections import deque
from typing import Deque, Dict, Iterator, Tuple from typing import Deque, Dict, Hashable, Iterator
from radicale import config, pathutils, types from radicale import config, pathutils, types
from radicale.storage import multifilesystem from radicale.storage import multifilesystem
@ -56,20 +56,21 @@ class RwLock(pathutils.RwLock):
self._cond.notify() self._cond.notify()
class Collection(multifilesystem.Collection): class LockDict:
_storage: "Storage" _lock: threading.Lock
_dict: Dict[Hashable, Deque[threading.Lock]]
def __init__(self) -> None:
self._lock = threading.Lock()
self._dict = {}
@types.contextmanager @types.contextmanager
def _acquire_cache_lock(self, ns: str = "") -> Iterator[None]: def acquire(self, key: Hashable) -> Iterator[None]:
if self._storage._lock.locked == "w": with self._lock:
yield waiters = self._dict.get(key)
return
key = (self.path, ns)
with self._storage._cache_lock:
waiters = self._storage._cache_locks.get(key)
if waiters is None: if waiters is None:
self._storage._cache_locks[key] = waiters = deque() self._dict[key] = waiters = deque()
wait = bool(waiters) wait = bool(waiters)
waiter = threading.Lock() waiter = threading.Lock()
waiter.acquire() waiter.acquire()
@ -79,25 +80,34 @@ class Collection(multifilesystem.Collection):
try: try:
yield yield
finally: finally:
with self._storage._cache_lock: with self._lock:
removedWaiter = waiters.popleft() del waiters[0]
assert removedWaiter is waiter
if waiters: if waiters:
waiters[0].release() waiters[0].release()
else: else:
removedWaiters = self._storage._cache_locks.pop(key) del self._dict[key]
assert removedWaiters is waiters
class Collection(multifilesystem.Collection):
_storage: "Storage"
@types.contextmanager
def _acquire_cache_lock(self, ns: str = "") -> Iterator[None]:
if self._storage._lock.locked == "w":
yield
return
with self._storage._cache_lock.acquire((self.path, ns)):
yield
class Storage(multifilesystem.Storage): class Storage(multifilesystem.Storage):
_collection_class = Collection _collection_class = Collection
_cache_lock: threading.Lock _cache_lock: LockDict
_cache_locks: Dict[Tuple[str, str], Deque[threading.Lock]]
def __init__(self, configuration: config.Configuration) -> None: def __init__(self, configuration: config.Configuration) -> None:
super().__init__(configuration) super().__init__(configuration)
self._lock = RwLock() self._lock = RwLock()
self._cache_lock = threading.Lock() self._cache_lock = LockDict()
self._cache_locks = {}