summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy McCurdy <andy@andymccurdy.com>2014-06-05 22:45:47 -0400
committerAndy McCurdy <andy@andymccurdy.com>2014-06-05 22:45:47 -0400
commit318bab78eba9e3a5cc7f93f3e865ecb2e05cba76 (patch)
tree534c5368280f62fd0c16b8f31468d7c34c5e9649
parentd6fc144c8db08d087b67c919a49fdc1f87bb3cb5 (diff)
parenta48c2d84fa9606fe3b83ad95061672de54865e2e (diff)
downloadredis-py-318bab78eba9e3a5cc7f93f3e865ecb2e05cba76.tar.gz
Merge pull request #491 from dystedium/fixlock3
move Lock.token attribute into thread-local storage
-rw-r--r--redis/lock.py18
-rw-r--r--tests/test_lock.py6
2 files changed, 13 insertions, 11 deletions
diff --git a/redis/lock.py b/redis/lock.py
index e6070c4..adf90e0 100644
--- a/redis/lock.py
+++ b/redis/lock.py
@@ -1,3 +1,4 @@
+import threading
import time as mod_time
import uuid
from redis.exceptions import LockError, WatchError
@@ -44,7 +45,8 @@ class Lock(object):
self.sleep = sleep
self.blocking = blocking
self.blocking_timeout = blocking_timeout
- self.token = None
+ self.local = threading.local()
+ self.local.token = None
if self.timeout and self.sleep > self.timeout:
raise LockError("'sleep' must be less than 'timeout'")
@@ -79,7 +81,7 @@ class Lock(object):
stop_trying_at = mod_time.time() + self.blocking_timeout
while 1:
if self.do_acquire(token):
- self.token = token
+ self.local.token = token
return True
if not blocking:
return False
@@ -98,10 +100,10 @@ class Lock(object):
def release(self):
"Releases the already acquired lock"
- if self.token is None:
+ expected_token = self.local.token
+ if expected_token is None:
raise LockError("Cannot release an unlocked lock")
- expected_token = self.token
- self.token = None
+ self.local.token = None
self.do_release(expected_token)
def do_release(self, expected_token):
@@ -122,7 +124,7 @@ class Lock(object):
``additional_time`` can be specified as an integer or a float, both
representing the number of seconds to add.
"""
- if self.token is None:
+ if self.local.token is None:
raise LockError("Cannot extend an unlocked lock")
if self.timeout is None:
raise LockError("Cannot extend a lock with no timeout")
@@ -132,7 +134,7 @@ class Lock(object):
pipe = self.redis.pipeline()
pipe.watch(self.name)
lock_value = pipe.get(self.name)
- if lock_value != self.token:
+ if lock_value != self.local.token:
raise LockError("Cannot extend a lock that's no longer owned")
expiration = pipe.pttl(self.name)
if expiration is None or expiration < 0:
@@ -236,7 +238,7 @@ class LuaLock(Lock):
def do_extend(self, additional_time):
additional_time = int(additional_time * 1000)
if not bool(self.lua_extend(keys=[self.name],
- args=[self.token, additional_time],
+ args=[self.local.token, additional_time],
client=self.redis)):
raise LockError("Cannot extend a lock that's no longer owned")
return True
diff --git a/tests/test_lock.py b/tests/test_lock.py
index 028f9a6..d732ae1 100644
--- a/tests/test_lock.py
+++ b/tests/test_lock.py
@@ -16,7 +16,7 @@ class TestLock(object):
def test_lock(self, sr):
lock = self.get_lock(sr, 'foo')
assert lock.acquire(blocking=False)
- assert sr.get('foo') == lock.token
+ assert sr.get('foo') == lock.local.token
assert sr.ttl('foo') == -1
lock.release()
assert sr.get('foo') is None
@@ -56,7 +56,7 @@ class TestLock(object):
# blocking_timeout prevents a deadlock if the lock can't be acquired
# for some reason
with self.get_lock(sr, 'foo', blocking_timeout=0.2) as lock:
- assert sr.get('foo') == lock.token
+ assert sr.get('foo') == lock.local.token
assert sr.get('foo') is None
def test_high_sleep_raises_error(self, sr):
@@ -77,7 +77,7 @@ class TestLock(object):
with pytest.raises(LockError):
lock.release()
# even though we errored, the token is still cleared
- assert lock.token is None
+ assert lock.local.token is None
def test_extend_lock(self, sr):
lock = self.get_lock(sr, 'foo', timeout=10)