]>
Commit | Line | Data |
---|---|---|
92f5a8d4 | 1 | from contextlib import contextmanager |
f91f0fd5 | 2 | import logging |
92f5a8d4 | 3 | from threading import Lock |
9f95a23c | 4 | from typing import Dict |
92f5a8d4 | 5 | |
f91f0fd5 TL |
6 | log = logging.getLogger(__name__) |
7 | ||
92f5a8d4 TL |
8 | # singleton design pattern taken from http://www.aleax.it/5ep.html |
9 | ||
10 | class GlobalLock(object): | |
11 | """ | |
12 | Global lock to serialize operations in mgr/volumes. This lock | |
13 | is currently held when accessing (opening) a volume to perform | |
14 | group/subvolume operations. Since this is a big lock, it's rather | |
15 | inefficient -- but right now it's ok since mgr/volumes does not | |
16 | expect concurrent operations via its APIs. | |
17 | ||
18 | As and when features get added (such as clone, where mgr/volumes | |
19 | would maintain subvolume states in the filesystem), there might | |
20 | be a need to allow concurrent operations. In that case it would | |
21 | be nice to implement an efficient path based locking mechanism. | |
22 | ||
23 | See: https://people.eecs.berkeley.edu/~kubitron/courses/cs262a-F14/projects/reports/project6_report.pdf | |
24 | """ | |
25 | _shared_state = { | |
26 | 'lock' : Lock(), | |
27 | 'init' : False | |
9f95a23c | 28 | } # type: Dict |
92f5a8d4 TL |
29 | |
30 | def __init__(self): | |
31 | with self._shared_state['lock']: | |
32 | if not self._shared_state['init']: | |
33 | self._shared_state['init'] = True | |
34 | # share this state among all instances | |
35 | self.__dict__ = self._shared_state | |
36 | ||
37 | @contextmanager | |
38 | def lock_op(self): | |
f91f0fd5 | 39 | log.debug("entering global lock") |
92f5a8d4 | 40 | with self._shared_state['lock']: |
f91f0fd5 | 41 | log.debug("acquired global lock") |
92f5a8d4 | 42 | yield |
f91f0fd5 | 43 | log.debug("exited global lock") |