home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / digsby_setup.exe / lib / pyxmpp / cache.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-06-22  |  10.8 KB  |  440 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. __revision__ = '$Id: cache.py 714 2010-04-05 10:20:10Z jajcus $'
  5. __docformat__ = 'restructuredtext en'
  6. import threading
  7. from datetime import datetime, timedelta
  8. _state_values = {
  9.     'new': 0,
  10.     'fresh': 1,
  11.     'old': 2,
  12.     'stale': 3,
  13.     'purged': 4 }
  14.  
  15. class CacheItem(object):
  16.     __slots__ = [
  17.         'value',
  18.         'address',
  19.         'state',
  20.         'timestamp',
  21.         'freshness_time',
  22.         'expire_time',
  23.         'purge_time',
  24.         'state_value',
  25.         '_lock']
  26.     
  27.     def __init__(self, address, value, freshness_period, expiration_period, purge_period, state = 'new'):
  28.         if freshness_period > expiration_period:
  29.             raise ValueError, 'freshness_period greater then expiration_period'
  30.         freshness_period > expiration_period
  31.         if expiration_period > purge_period:
  32.             raise ValueError, 'expiration_period greater then purge_period'
  33.         expiration_period > purge_period
  34.         self.address = address
  35.         self.value = value
  36.         now = datetime.utcnow()
  37.         self.timestamp = now
  38.         self.freshness_time = now + freshness_period
  39.         self.expire_time = now + expiration_period
  40.         if purge_period:
  41.             self.purge_time = now + purge_period
  42.         else:
  43.             self.purge_time = datetime.max
  44.         self.state = state
  45.         self.state_value = _state_values[state]
  46.         self._lock = threading.RLock()
  47.  
  48.     
  49.     def update_state(self):
  50.         self._lock.acquire()
  51.         
  52.         try:
  53.             now = datetime.utcnow()
  54.             if self.state == 'new':
  55.                 self.state = 'fresh'
  56.             
  57.             if self.state == 'fresh':
  58.                 if now > self.freshness_time:
  59.                     self.state = 'old'
  60.                 
  61.             
  62.             if self.state == 'old':
  63.                 if now > self.expire_time:
  64.                     self.state = 'stale'
  65.                 
  66.             
  67.             if self.state == 'stale':
  68.                 if now > self.purge_time:
  69.                     self.state = 'purged'
  70.                 
  71.             
  72.             self.state_value = _state_values[self.state]
  73.             return self.state
  74.         finally:
  75.             self._lock.release()
  76.  
  77.  
  78.     
  79.     def __cmp__(self, other):
  80.         
  81.         try:
  82.             return cmp((-(self.state_value), self.timestamp, id(self)), (-(other.state_value), other.timestamp, id(other)))
  83.         except AttributeError:
  84.             return cmp(id(self), id(other))
  85.  
  86.  
  87.  
  88. _hour = timedelta(hours = 1)
  89.  
  90. class CacheFetcher:
  91.     
  92.     def __init__(self, cache, address, item_freshness_period, item_expiration_period, item_purge_period, object_handler, error_handler, timeout_handler, timeout_period, backup_state = None):
  93.         self.cache = cache
  94.         self.address = address
  95.         self._item_freshness_period = item_freshness_period
  96.         self._item_expiration_period = item_expiration_period
  97.         self._item_purge_period = item_purge_period
  98.         self._object_handler = object_handler
  99.         self._error_handler = error_handler
  100.         self._timeout_handler = timeout_handler
  101.         if timeout_period:
  102.             self.timeout_time = datetime.utcnow() + timeout_period
  103.         else:
  104.             self.timeout_time = datetime.max
  105.         self._backup_state = backup_state
  106.         self.active = True
  107.  
  108.     
  109.     def _deactivate(self):
  110.         self.cache.remove_fetcher(self)
  111.         if self.active:
  112.             self._deactivated()
  113.         
  114.  
  115.     
  116.     def _deactivated(self):
  117.         self.active = False
  118.  
  119.     
  120.     def fetch(self):
  121.         raise RuntimeError, 'Pure virtual method called'
  122.  
  123.     
  124.     def got_it(self, value, state = 'new'):
  125.         if not self.active:
  126.             return None
  127.         item = CacheItem(self.address, value, self._item_freshness_period, self._item_expiration_period, self._item_purge_period, state)
  128.         self._object_handler(item.address, item.value, item.state)
  129.         self.cache.add_item(item)
  130.         self._deactivate()
  131.  
  132.     
  133.     def error(self, error_data):
  134.         if not self.active:
  135.             return None
  136.         if not self._try_backup_item():
  137.             self._error_handler(self.address, error_data)
  138.         
  139.         self.cache.invalidate_object(self.address)
  140.         self._deactivate()
  141.  
  142.     
  143.     def timeout(self):
  144.         if not self.active:
  145.             return None
  146.         if not self._try_backup_item():
  147.             if self._timeout_handler:
  148.                 self._timeout_handler(self.address)
  149.             else:
  150.                 self._error_handler(self.address, None)
  151.         
  152.         self.cache.invalidate_object(self.address)
  153.         self._deactivate()
  154.  
  155.     
  156.     def _try_backup_item(self):
  157.         if not self._backup_state:
  158.             return False
  159.         item = self.cache.get_item(self.address, self._backup_state)
  160.         if item:
  161.             self._object_handler(item.address, item.value, item.state)
  162.             return True
  163.         False
  164.  
  165.  
  166.  
  167. class Cache:
  168.     
  169.     def __init__(self, max_items, default_freshness_period = _hour, default_expiration_period = 12 * _hour, default_purge_period = 24 * _hour):
  170.         self.default_freshness_period = default_freshness_period
  171.         self.default_expiration_period = default_expiration_period
  172.         self.default_purge_period = default_purge_period
  173.         self.max_items = max_items
  174.         self._items = { }
  175.         self._items_list = []
  176.         self._fetcher = None
  177.         self._active_fetchers = []
  178.         self._purged = 0
  179.         self._lock = threading.RLock()
  180.  
  181.     
  182.     def request_object(self, address, state, object_handler, error_handler = None, timeout_handler = None, backup_state = None, timeout = timedelta(minutes = 60), freshness_period = None, expiration_period = None, purge_period = None):
  183.         self._lock.acquire()
  184.         
  185.         try:
  186.             if state == 'stale':
  187.                 state = 'purged'
  188.             
  189.             item = self.get_item(address, state)
  190.             if item:
  191.                 object_handler(item.address, item.value, item.state)
  192.                 return None
  193.             if not self._fetcher:
  194.                 raise TypeError, 'No cache fetcher defined'
  195.             self._fetcher
  196.             if not error_handler:
  197.                 
  198.                 def default_error_handler(address, _unused):
  199.                     return object_handler(address, None, 'error')
  200.  
  201.                 error_handler = default_error_handler
  202.             
  203.             if not timeout_handler:
  204.                 
  205.                 def default_timeout_handler(address):
  206.                     return error_handler(address, None)
  207.  
  208.                 timeout_handler = default_timeout_handler
  209.             
  210.             if freshness_period is None:
  211.                 freshness_period = self.default_freshness_period
  212.             
  213.             if expiration_period is None:
  214.                 expiration_period = self.default_expiration_period
  215.             
  216.             if purge_period is None:
  217.                 purge_period = self.default_purge_period
  218.             
  219.             fetcher = self._fetcher(self, address, freshness_period, expiration_period, purge_period, object_handler, error_handler, timeout_handler, timeout, backup_state)
  220.             fetcher.fetch()
  221.             self._active_fetchers.append((fetcher.timeout_time, fetcher))
  222.             self._active_fetchers.sort()
  223.         finally:
  224.             self._lock.release()
  225.  
  226.  
  227.     
  228.     def invalidate_object(self, address, state = 'stale'):
  229.         self._lock.acquire()
  230.         
  231.         try:
  232.             item = self.get_item(address)
  233.             if item and item.state_value < _state_values[state]:
  234.                 item.state = state
  235.                 item.update_state()
  236.                 self._items_list.sort()
  237.         finally:
  238.             self._lock.release()
  239.  
  240.  
  241.     
  242.     def add_item(self, item):
  243.         self._lock.acquire()
  244.         
  245.         try:
  246.             state = item.update_state()
  247.             if state != 'purged':
  248.                 if len(self._items_list) >= self.max_items:
  249.                     self.purge_items()
  250.                 
  251.                 self._items[item.address] = item
  252.                 self._items_list.append(item)
  253.                 self._items_list.sort()
  254.             
  255.             return item.state
  256.         finally:
  257.             self._lock.release()
  258.  
  259.  
  260.     
  261.     def get_item(self, address, state = 'fresh'):
  262.         self._lock.acquire()
  263.         
  264.         try:
  265.             item = self._items.get(address)
  266.             if not item:
  267.                 return None
  268.             self.update_item(item)
  269.             if _state_values[state] >= item.state_value:
  270.                 return item
  271.             return None
  272.         finally:
  273.             self._lock.release()
  274.  
  275.  
  276.     
  277.     def update_item(self, item):
  278.         self._lock.acquire()
  279.         
  280.         try:
  281.             state = item.update_state()
  282.             self._items_list.sort()
  283.             if item.state == 'purged':
  284.                 self._purged += 1
  285.                 if self._purged > 0.25 * self.max_items:
  286.                     self.purge_items()
  287.                 
  288.             
  289.             return state
  290.         finally:
  291.             self._lock.release()
  292.  
  293.  
  294.     
  295.     def num_items(self):
  296.         return len(self._items_list)
  297.  
  298.     
  299.     def purge_items(self):
  300.         self._lock.acquire()
  301.         
  302.         try:
  303.             il = self._items_list
  304.             num_items = len(il)
  305.             need_remove = num_items - int(0.75 * self.max_items)
  306.             for _unused in range(need_remove):
  307.                 item = il.pop(0)
  308.                 
  309.                 try:
  310.                     del self._items[item.address]
  311.                 continue
  312.                 except KeyError:
  313.                     continue
  314.                 
  315.  
  316.             
  317.             while il and il[0].update_state() == 'purged':
  318.                 item = il.pop(0)
  319.                 
  320.                 try:
  321.                     del self._items[item.address]
  322.                 continue
  323.                 except KeyError:
  324.                     None<EXCEPTION MATCH>KeyError
  325.                     None<EXCEPTION MATCH>KeyError
  326.                     continue
  327.                 
  328.  
  329.                 None<EXCEPTION MATCH>KeyError<EXCEPTION MATCH>KeyError
  330.         finally:
  331.             self._lock.release()
  332.  
  333.  
  334.     
  335.     def tick(self):
  336.         self._lock.acquire()
  337.         
  338.         try:
  339.             now = datetime.utcnow()
  340.             for t, f in list(self._active_fetchers):
  341.                 if t > now:
  342.                     break
  343.                 
  344.                 f.timeout()
  345.             
  346.             self.purge_items()
  347.         finally:
  348.             self._lock.release()
  349.  
  350.  
  351.     
  352.     def remove_fetcher(self, fetcher):
  353.         self._lock.acquire()
  354.         
  355.         try:
  356.             for t, f in list(self._active_fetchers):
  357.                 if f is fetcher:
  358.                     self._active_fetchers.remove((t, f))
  359.                     f._deactivated()
  360.                     return None
  361.         finally:
  362.             self._lock.release()
  363.  
  364.  
  365.     
  366.     def set_fetcher(self, fetcher_class):
  367.         self._lock.acquire()
  368.         
  369.         try:
  370.             self._fetcher = fetcher_class
  371.         finally:
  372.             self._lock.release()
  373.  
  374.  
  375.  
  376.  
  377. class CacheSuite:
  378.     
  379.     def __init__(self, max_items, default_freshness_period = _hour, default_expiration_period = 12 * _hour, default_purge_period = 24 * _hour):
  380.         self.default_freshness_period = default_freshness_period
  381.         self.default_expiration_period = default_expiration_period
  382.         self.default_purge_period = default_purge_period
  383.         self.max_items = max_items
  384.         self._caches = { }
  385.         self._lock = threading.RLock()
  386.  
  387.     
  388.     def request_object(self, object_class, address, state, object_handler, error_handler = None, timeout_handler = None, backup_state = None, timeout = None, freshness_period = None, expiration_period = None, purge_period = None):
  389.         self._lock.acquire()
  390.         
  391.         try:
  392.             if object_class not in self._caches:
  393.                 raise TypeError, 'No cache for %r' % (object_class,)
  394.             object_class not in self._caches
  395.             self._caches[object_class].request_object(address, state, object_handler, error_handler, timeout_handler, backup_state, timeout, freshness_period, expiration_period, purge_period)
  396.         finally:
  397.             self._lock.release()
  398.  
  399.  
  400.     
  401.     def tick(self):
  402.         self._lock.acquire()
  403.         
  404.         try:
  405.             for cache in self._caches.values():
  406.                 cache.tick()
  407.         finally:
  408.             self._lock.release()
  409.  
  410.  
  411.     
  412.     def register_fetcher(self, object_class, fetcher_class):
  413.         self._lock.acquire()
  414.         
  415.         try:
  416.             cache = self._caches.get(object_class)
  417.             if not cache:
  418.                 cache = Cache(self.max_items, self.default_freshness_period, self.default_expiration_period, self.default_purge_period)
  419.                 self._caches[object_class] = cache
  420.             
  421.             cache.set_fetcher(fetcher_class)
  422.         finally:
  423.             self._lock.release()
  424.  
  425.  
  426.     
  427.     def unregister_fetcher(self, object_class):
  428.         self._lock.acquire()
  429.         
  430.         try:
  431.             cache = self._caches.get(object_class)
  432.             if not cache:
  433.                 return None
  434.             cache.set_fetcher(None)
  435.         finally:
  436.             self._lock.release()
  437.  
  438.  
  439.  
  440.