Package logilab :: Package common :: Module cache

[frames] | no frames]

# Source Code for Module logilab.common.cache

      1  # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
      2  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
      3  #
      4  # This file is part of logilab-common.
      5  #
      6  # logilab-common is free software: you can redistribute it and/or modify it under
      7  # the terms of the GNU Lesser General Public License as published by the Free
      8  # Software Foundation, either version 2.1 of the License, or (at your option) any
      9  # later version.
     10  #
     11  # logilab-common is distributed in the hope that it will be useful, but WITHOUT
     12  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     13  # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
     14  # details.
     15  #
     16  # You should have received a copy of the GNU Lesser General Public License along
     17  # with logilab-common.  If not, see <http://www.gnu.org/licenses/>.
     18  """Cache module, with a least recently used algorithm for the management of the
     19  deletion of entries.
     20
     21
     22
     23
     24  """
     25  __docformat__ = "restructuredtext en"
     26
     27  from threading import Lock
     28
     29  from logilab.common.decorators import locked
     30
     31  _marker = object()
     32
     33 -class Cache(dict):
     34      """A dictionary like cache.
     35
     36      inv:
     37          len(self._usage) <= self.size
     38          len(self.data) <= self.size
     39      """
     40
     41 -    def __init__(self, size=100):
     42          """ Warning : Cache.__init__() != dict.__init__().
     43          Constructor does not take any arguments beside size.
     44          """
     45          assert size >= 0, 'cache size must be >= 0 (0 meaning no caching)'
     46          self.size = size
     47          self._usage = []
     48          self._lock = Lock()
     49          super(Cache, self).__init__()
     50
     51 -    def _acquire(self):
     52          self._lock.acquire()
     53
     54 -    def _release(self):
     55          self._lock.release()
     56
     57 -    def _update_usage(self, key):
     58          if not self._usage:
     59              self._usage.append(key)
     60          elif self._usage[-1] != key:
     61              try:
     62                  self._usage.remove(key)
     63              except ValueError:
     64                  # we are inserting a new key
     65                  # check the size of the dictionary
     66                  # and remove the oldest item in the cache
     67                  if self.size and len(self._usage) >= self.size:
     68                      super(Cache, self).__delitem__(self._usage[0])
     69                      del self._usage[0]
     70              self._usage.append(key)
     71          else:
     72              pass # key is already the most recently used key
     73
     74 -    def __getitem__(self, key):
     75          value = super(Cache, self).__getitem__(key)
     76          self._update_usage(key)
     77          return value
     78      __getitem__ = locked(_acquire, _release)(__getitem__)
     79
     80 -    def __setitem__(self, key, item):
     81          # Just make sure that size > 0 before inserting a new item in the cache
     82          if self.size > 0:
     83              super(Cache, self).__setitem__(key, item)
     84              self._update_usage(key)
     85      __setitem__ = locked(_acquire, _release)(__setitem__)
     86
     87 -    def __delitem__(self, key):
     88          super(Cache, self).__delitem__(key)
     89          self._usage.remove(key)
     90      __delitem__ = locked(_acquire, _release)(__delitem__)
     91
     92 -    def clear(self):
     93          super(Cache, self).clear()
     94          self._usage = []
     95      clear = locked(_acquire, _release)(clear)
     96
     97 -    def pop(self, key, default=_marker):
     98          if key in self:
     99              self._usage.remove(key)
    100          #if default is _marker:
    101          #    return super(Cache, self).pop(key)
    102          return super(Cache, self).pop(key, default)
    103      pop = locked(_acquire, _release)(pop)
    104
    105 -    def popitem(self):
    106          raise NotImplementedError()
    107
    108 -    def setdefault(self, key, default=None):
    109          raise NotImplementedError()
    110
    111 -    def update(self, other):
    112          raise NotImplementedError()
    113