Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/virtualenv/util/lock.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 """holds locking functionality that works across processes""" | |
2 from __future__ import absolute_import, unicode_literals | |
3 | |
4 import logging | |
5 import os | |
6 from contextlib import contextmanager | |
7 from threading import Lock, RLock | |
8 | |
9 from filelock import FileLock, Timeout | |
10 | |
11 from virtualenv.util.path import Path | |
12 | |
13 | |
14 class _CountedFileLock(FileLock): | |
15 def __init__(self, lock_file): | |
16 super(_CountedFileLock, self).__init__(lock_file) | |
17 self.count = 0 | |
18 self.thread_safe = RLock() | |
19 | |
20 def acquire(self, timeout=None, poll_intervall=0.05): | |
21 with self.thread_safe: | |
22 if self.count == 0: | |
23 super(_CountedFileLock, self).acquire(timeout=timeout, poll_intervall=poll_intervall) | |
24 self.count += 1 | |
25 | |
26 def release(self, force=False): | |
27 with self.thread_safe: | |
28 if self.count == 1: | |
29 super(_CountedFileLock, self).release() | |
30 self.count = max(self.count - 1, 0) | |
31 | |
32 | |
33 _lock_store = {} | |
34 _store_lock = Lock() | |
35 | |
36 | |
37 class ReentrantFileLock(object): | |
38 def __init__(self, folder): | |
39 self._lock = None | |
40 path = Path(folder) | |
41 self.path = path.resolve() if path.exists() else path | |
42 | |
43 def __repr__(self): | |
44 return "{}({})".format(self.__class__.__name__, self.path) | |
45 | |
46 def __div__(self, other): | |
47 return ReentrantFileLock(self.path / other) | |
48 | |
49 def __truediv__(self, other): | |
50 return self.__div__(other) | |
51 | |
52 def _create_lock(self, name=""): | |
53 lock_file = str(self.path / "{}.lock".format(name)) | |
54 with _store_lock: | |
55 if lock_file not in _lock_store: | |
56 _lock_store[lock_file] = _CountedFileLock(lock_file) | |
57 return _lock_store[lock_file] | |
58 | |
59 @staticmethod | |
60 def _del_lock(lock): | |
61 with _store_lock: | |
62 if lock is not None: | |
63 with lock.thread_safe: | |
64 if lock.count == 0: | |
65 _lock_store.pop(lock.lock_file, None) | |
66 | |
67 def __del__(self): | |
68 self._del_lock(self._lock) | |
69 | |
70 def __enter__(self): | |
71 self._lock = self._create_lock() | |
72 self._lock_file(self._lock) | |
73 | |
74 def __exit__(self, exc_type, exc_val, exc_tb): | |
75 self._release(self._lock) | |
76 | |
77 def _lock_file(self, lock): | |
78 # multiple processes might be trying to get a first lock... so we cannot check if this directory exist without | |
79 # a lock, but that lock might then become expensive, and it's not clear where that lock should live. | |
80 # Instead here we just ignore if we fail to create the directory. | |
81 try: | |
82 os.makedirs(str(self.path)) | |
83 except OSError: | |
84 pass | |
85 try: | |
86 lock.acquire(0.0001) | |
87 except Timeout: | |
88 logging.debug("lock file %s present, will block until released", lock.lock_file) | |
89 lock.release() # release the acquire try from above | |
90 lock.acquire() | |
91 | |
92 @staticmethod | |
93 def _release(lock): | |
94 lock.release() | |
95 | |
96 @contextmanager | |
97 def lock_for_key(self, name): | |
98 lock = self._create_lock(name) | |
99 try: | |
100 try: | |
101 self._lock_file(lock) | |
102 yield | |
103 finally: | |
104 self._release(lock) | |
105 finally: | |
106 self._del_lock(lock) |