Make Provider overriding methods thread safe

This commit is contained in:
Roman Mogilatov 2017-04-18 23:30:29 +03:00
parent 9ed806b0ca
commit 2a9b14cb0e
5 changed files with 3341 additions and 2710 deletions

View File

@ -10,6 +10,9 @@ follows `Semantic versioning`_
Development version Development version
------------------- -------------------
.. - No features. .. - No features.
- Make ``Provider`` overriding methods thread safe:
``Provider.override(provider)``, ``Provider.reset_last_overriding()``,
``Provider.reset_override()``.
- Refactor storage locking of ``ThreadSafeSingleton`` provider. - Refactor storage locking of ``ThreadSafeSingleton`` provider.
3.4.1 3.4.1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@ cimport cython
cdef class Provider(object): cdef class Provider(object):
cdef tuple __overridden cdef tuple __overridden
cdef Provider __last_overriding cdef Provider __last_overriding
cdef object __overriding_lock
cpdef object _provide(self, tuple args, dict kwargs) cpdef object _provide(self, tuple args, dict kwargs)

View File

@ -74,10 +74,17 @@ cdef class Provider(object):
__IS_PROVIDER__ = True __IS_PROVIDER__ = True
overriding_lock = threading.RLock()
"""Storage reentrant lock.
:type: :py:class:`threading.RLock`
"""
def __init__(self): def __init__(self):
"""Initializer.""" """Initializer."""
self.__overridden = tuple() self.__overridden = tuple()
self.__last_overriding = None self.__last_overriding = None
self.__overriding_lock = self.__class__.overriding_lock
super(Provider, self).__init__() super(Provider, self).__init__()
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
@ -119,7 +126,8 @@ cdef class Provider(object):
@property @property
def overridden(self): def overridden(self):
"""Return tuple of overriding providers.""" """Return tuple of overriding providers."""
return self.__overridden with self.__overriding_lock:
return self.__overridden
def override(self, provider): def override(self, provider):
"""Override provider with another provider. """Override provider with another provider.
@ -139,8 +147,9 @@ cdef class Provider(object):
if not is_provider(provider): if not is_provider(provider):
provider = Object(provider) provider = Object(provider)
self.__overridden += (provider,) with self.__overriding_lock:
self.__last_overriding = provider self.__overridden += (provider,)
self.__last_overriding = provider
return OverridingContext(self, provider) return OverridingContext(self, provider)
@ -152,22 +161,24 @@ cdef class Provider(object):
:rtype: None :rtype: None
""" """
if len(self.__overridden) == 0: with self.__overriding_lock:
raise Error('Provider {0} is not overridden'.format(str(self))) if len(self.__overridden) == 0:
raise Error('Provider {0} is not overridden'.format(str(self)))
self.__overridden = self.__overridden[:-1] self.__overridden = self.__overridden[:-1]
try: try:
self.__last_overriding = self.__overridden[-1] self.__last_overriding = self.__overridden[-1]
except IndexError: except IndexError:
self.__last_overriding = None self.__last_overriding = None
def reset_override(self): def reset_override(self):
"""Reset all overriding providers. """Reset all overriding providers.
:rtype: None :rtype: None
""" """
self.__overridden = tuple() with self.__overriding_lock:
self.__last_overriding = None self.__overridden = tuple()
self.__last_overriding = None
def delegate(self): def delegate(self):
"""Return provider's delegate. """Return provider's delegate.