Package ganeti :: Module cache
[hide private]
[frames] | no frames]

Source Code for Module ganeti.cache

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2011 Google Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 19  # 02110-1301, USA. 
 20   
 21   
 22  """This module implements caching.""" 
 23   
 24   
 25  import time 
 26   
 27  from ganeti import locking 
 28  from ganeti import serializer 
 29   
 30   
 31  TIMESTAMP = "timestamp" 
 32  TTL = "ttl" 
 33  VALUE = "value" 
34 35 36 -class CacheBase:
37 """This is the base class for all caches. 38 39 """
40 - def __init__(self):
41 """Base init method. 42 43 """
44
45 - def Store(self, key, value, ttl=0):
46 """Stores key with value in the cache. 47 48 @param key: The key to associate this cached value 49 @param value: The value to cache 50 @param ttl: TTL in seconds after when this entry is considered outdated 51 @returns: L{True} on success, L{False} on failure 52 53 """ 54 raise NotImplementedError
55
56 - def GetMulti(self, keys):
57 """Retrieve multiple values from the cache. 58 59 @param keys: The keys to retrieve 60 @returns: The list of values 61 62 """ 63 raise NotImplementedError
64
65 - def Get(self, key):
66 """Retrieve the value from the cache. 67 68 @param key: The key to retrieve 69 @returns: The value or L{None} if not found 70 71 """ 72 raise NotImplementedError
73
74 - def Invalidate(self, keys):
75 """Invalidate given keys. 76 77 @param keys: The list of keys to invalidate 78 @returns: L{True} on success, L{False} otherwise 79 80 """ 81 raise NotImplementedError
82
83 - def Flush(self):
84 """Invalidates all of the keys and flushes the cache. 85 86 """ 87 raise NotImplementedError
88
89 - def ResetState(self):
90 """Used to reset the state of the cache. 91 92 This can be used to reinstantiate connection or any other state refresh 93 94 """
95
96 - def Cleanup(self):
97 """Cleanup the cache from expired entries. 98 99 """
100
101 102 -class SimpleCache(CacheBase):
103 """Implements a very simple, dict base cache. 104 105 """ 106 CLEANUP_ROUND = 1800 107 _LOCK = "lock" 108
109 - def __init__(self, _time_fn=time.time):
110 """Initialize this class. 111 112 @param _time_fn: Function used to return time (unittest only) 113 114 """ 115 CacheBase.__init__(self) 116 117 self._time_fn = _time_fn 118 119 self.cache = {} 120 self.lock = locking.SharedLock("SimpleCache") 121 self.last_cleanup = self._time_fn()
122
123 - def _UnlockedCleanup(self):
124 """Does cleanup of the cache. 125 126 """ 127 check_time = self._time_fn() 128 if (self.last_cleanup + self.CLEANUP_ROUND) <= check_time: 129 keys = [] 130 for key, value in self.cache.items(): 131 if not value[TTL]: 132 continue 133 134 expired = value[TIMESTAMP] + value[TTL] 135 if expired < check_time: 136 keys.append(key) 137 self._UnlockedInvalidate(keys) 138 self.last_cleanup = check_time
139 140 @locking.ssynchronized(_LOCK)
141 - def Cleanup(self):
142 """Cleanup our cache. 143 144 """ 145 self._UnlockedCleanup()
146 147 @locking.ssynchronized(_LOCK)
148 - def Store(self, key, value, ttl=0):
149 """Stores a value at key in the cache. 150 151 See L{CacheBase.Store} for parameter description 152 153 """ 154 assert ttl >= 0 155 self._UnlockedCleanup() 156 val = serializer.Dump(value) 157 cache_val = { 158 TIMESTAMP: self._time_fn(), 159 TTL: ttl, 160 VALUE: val 161 } 162 self.cache[key] = cache_val 163 return True
164 165 @locking.ssynchronized(_LOCK, shared=1)
166 - def GetMulti(self, keys):
167 """Retrieve the values of keys from cache. 168 169 See L{CacheBase.GetMulti} for parameter description 170 171 """ 172 return [self._ExtractValue(key) for key in keys]
173 174 @locking.ssynchronized(_LOCK, shared=1)
175 - def Get(self, key):
176 """Retrieve the value of key from cache. 177 178 See L{CacheBase.Get} for parameter description 179 180 """ 181 return self._ExtractValue(key)
182 183 @locking.ssynchronized(_LOCK)
184 - def Invalidate(self, keys):
185 """Invalidates value for keys in cache. 186 187 See L{CacheBase.Invalidate} for parameter description 188 189 """ 190 return self._UnlockedInvalidate(keys)
191 192 @locking.ssynchronized(_LOCK)
193 - def Flush(self):
194 """Invalidates all keys and values in cache. 195 196 See L{CacheBase.Flush} for parameter description 197 198 """ 199 self.cache.clear() 200 self.last_cleanup = self._time_fn()
201
202 - def _UnlockedInvalidate(self, keys):
203 """Invalidate keys in cache. 204 205 This is the unlocked version, see L{Invalidate} for parameter description 206 207 """ 208 for key in keys: 209 self.cache.pop(key, None) 210 211 return True
212
213 - def _ExtractValue(self, key):
214 """Extracts just the value for a key. 215 216 This method is taking care if the value did not expire ans returns it 217 218 @param key: The key to look for 219 @returns: The value if key is not expired, L{None} otherwise 220 221 """ 222 try: 223 cache_val = self.cache[key] 224 except KeyError: 225 return None 226 else: 227 if cache_val[TTL] == 0: 228 return serializer.Load(cache_val[VALUE]) 229 else: 230 expired = cache_val[TIMESTAMP] + cache_val[TTL] 231 232 if self._time_fn() <= expired: 233 return serializer.Load(cache_val[VALUE]) 234 else: 235 return None
236