diff options
Diffstat (limited to 'dogpile/core/legacy.py')
-rw-r--r-- | dogpile/core/legacy.py | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/dogpile/core/legacy.py b/dogpile/core/legacy.py new file mode 100644 index 0000000..5f8dd22 --- /dev/null +++ b/dogpile/core/legacy.py @@ -0,0 +1,152 @@ +from .util import threading +from .readwrite_lock import ReadWriteMutex +from .dogpile import Lock +import time +import contextlib + +class Dogpile(object): + """Dogpile lock class. + + .. deprecated:: 0.4.0 + The :class:`.Lock` object specifies the full + API of the :class:`.Dogpile` object in a single way, + rather than providing multiple modes of usage which + don't necessarily work in the majority of cases. + :class:`.Dogpile` is now a wrapper around the :class:`.Lock` object + which provides dogpile.core's original usage pattern. + This usage pattern began as something simple, but was + not of general use in real-world caching environments without + several extra complicating factors; the :class:`.Lock` + object presents the "real-world" API more succinctly, + and also fixes a cross-process concurrency issue. + + :param expiretime: Expiration time in seconds. Set to + ``None`` for never expires. + :param init: if True, set the 'createdtime' to the + current time. + :param lock: a mutex object that provides + ``acquire()`` and ``release()`` methods. + + """ + def __init__(self, expiretime, init=False, lock=None): + """Construct a new :class:`.Dogpile`. + + """ + if lock: + self.dogpilelock = lock + else: + self.dogpilelock = threading.Lock() + + self.expiretime = expiretime + if init: + self.createdtime = time.time() + + createdtime = -1 + """The last known 'creation time' of the value, + stored as an epoch (i.e. from ``time.time()``). + + If the value here is -1, it is assumed the value + should recreate immediately. + + """ + + def acquire(self, creator, + value_fn=None, + value_and_created_fn=None): + """Acquire the lock, returning a context manager. + + :param creator: Creation function, used if this thread + is chosen to create a new value. + + :param value_fn: Optional function that returns + the value from some datasource. Will be returned + if regeneration is not needed. + + :param value_and_created_fn: Like value_fn, but returns a tuple + of (value, createdtime). The returned createdtime + will replace the "createdtime" value on this dogpile + lock. This option removes the need for the dogpile lock + itself to remain persistent across usages; another + dogpile can come along later and pick up where the + previous one left off. + + """ + + if value_and_created_fn is None: + if value_fn is None: + def value_and_created_fn(): + return None, self.createdtime + else: + def value_and_created_fn(): + return value_fn(), self.createdtime + + def creator_wrapper(): + value = creator() + self.createdtime = time.time() + return value, self.createdtime + else: + def creator_wrapper(): + value = creator() + self.createdtime = time.time() + return value + + return Lock( + self.dogpilelock, + creator_wrapper, + value_and_created_fn, + self.expiretime + ) + + @property + def is_expired(self): + """Return true if the expiration time is reached, or no + value is available.""" + + return not self.has_value or \ + ( + self.expiretime is not None and + time.time() - self.createdtime > self.expiretime + ) + + @property + def has_value(self): + """Return true if the creation function has proceeded + at least once.""" + return self.createdtime > 0 + + +class SyncReaderDogpile(Dogpile): + """Provide a read-write lock function on top of the :class:`.Dogpile` + class. + + .. deprecated:: 0.4.0 + The :class:`.ReadWriteMutex` object can be used directly. + + """ + def __init__(self, *args, **kw): + super(SyncReaderDogpile, self).__init__(*args, **kw) + self.readwritelock = ReadWriteMutex() + + @contextlib.contextmanager + def acquire_write_lock(self): + """Return the "write" lock context manager. + + This will provide a section that is mutexed against + all readers/writers for the dogpile-maintained value. + + """ + + self.readwritelock.acquire_write_lock() + try: + yield + finally: + self.readwritelock.release_write_lock() + + @contextlib.contextmanager + def acquire(self, *arg, **kw): + with super(SyncReaderDogpile, self).acquire(*arg, **kw): + self.readwritelock.acquire_read_lock() + try: + yield + finally: + self.readwritelock.release_read_lock() |