From 059f2ae5406a325017ad181ace1e5b7c5bff0d22 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 18 Mar 2017 10:33:57 +0100 Subject: [PATCH] redis: fix concurrent access on acquire() Redis-py is not thread safe and in lock management, which means the following can also happen: 1. lock.acquire() 2a. lock.release() ---\_ at the same time for all 2. operations 2b. lock.acquire() ---/ 2c. lock.heartbeat() / which means the lock can be when a lock is already acquired and in the process of being released and re-acquired in paralllel: 1. acquire() acquire the lock (self._lock.acquire()) 2. release() release the lock (self._lock.release()) and remove it from self._lock.acquire() where it's not (discard() does not raise on non-existing element) 3. acquire() put the lock in _acquired_locks 4. heartbeat() iterates on _acquired_locks and try to extend a lock that indeed was acquired but was in the mean time released by Redis. Change-Id: Ib9549b44485cb15de312ec9dfa57b148cb45e2c9 Closes-Bug: #1557593 --- tooz/drivers/redis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tooz/drivers/redis.py b/tooz/drivers/redis.py index 6152e134..84527a05 100644 --- a/tooz/drivers/redis.py +++ b/tooz/drivers/redis.py @@ -86,7 +86,8 @@ class RedisLock(locking.Lock): acquired = self._lock.acquire( blocking=blocking, blocking_timeout=timeout) if acquired: - self._coord._acquired_locks.add(self) + with self._exclusive_access: + self._coord._acquired_locks.add(self) return acquired def release(self):