From 57422baf1787710122c9523170b17b8aa978b224 Mon Sep 17 00:00:00 2001 From: zhen Date: Fri, 20 May 2022 15:57:53 +0800 Subject: [PATCH] Fix inappropriate logic in memcachedlock.release() Whether 'was_deleted' was 'TRUE' or not, eventually we have to remove self from '_acquired_locks'. For example: 1. App #1 with coordinator 'A' wants to release lock "b" 2. 'self.coord.client.delete()' failed for some reason(.e.g, BrokenPipeError,MemcacheUnexpectedCloseError) 3. According to the former logic,lock "b" will not remove from "_acquired_locks", so "self.heartbeat()" will make it alive forever until App #1 was down or lock "b" turned expired. 4. Now App #1 with coordinator 'A' wants to acquire lock "c", who have the same lock-name with lock "b",It is clear that this will fail and prevent the locked program from continuing to execute. Change-Id: I6fc33b8e0a88510027bcfc30d1504489d2a91b4e --- tooz/drivers/memcached.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tooz/drivers/memcached.py b/tooz/drivers/memcached.py index 1cefd954..6dacd77f 100644 --- a/tooz/drivers/memcached.py +++ b/tooz/drivers/memcached.py @@ -152,10 +152,24 @@ class MemcachedLock(locking.Lock): if value != self.coord._member_id: return False else: - was_deleted = self.coord.client.delete(self.name, noreply=False) - if was_deleted: + # NOTE(zhen): Whether 'was_deleted' was 'TRUE' or not, + # eventually we have to remove self from '_acquired_locks'. + # + # For example: + # 1. App #1 with coordinator 'A' wants to release lock "b" + # 2. 'self.coord.client.delete()' failed for some reason(.e.g, + # BrokenPipeError,MemcacheUnexpectedCloseError) + # 3. According to the former logic,lock "b" will not remove + # from "_acquired_locks", so "self.heartbeat()" will make it alive + # forever until App #1 was down or lock "b" turned expired. + # 4. Now App #1 with coordinator 'A' wants to acquire lock "c", who + # have the same lock-name with lock "b",It is clear that this will + # fail and prevent the locked program from continuing to execute. + try: + was_deleted = self.coord.client.delete(self.name, noreply=False) + finally: self.coord._acquired_locks.remove(self) - return was_deleted + return was_deleted @_translate_failures def heartbeat(self):