Added Beaker lock manager
authorThierry Florac <thierry.florac@onf.fr>
Thu, 02 Jun 2016 16:38:39 +0200
changeset 62 52a07a902854
parent 61 6a579f05c692
child 63 f188db1a1ce7
Added Beaker lock manager
src/pyams_utils/lock.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_utils/lock.py	Thu Jun 02 16:38:39 2016 +0200
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+import time
+from threading import local
+
+# import interfaces
+
+# import packages
+from beaker import cache
+
+
+_local = local()
+
+
+def get_locks_cache():
+    """Get locks shared cache"""
+    try:
+        locks_cache = _local.locks_cache
+    except AttributeError:
+        manager = cache.CacheManager(**cache.cache_regions['persistent'])
+        locks_cache = _local.locks_cache = manager.get_cache('PyAMS::locks')
+    return locks_cache
+
+
+class LockException(Exception):
+    """Cache lock exception"""
+
+
+class CacheLock(object):
+    """Beaker based lock"""
+
+    def __init__(self, name, wait=True):
+        self.key = 'PyAMS_lock::{0}'.format(name)
+        self.wait = wait
+        self.has_lock = False
+
+    def __enter__(self):
+        locks_cache = get_locks_cache()
+        while True:
+            test = locks_cache.has_key(self.key)
+            if test:
+                if not self.wait:
+                    raise LockException()
+                else:
+                    time.sleep(0.1)
+            else:
+                locks_cache.set_value(self.key, 1)
+                self.has_lock = True
+                return
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        if self.has_lock:
+            get_locks_cache().remove_value(self.key)
+        return False
+
+
+def locked(name, wait=True):
+    """Locked function decorator"""
+
+    def lock_decorator(func):
+        def wrapper(*args, **kwargs):
+            with CacheLock(name, wait):
+                return func(*args, **kwargs)
+        return wrapper
+
+    return lock_decorator