1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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"
37 """This is the base class for all caches.
38
39 """
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
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
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
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
84 """Invalidates all of the keys and flushes the cache.
85
86 """
87 raise NotImplementedError
88
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
97 """Cleanup the cache from expired entries.
98
99 """
100
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
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)
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)
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)
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)
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
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
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