diff --git a/PandaPkgInfo.py b/PandaPkgInfo.py index 5dabf18..b6ebdbb 100644 --- a/PandaPkgInfo.py +++ b/PandaPkgInfo.py @@ -1 +1 @@ -release_version = "0.0.33" +release_version = "0.0.34" diff --git a/README.txt b/README.txt index c6b7c1b..56f015b 100644 --- a/README.txt +++ b/README.txt @@ -7,6 +7,9 @@ Includes all libraries used by both server and monitor (and others). Release Note ------------ +* 0.0.34 (24/4/2023) + * added LockPool + * 0.0.32 (17/11/2022) * heartbeat in stomp connection diff --git a/pandacommon/pandautils/thread_utils.py b/pandacommon/pandautils/thread_utils.py index b9b74e1..cc52ccb 100644 --- a/pandacommon/pandautils/thread_utils.py +++ b/pandacommon/pandautils/thread_utils.py @@ -109,3 +109,42 @@ def pop(self): self.weights.put(weights) self.data.put(data) return d + + +# lock pool +class LockPool(object): + + def __init__(self, pool_size=100): + self.pool_size = pool_size + self.lock = multiprocessing.Lock() + self.manager = multiprocessing.Manager() + self.key_to_lock = self.manager.dict() + self.lock_ref_count = self.manager.dict() + self.lock_pool = {i: multiprocessing.Lock() for i in range(pool_size)} + + def get(self, key): + with self.lock: + if key not in self.key_to_lock: + in_used = set(self.key_to_lock.values()) + free_locks = set(range(self.pool_size)).difference(in_used) + if not free_locks: + return None + index = free_locks.pop() + self.key_to_lock[key] = index + self.lock_ref_count[index] = 1 + else: + index = self.key_to_lock[key] + self.lock_ref_count[index] += 1 + return self.lock_pool[index] + + def release(self, key): + with self.lock: + if key not in self.key_to_lock: + return + index = self.key_to_lock[key] + count = self.lock_ref_count[index] + count -= 1 + if count <= 0: + count = 0 + del self.key_to_lock[key] + self.lock_ref_count[index] = count