Source code for pyams_utils.lock

#
# 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.
#

"""PyAMS_utils.lock module

This module is use to manage shared locks; these locks can be used accross several
processes; the lock relies on a shared value stored info Beaker's cache.
"""

import time
from threading import local

from beaker import cache


__docformat__ = 'restructuredtext'


_LOCAL = local()


[docs]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
[docs]class LockException(Exception): """Cache lock exception"""
[docs]class CacheLock: """Beaker based lock This lock can be used when you need to get a lot across several processes or even computers. The lock relies on a shared value stored into a shared Beaker cache. :param str name: name of the lock to use as shared key :param boolean wait: if *False*, a *LockException* is raised if lock can't be taken; otherwise, application waits until lock is released Lock can be used as a context manager. """ 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() 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
[docs]def locked(name, wait=True): """Locked function decorator Can be used with any function or method which requires a global shared lock. :param str name: name of the lock to use as shared key :param boolean wait: if *False*, a *LockException* is raised if lock can't be taken; otherwise, application waits until lock is released """ def lock_decorator(func): def wrapper(*args, **kwargs): with CacheLock(name, wait): return func(*args, **kwargs) return wrapper return lock_decorator