##// END OF EJS Templates
caches: improved locking problems with distributed lock new cache backend
super-admin -
r946:aa8791b1 stable
parent child Browse files
Show More
@@ -10,7 +10,7 b' from redis import StrictRedis'
10 __version__ = '3.7.0'
10 __version__ = '3.7.0'
11
11
12 loggers = {
12 loggers = {
13 k: getLogger("vcsserver" + ".".join((__name__, k)))
13 k: getLogger("vcsserver." + ".".join((__name__, k)))
14 for k in [
14 for k in [
15 "acquire",
15 "acquire",
16 "refresh.thread.start",
16 "refresh.thread.start",
@@ -221,10 +221,11 b' class Lock(object):'
221 """
221 """
222 logger = loggers["acquire"]
222 logger = loggers["acquire"]
223
223
224 logger.debug("Getting %r ...", self._name)
224 logger.debug("Getting acquire on %r ...", self._name)
225
225
226 if self._held:
226 if self._held:
227 raise AlreadyAcquired("Already acquired from this Lock instance.")
227 owner_id = self.get_owner_id()
228 raise AlreadyAcquired("Already acquired from this Lock instance. Lock id: {}".format(owner_id))
228
229
229 if not blocking and timeout is not None:
230 if not blocking and timeout is not None:
230 raise TimeoutNotUsable("Timeout cannot be used if blocking=False")
231 raise TimeoutNotUsable("Timeout cannot be used if blocking=False")
@@ -124,7 +124,14 b' class FileNamespaceBackend(PickleSeriali'
124
124
125 def __init__(self, arguments):
125 def __init__(self, arguments):
126 arguments['lock_factory'] = CustomLockFactory
126 arguments['lock_factory'] = CustomLockFactory
127 super(FileNamespaceBackend, self).__init__(arguments)
127 db_file = arguments.get('filename')
128
129 log.debug('initialing %s DB in %s', self.__class__.__name__, db_file)
130 try:
131 super(FileNamespaceBackend, self).__init__(arguments)
132 except Exception:
133 log.error('Failed to initialize db at: %s', db_file)
134 raise
128
135
129 def __repr__(self):
136 def __repr__(self):
130 return '{} `{}`'.format(self.__class__, self.filename)
137 return '{} `{}`'.format(self.__class__, self.filename)
@@ -141,13 +148,16 b' class FileNamespaceBackend(PickleSeriali'
141 return False
148 return False
142
149
143 with self._dbm_file(True) as dbm:
150 with self._dbm_file(True) as dbm:
144
151 try:
145 return filter(cond, dbm.keys())
152 return filter(cond, dbm.keys())
153 except Exception:
154 log.error('Failed to fetch DBM keys from DB: %s', self.get_store())
155 raise
146
156
147 def get_store(self):
157 def get_store(self):
148 return self.filename
158 return self.filename
149
159
150 def get(self, key):
160 def _dbm_get(self, key):
151 with self._dbm_file(False) as dbm:
161 with self._dbm_file(False) as dbm:
152 if hasattr(dbm, 'get'):
162 if hasattr(dbm, 'get'):
153 value = dbm.get(key, NO_VALUE)
163 value = dbm.get(key, NO_VALUE)
@@ -161,6 +171,13 b' class FileNamespaceBackend(PickleSeriali'
161 value = self._loads(value)
171 value = self._loads(value)
162 return value
172 return value
163
173
174 def get(self, key):
175 try:
176 return self._dbm_get(key)
177 except Exception:
178 log.error('Failed to fetch DBM key %s from DB: %s', key, self.get_store())
179 raise
180
164 def set(self, key, value):
181 def set(self, key, value):
165 with self._dbm_file(True) as dbm:
182 with self._dbm_file(True) as dbm:
166 dbm[key] = self._dumps(value)
183 dbm[key] = self._dumps(value)
@@ -235,17 +252,16 b' class BaseRedisBackend(redis_backend.Red'
235
252
236 def get_mutex(self, key):
253 def get_mutex(self, key):
237 if self.distributed_lock:
254 if self.distributed_lock:
238 import redis_lock
239 lock_key = redis_backend.u('_lock_{0}').format(key)
255 lock_key = redis_backend.u('_lock_{0}').format(key)
240 log.debug('Trying to acquire Redis lock for key %s', lock_key)
256 log.debug('Trying to acquire Redis lock for key %s', lock_key)
241 lock = redis_lock.Lock(
257
242 redis_client=self.client,
258 auto_renewal = True
243 name=lock_key,
259 lock_timeout = self.lock_timeout
244 expire=self.lock_timeout,
260 if auto_renewal and not self.lock_timeout:
245 auto_renewal=False,
261 # set default timeout for auto_renewal
246 strict=True,
262 lock_timeout = 10
247 )
263 return get_mutex_lock(self.client, lock_key, lock_timeout,
248 return lock
264 auto_renewal=auto_renewal)
249 else:
265 else:
250 return None
266 return None
251
267
@@ -258,3 +274,34 b' class RedisPickleBackend(PickleSerialize'
258 class RedisMsgPackBackend(MsgPackSerializer, BaseRedisBackend):
274 class RedisMsgPackBackend(MsgPackSerializer, BaseRedisBackend):
259 key_prefix = 'redis_msgpack_backend'
275 key_prefix = 'redis_msgpack_backend'
260 pass
276 pass
277
278
279 def get_mutex_lock(client, lock_key, lock_timeout, auto_renewal=False):
280 import redis_lock
281
282 class _RedisLockWrapper(object):
283 """LockWrapper for redis_lock"""
284
285 def __init__(self):
286 pass
287
288 @property
289 def lock(self):
290 return redis_lock.Lock(
291 redis_client=client,
292 name=lock_key,
293 expire=lock_timeout,
294 auto_renewal=auto_renewal,
295 strict=True,
296 )
297
298 def acquire(self, wait=True):
299 return self.lock.acquire(wait)
300
301 def release(self):
302 try:
303 self.lock.release()
304 except redis_lock.NotAcquired:
305 pass
306
307 return _RedisLockWrapper()
General Comments 0
You need to be logged in to leave comments. Login now