diff options
author | Andy McCurdy <andy@andymccurdy.com> | 2014-05-27 13:40:41 -0700 |
---|---|---|
committer | Andy McCurdy <andy@andymccurdy.com> | 2014-05-31 16:10:51 -0700 |
commit | be6e501d046c9fb7ef86a47ec3b276a22997e900 (patch) | |
tree | 081b1aca39090978989da9057785887768b8b7ec | |
parent | 967742f6140d1379d0ac80a60d257a5b9876752c (diff) | |
download | redis-py-be6e501d046c9fb7ef86a47ec3b276a22997e900.tar.gz |
move Lock class to it's own module
-rwxr-xr-x | redis/client.py | 93 | ||||
-rw-r--r-- | redis/exceptions.py | 4 | ||||
-rw-r--r-- | tests/test_lock.py | 2 |
3 files changed, 6 insertions, 93 deletions
diff --git a/redis/client.py b/redis/client.py index 511df4d..efce1d8 100755 --- a/redis/client.py +++ b/redis/client.py @@ -9,6 +9,7 @@ from redis._compat import (b, basestring, bytes, imap, iteritems, iterkeys, itervalues, izip, long, nativestr, unicode) from redis.connection import (ConnectionPool, UnixDomainSocketConnection, SSLConnection, Token) +from redis.lock import Lock from redis.exceptions import ( ConnectionError, DataError, @@ -2576,95 +2577,3 @@ class Script(object): # that created this instance? self.sha = client.script_load(self.script) return client.evalsha(self.sha, len(keys), *args) - - -class LockError(RedisError): - "Errors thrown from the Lock" - pass - - -class Lock(object): - """ - A shared, distributed Lock. Using Redis for locking allows the Lock - to be shared across processes and/or machines. - - It's left to the user to resolve deadlock issues and make sure - multiple clients play nicely together. - """ - - LOCK_FOREVER = float(2 ** 31 + 1) # 1 past max unix time - - def __init__(self, redis, name, timeout=None, sleep=0.1): - """ - Create a new Lock instance named ``name`` using the Redis client - supplied by ``redis``. - - ``timeout`` indicates a maximum life for the lock. - By default, it will remain locked until release() is called. - - ``sleep`` indicates the amount of time to sleep per loop iteration - when the lock is in blocking mode and another client is currently - holding the lock. - - Note: If using ``timeout``, you should make sure all the hosts - that are running clients have their time synchronized with a network - time service like ntp. - """ - self.redis = redis - self.name = name - self.acquired_until = None - self.timeout = timeout - self.sleep = sleep - if self.timeout and self.sleep > self.timeout: - raise LockError("'sleep' must be less than 'timeout'") - - def __enter__(self): - return self.acquire() - - def __exit__(self, exc_type, exc_value, traceback): - self.release() - - def acquire(self, blocking=True): - """ - Use Redis to hold a shared, distributed lock named ``name``. - Returns True once the lock is acquired. - - If ``blocking`` is False, always return immediately. If the lock - was acquired, return True, otherwise return False. - """ - sleep = self.sleep - timeout = self.timeout - while 1: - unixtime = mod_time.time() - if timeout: - timeout_at = unixtime + timeout - else: - timeout_at = Lock.LOCK_FOREVER - timeout_at = float(timeout_at) - if self.redis.setnx(self.name, timeout_at): - self.acquired_until = timeout_at - return True - # We want blocking, but didn't acquire the lock - # check to see if the current lock is expired - existing = float(self.redis.get(self.name) or 1) - if existing < unixtime: - # the previous lock is expired, attempt to overwrite it - existing = float(self.redis.getset(self.name, timeout_at) or 1) - if existing < unixtime: - # we successfully acquired the lock - self.acquired_until = timeout_at - return True - if not blocking: - return False - mod_time.sleep(sleep) - - def release(self): - "Releases the already acquired lock" - if self.acquired_until is None: - raise ValueError("Cannot release an unlocked lock") - existing = float(self.redis.get(self.name) or 1) - # if the lock time is in the future, delete the lock - delete_lock = existing >= self.acquired_until - self.acquired_until = None - if delete_lock: - self.redis.delete(self.name) diff --git a/redis/exceptions.py b/redis/exceptions.py index b8b81dc..6ab5a6e 100644 --- a/redis/exceptions.py +++ b/redis/exceptions.py @@ -62,3 +62,7 @@ class ExecAbortError(ResponseError): class ReadOnlyError(ResponseError): pass + + +class LockError(RedisError): + pass diff --git a/tests/test_lock.py b/tests/test_lock.py index 7c6bb3d..a31f5f1 100644 --- a/tests/test_lock.py +++ b/tests/test_lock.py @@ -2,7 +2,7 @@ from __future__ import with_statement import pytest import time -from redis.client import Lock, LockError +from redis.lock import Lock, LockError class TestLock(object): |