Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/virtualenv/util/lock.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 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 parent = os.path.dirname(lock_file) | |
| 17 if not os.path.exists(parent): | |
| 18 try: | |
| 19 os.makedirs(parent) | |
| 20 except OSError: | |
| 21 pass | |
| 22 super(_CountedFileLock, self).__init__(lock_file) | |
| 23 self.count = 0 | |
| 24 self.thread_safe = RLock() | |
| 25 | |
| 26 def acquire(self, timeout=None, poll_intervall=0.05): | |
| 27 with self.thread_safe: | |
| 28 if self.count == 0: | |
| 29 super(_CountedFileLock, self).acquire(timeout=timeout, poll_intervall=poll_intervall) | |
| 30 self.count += 1 | |
| 31 | |
| 32 def release(self, force=False): | |
| 33 with self.thread_safe: | |
| 34 if self.count == 1: | |
| 35 super(_CountedFileLock, self).release() | |
| 36 self.count = max(self.count - 1, 0) | |
| 37 | |
| 38 | |
| 39 _lock_store = {} | |
| 40 _store_lock = Lock() | |
| 41 | |
| 42 | |
| 43 class ReentrantFileLock(object): | |
| 44 def __init__(self, folder): | |
| 45 self._lock = None | |
| 46 path = Path(folder) | |
| 47 self.path = path.resolve() if path.exists() else path | |
| 48 | |
| 49 def __repr__(self): | |
| 50 return "{}({})".format(self.__class__.__name__, self.path) | |
| 51 | |
| 52 def __div__(self, other): | |
| 53 return ReentrantFileLock(self.path / other) | |
| 54 | |
| 55 def __truediv__(self, other): | |
| 56 return self.__div__(other) | |
| 57 | |
| 58 def _create_lock(self, name=""): | |
| 59 lock_file = str(self.path / "{}.lock".format(name)) | |
| 60 with _store_lock: | |
| 61 if lock_file not in _lock_store: | |
| 62 _lock_store[lock_file] = _CountedFileLock(lock_file) | |
| 63 return _lock_store[lock_file] | |
| 64 | |
| 65 @staticmethod | |
| 66 def _del_lock(lock): | |
| 67 with _store_lock: | |
| 68 if lock is not None: | |
| 69 with lock.thread_safe: | |
| 70 if lock.count == 0: | |
| 71 _lock_store.pop(lock.lock_file, None) | |
| 72 | |
| 73 def __del__(self): | |
| 74 self._del_lock(self._lock) | |
| 75 | |
| 76 def __enter__(self): | |
| 77 self._lock = self._create_lock() | |
| 78 self._lock_file(self._lock) | |
| 79 | |
| 80 def __exit__(self, exc_type, exc_val, exc_tb): | |
| 81 self._release(self._lock) | |
| 82 | |
| 83 def _lock_file(self, lock, no_block=False): | |
| 84 # multiple processes might be trying to get a first lock... so we cannot check if this directory exist without | |
| 85 # a lock, but that lock might then become expensive, and it's not clear where that lock should live. | |
| 86 # Instead here we just ignore if we fail to create the directory. | |
| 87 try: | |
| 88 os.makedirs(str(self.path)) | |
| 89 except OSError: | |
| 90 pass | |
| 91 try: | |
| 92 lock.acquire(0.0001) | |
| 93 except Timeout: | |
| 94 if no_block: | |
| 95 raise | |
| 96 logging.debug("lock file %s present, will block until released", lock.lock_file) | |
| 97 lock.release() # release the acquire try from above | |
| 98 lock.acquire() | |
| 99 | |
| 100 @staticmethod | |
| 101 def _release(lock): | |
| 102 lock.release() | |
| 103 | |
| 104 @contextmanager | |
| 105 def lock_for_key(self, name, no_block=False): | |
| 106 lock = self._create_lock(name) | |
| 107 try: | |
| 108 try: | |
| 109 self._lock_file(lock, no_block) | |
| 110 yield | |
| 111 finally: | |
| 112 self._release(lock) | |
| 113 finally: | |
| 114 self._del_lock(lock) | |
| 115 | |
| 116 | |
| 117 __all__ = ( | |
| 118 "Timeout", | |
| 119 "ReentrantFileLock", | |
| 120 ) |
