# HG changeset patch # User Thierry Florac # Date 1464878319 -7200 # Node ID 52a07a902854f612befcd2c2817bf4261ce11c13 # Parent 6a579f05c6922cb0c76cb455f4d37bad9e4f06c7 Added Beaker lock manager diff -r 6a579f05c692 -r 52a07a902854 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 +# 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