def __init__(self): self._global = [] self._thread_context_lock = ThreadLock() self._thread_context = thread_local() self._greenlet_context_lock = GreenletRLock() self._greenlet_context = greenlet_local() self._cache = {} self._stackop = get_iterator_next_method(count())
class ContextStackManager(object): """Helper class for context objects that manages a stack of objects. """ def __init__(self): self._global = [] self._thread_context_lock = ThreadLock() self._thread_context = thread_local() self._greenlet_context_lock = GreenletRLock() self._greenlet_context = greenlet_local() self._cache = {} self._stackop = get_iterator_next_method(count()) def iter_context_objects(self): """Returns an iterator over all objects for the combined application and context cache. """ use_gevent = is_gevent_enabled() tid = greenlet_get_ident() if use_gevent else thread_get_ident() objects = self._cache.get(tid) if objects is None: if len(self._cache) > _MAX_CONTEXT_OBJECT_CACHE: self._cache.clear() objects = self._global[:] objects.extend(getattr(self._thread_context, 'stack', ())) if use_gevent: objects.extend(getattr(self._greenlet_context, 'stack', ())) objects.sort(reverse=True) objects = [x[1] for x in objects] self._cache[tid] = objects return iter(objects) def push_greenlet(self, obj): self._greenlet_context_lock.acquire() try: self._cache.pop(greenlet_get_ident(), None) # remote chance to conflict with thread ids item = (self._stackop(), obj) stack = getattr(self._greenlet_context, 'stack', None) if stack is None: self._greenlet_context.stack = [item] else: stack.append(item) finally: self._greenlet_context_lock.release() def pop_greenlet(self): self._greenlet_context_lock.acquire() try: self._cache.pop(greenlet_get_ident(), None) # remote chance to conflict with thread ids stack = getattr(self._greenlet_context, 'stack', None) assert stack, 'no objects on stack' return stack.pop()[1] finally: self._greenlet_context_lock.release() def push_thread(self, obj): self._thread_context_lock.acquire() try: self._cache.pop(thread_get_ident(), None) item = (self._stackop(), obj) stack = getattr(self._thread_context, 'stack', None) if stack is None: self._thread_context.stack = [item] else: stack.append(item) finally: self._thread_context_lock.release() def pop_thread(self): self._thread_context_lock.acquire() try: self._cache.pop(thread_get_ident(), None) stack = getattr(self._thread_context, 'stack', None) assert stack, 'no objects on stack' return stack.pop()[1] finally: self._thread_context_lock.release() def push_application(self, obj): self._global.append((self._stackop(), obj)) self._cache.clear() def pop_application(self): assert self._global, 'no objects on application stack' popped = self._global.pop()[1] self._cache.clear() return popped