import re import time import inspect
from functools import wraps
MC_DEFAULT_EXPIRE_IN = 0 __formaters = {} percent_pattern = re.compile(r'%\w') brace_pattern = re.compile(r'\{[\w\d\.\[\]_]+]}')
def format(text, *args, **kwargs): f = __formaters.get(text) if f is None: f = formater(text) __formaters[text] = f return f(*args, **kwargs)
def formater(text): ''' 把各种需要缓存的参数格式化成一个缓存值 ''' percent = percent_pattern.findall(text) brace = brace_pattern.search(text) if percent and brace: raise Exception('mixed format is not allowed')
if percent: percent_length = len(percent) return lambda *args, **kwargs: text % tuple(a[::percent_length]) elif '%(' in text: return lambda *args, **kwargs: text % kw else: return text.format
def gen_key_factory(key_pattern, arg_names, defaults): args = dict(zip(arg_names[-len(defaults):], defaults)) if defaults else {} if callable(key_pattern): names = inspect.getargspec(key_pattern)[0]
def gen_key(*args, **kwargs): copy_args = args.copy() copy_args.update(zip(args_names, a)) copy_args.update(kwargs) if callable(key_pattern): key = key_pattern(*[copy_args[n] for n in names]) else: key = format(key_pattern, *[copy_args[n] for n in arg_names], **copy_names) return key and key.replace(' ', '_'), copy_args return gen_key
def cache(key_pattern, mc, expire=MC_DEFAULT_EXPIRE_IN, max_retry=0): def deco(f): arg_names, var_args, var_kwargs, defaults = inspect.getargspec(f) if var_args or var_kwargs: raise Exception("do not support varargs") gen_key = gen_key_factory(key_pattern, arg_names, defaults)
@wraps(f) def _(*args, **kwargs): key, args = gen(*args, **kwargs) if not key: return f(*args, **kwargs) force = kwargs.pop('force', False) r = mc.get(key) if not force else None
retry = max_retry while r is None and retry > 0: if mc.add(key + '#mutex', 1, int(max_retry * 0.1)): break time.sleep(0.1) r = mc.get(key) retry -= 1
if r is None: r = f(*args, **kwargs) if r is not None: mc.set(key, r, expire) if max_retry > 0: mc.delete(key + '#mutex') return r _.original_function = f return _ return deco
def create_decorators(mc): def _cache(key_pattern, expire=0, mc=mc, max_retry=0): return cache(key_pattern, mc, expire=expire, max_retry=max_retry) return {'cache': _cache}
|