Python module (submodule repositary), which provides content (video streams) from various online stream sources to corresponding Enigma2, Kodi, Plex plugins

stampede.py 2.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. "Stampede barrier implementation."
  2. import functools as ft
  3. import math
  4. import random
  5. import tempfile
  6. import time
  7. from .core import Cache, ENOVAL
  8. class StampedeBarrier(object):
  9. """Stampede barrier mitigates cache stampedes.
  10. Cache stampedes are also known as dog-piling, cache miss storm, cache
  11. choking, or the thundering herd problem.
  12. Based on research by Vattani, A.; Chierichetti, F.; Lowenstein, K. (2015),
  13. Optimal Probabilistic Cache Stampede Prevention,
  14. VLDB, pp. 886?897, ISSN 2150-8097
  15. Example:
  16. ```python
  17. stampede_barrier = StampedeBarrier('/tmp/user_data', expire=3)
  18. @stampede_barrier
  19. def load_user_info(user_id):
  20. return database.lookup_user_info_by_id(user_id)
  21. ```
  22. """
  23. # pylint: disable=too-few-public-methods
  24. def __init__(self, cache=None, expire=None):
  25. if isinstance(cache, Cache):
  26. pass
  27. elif cache is None:
  28. cache = Cache(tempfile.mkdtemp())
  29. else:
  30. cache = Cache(cache)
  31. self._cache = cache
  32. self._expire = expire
  33. def __call__(self, func):
  34. cache = self._cache
  35. expire = self._expire
  36. @ft.wraps(func)
  37. def wrapper(*args, **kwargs):
  38. "Wrapper function to cache function result."
  39. key = (args, kwargs)
  40. try:
  41. result, expire_time, delta = cache.get(
  42. key, default=ENOVAL, expire_time=True, tag=True
  43. )
  44. if result is ENOVAL:
  45. raise KeyError
  46. now = time.time()
  47. ttl = expire_time - now
  48. if (-delta * math.log(random.random())) < ttl:
  49. return result
  50. except KeyError:
  51. pass
  52. now = time.time()
  53. result = func(*args, **kwargs)
  54. delta = time.time() - now
  55. cache.set(key, result, expire=expire, tag=delta)
  56. return result
  57. return wrapper