6 """ |
6 """ |
7 Module implementing classes used for caching objects. |
7 Module implementing classes used for caching objects. |
8 """ |
8 """ |
9 |
9 |
10 from __future__ import unicode_literals |
10 from __future__ import unicode_literals |
|
11 |
|
12 from PyQt5.QtCore import QDateTime, QTimer |
11 |
13 |
12 |
14 |
13 # TODO: add timeout for cached entries |
15 # TODO: add timeout for cached entries |
14 class E5Cache(object): |
16 class E5Cache(object): |
15 """ |
17 """ |
30 |
32 |
31 self.__size = size |
33 self.__size = size |
32 |
34 |
33 # internal objects |
35 # internal objects |
34 self.__keyList = [] |
36 self.__keyList = [] |
35 self.__store = {} |
37 self.__store = {} # stores the cache entries |
|
38 self.__accesStore = {} # stores the last access date and times |
36 self.__hits = 0 |
39 self.__hits = 0 |
37 self.__misses = 0 |
40 self.__misses = 0 |
38 self.__maxsize = 0 |
41 self.__maxsize = 0 |
|
42 self.__maxCacheTime = 0 # 0 seconds means aging is disabled |
|
43 |
|
44 self.__cacheTimer = QTimer() |
|
45 self.__cacheTimer.setSingleShot(True) |
|
46 self.__cacheTimer.timeout.connect(self.__pruneCache) |
39 |
47 |
40 def __moveLast(self, key): |
48 def __moveLast(self, key): |
41 """ |
49 """ |
42 Private method to move a cached item to the MRU position. |
50 Private method to move a cached item to the MRU position. |
43 |
51 |
53 """ |
61 """ |
54 removeList, self.__keyList = \ |
62 removeList, self.__keyList = \ |
55 self.__keyList[:-self.__size], self.__keyList[-self.__size:] |
63 self.__keyList[:-self.__size], self.__keyList[-self.__size:] |
56 for key in removeList: |
64 for key in removeList: |
57 del self.__store[key] |
65 del self.__store[key] |
|
66 del self.__accesStore[key] |
58 |
67 |
59 def getSize(self): |
68 def getSize(self): |
60 """ |
69 """ |
61 Public method to get the maximum size of the cache. |
70 Public method to get the maximum size of the cache. |
62 |
71 |
76 assert newSize >= 0 |
85 assert newSize >= 0 |
77 |
86 |
78 self.__size = newSize |
87 self.__size = newSize |
79 self.__adjustToSize() |
88 self.__adjustToSize() |
80 |
89 |
|
90 def getMaximumCacheTime(self): |
|
91 """ |
|
92 Public method to get the maximum time entries may exist in the cache. |
|
93 |
|
94 @return maximum cache time in seconds |
|
95 @rtype int |
|
96 """ |
|
97 return self.__maxCacheTime |
|
98 |
|
99 def setMaximumCacheTime(self, time): |
|
100 """ |
|
101 Public method to set the maximum time entries may exist in the cache. |
|
102 |
|
103 @param time maximum cache time in seconds |
|
104 @type int |
|
105 """ |
|
106 if time != self.__maxCacheTime: |
|
107 self.__cacheTimer.stop() |
|
108 self.__pruneCache() |
|
109 self.__maxCacheTime = time |
|
110 if self.__maxCacheTime > 0: |
|
111 self.__cacheTimer.setInterval(self.__maxCacheTime * 1000) |
|
112 self.__cacheTimer.start() |
|
113 |
81 def get(self, key): |
114 def get(self, key): |
82 """ |
115 """ |
83 Public method to get an entry from the cache given its key. |
116 Public method to get an entry from the cache given its key. |
84 |
117 |
85 If the key is present in the cache, it is moved to the MRU position. |
118 If the key is present in the cache, it is moved to the MRU position. |
113 if key in self.__store: |
147 if key in self.__store: |
114 self.__moveLast(key) |
148 self.__moveLast(key) |
115 else: |
149 else: |
116 self.__keyList.append(key) |
150 self.__keyList.append(key) |
117 self.__store[key] = item |
151 self.__store[key] = item |
|
152 self.__accesStore[key] = QDateTime.currentDateTimeUtc() |
118 |
153 |
119 self.__adjustToSize() |
154 self.__adjustToSize() |
120 |
155 |
121 self.__maxsize = max(self.__maxsize, len(self.__keyList)) |
156 self.__maxsize = max(self.__maxsize, len(self.__keyList)) |
122 |
157 |
127 @param key key of the item to be retrieved |
162 @param key key of the item to be retrieved |
128 @type any hashable type that can be used as a dict key |
163 @type any hashable type that can be used as a dict key |
129 """ |
164 """ |
130 if key in self.__store: |
165 if key in self.__store: |
131 del self.__store[key] |
166 del self.__store[key] |
|
167 del self.__accesStore[key] |
132 self.__keyList.remove(key) |
168 self.__keyList.remove(key) |
133 |
169 |
134 def clear(self): |
170 def clear(self): |
135 """ |
171 """ |
136 Public method to clear the cache. |
172 Public method to clear the cache. |
137 """ |
173 """ |
138 self.__keyList = [] |
174 self.__keyList = [] |
139 self.__store = {} |
175 self.__store = {} |
|
176 self.__accesStore = {} |
140 |
177 |
141 def reset(self): |
178 def reset(self): |
142 """ |
179 """ |
143 Public method to reset the cache. |
180 Public method to reset the cache. |
144 |
181 |
170 "hits": self.__hits, |
207 "hits": self.__hits, |
171 "misses": self.__misses, |
208 "misses": self.__misses, |
172 "maxsize": self.__maxsize, |
209 "maxsize": self.__maxsize, |
173 "currsize": self.length(), |
210 "currsize": self.length(), |
174 } |
211 } |
|
212 |
|
213 def __pruneCache(self): |
|
214 """ |
|
215 Private slot to prune outdated cache entries and restart the timer. |
|
216 """ |
|
217 if self.__maxCacheTime > 0: |
|
218 current = QDateTime.currentDateTimeUtc() |
|
219 |
|
220 keysToBeDeleted = [] |
|
221 for key, lastAccessTime in self.__accesStore.items(): |
|
222 if lastAccessTime.secsTo(current) > self.__maxCacheTime: |
|
223 keysToBeDeleted.append(key) |
|
224 for key in keysToBeDeleted: |
|
225 self.remove(key) |
|
226 |
|
227 self.__cacheTimer.start() |