E5Utilities/E5Cache.py

changeset 5909
21d90a3abc7c
parent 5903
7e7002215f9e
child 5910
3f0255a8786a
diff -r 4d08fb83a844 -r 21d90a3abc7c E5Utilities/E5Cache.py
--- a/E5Utilities/E5Cache.py	Mon Oct 16 19:11:25 2017 +0200
+++ b/E5Utilities/E5Cache.py	Mon Oct 16 19:39:57 2017 +0200
@@ -9,6 +9,8 @@
 
 from __future__ import unicode_literals
 
+from PyQt5.QtCore import QDateTime, QTimer
+
 
 # TODO: add timeout for cached entries
 class E5Cache(object):
@@ -32,10 +34,16 @@
         
         # internal objects
         self.__keyList = []
-        self.__store = {}
+        self.__store = {}           # stores the cache entries
+        self.__accesStore = {}      # stores the last access date and times
         self.__hits = 0
         self.__misses = 0
         self.__maxsize = 0
+        self.__maxCacheTime = 0     # 0 seconds means aging is disabled
+        
+        self.__cacheTimer = QTimer()
+        self.__cacheTimer.setSingleShot(True)
+        self.__cacheTimer.timeout.connect(self.__pruneCache)
     
     def __moveLast(self, key):
         """
@@ -55,6 +63,7 @@
             self.__keyList[:-self.__size], self.__keyList[-self.__size:]
         for key in removeList:
             del self.__store[key]
+            del self.__accesStore[key]
     
     def getSize(self):
         """
@@ -78,6 +87,30 @@
         self.__size = newSize
         self.__adjustToSize()
     
+    def getMaximumCacheTime(self):
+        """
+        Public method to get the maximum time entries may exist in the cache.
+        
+        @return maximum cache time in seconds
+        @rtype int
+        """
+        return self.__maxCacheTime
+    
+    def setMaximumCacheTime(self, time):
+        """
+        Public method to set the maximum time entries may exist in the cache.
+        
+        @param time maximum cache time in seconds
+        @type int
+        """
+        if time != self.__maxCacheTime:
+            self.__cacheTimer.stop()
+            self.__pruneCache()
+            self.__maxCacheTime = time
+            if self.__maxCacheTime > 0:
+                self.__cacheTimer.setInterval(self.__maxCacheTime * 1000)
+                self.__cacheTimer.start()
+    
     def get(self, key):
         """
         Public method to get an entry from the cache given its key.
@@ -93,6 +126,7 @@
         if key in self.__store:
             self.__hits += 1
             self.__moveLast(key)
+            self.__accesStore[key] = QDateTime.currentDateTimeUtc()
             return self.__store[key]
         else:
             self.__misses += 1
@@ -115,6 +149,7 @@
         else:
             self.__keyList.append(key)
         self.__store[key] = item
+        self.__accesStore[key] = QDateTime.currentDateTimeUtc()
         
         self.__adjustToSize()
         
@@ -129,6 +164,7 @@
         """
         if key in self.__store:
             del self.__store[key]
+            del self.__accesStore[key]
             self.__keyList.remove(key)
     
     def clear(self):
@@ -137,6 +173,7 @@
         """
         self.__keyList = []
         self.__store = {}
+        self.__accesStore = {}
     
     def reset(self):
         """
@@ -172,3 +209,19 @@
             "maxsize": self.__maxsize,
             "currsize": self.length(),
         }
+    
+    def __pruneCache(self):
+        """
+        Private slot to prune outdated cache entries and restart the timer.
+        """
+        if self.__maxCacheTime > 0:
+            current = QDateTime.currentDateTimeUtc()
+            
+            keysToBeDeleted = []
+            for key, lastAccessTime in self.__accesStore.items():
+                if lastAccessTime.secsTo(current) > self.__maxCacheTime:
+                    keysToBeDeleted.append(key)
+            for key in keysToBeDeleted:
+                self.remove(key)
+        
+            self.__cacheTimer.start()

eric ide

mercurial