--- /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