[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/SQLScript - ISQLScript.py:1.5 SQLScript.py:1.7

Erik ersab@codeworks.lt
Thu, 8 Aug 2002 11:06:30 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/SQLScript
In directory cvs.zope.org:/tmp/cvs-serv29083

Modified Files:
	ISQLScript.py SQLScript.py 
Log Message:
Ported SQL caching support from Zope 2.



=== Zope3/lib/python/Zope/App/OFS/Content/SQLScript/ISQLScript.py 1.4 => 1.5 ===
--- Zope3/lib/python/Zope/App/OFS/Content/SQLScript/ISQLScript.py:1.4	Thu Aug  8 07:10:23 2002
+++ Zope3/lib/python/Zope/App/OFS/Content/SQLScript/ISQLScript.py	Thu Aug  8 11:05:59 2002
@@ -37,32 +37,45 @@
     connectionName = SQLConnectionName(
         id="connectionName",
         title="Connection Name",
-        description="""The Connection Name for the connection to be used.""",
+        description="The Connection Name for the connection to be used.",
         required=1)
 
     arguments = Schema.Str(
         id="arguments",
         title="Arguments",
-        description='A set of attributes that can be used during the DTML '
-                    'rendering process to provide dynamic data.',
+        description="A set of attributes that can be used during the DTML "
+                    "rendering process to provide dynamic data.",
         required=0)
 
     source = Schema.Str(
         id="source",
         title="Source",
-        description="""The source of the page template.""",
+        description="The source of the page template.",
+        required=1)
+
+    maxCache = Schema.Int(
+        id="maxCache",
+        title="Maximum results to cache",
+        description="The size of the SQL script cache.",
+        min=0,
+        required=1)
+
+    cacheTime = Schema.Int(
+        id="cacheTime",
+        title="Maximum time (sec) to cache",
+        description="The time in seconds that results are cached. "
+                    "Setting to zero disables caching.",
+        min=0,
         required=1)
 
     def setArguments(arguments):
         """Processes the arguments (which could be a dict, string or whatever)
         to arguments as they are needed for the rendering process."""
 
-
     def getArguments():
         """Get the arguments. A method is preferred here, since some argument
         evaluation might be done."""
 
-
     def getArgumentsString():
         """This method returns the arguments string."""
 
@@ -80,3 +93,15 @@
 
     def getConnectionName():
         """Get the connection name for this SQL Script."""
+
+    def setMaxCache(maxCache):
+        """Set the size of the SQL script cache."""
+
+    def getMaxCache():
+        """Get the size of the SQL script cache."""
+
+    def setCacheTime(cacheTime):
+        """Set the time in seconds that results are cached."""
+
+    def getCacheTime():
+        """Get the time in seconds that results are cached."""


=== Zope3/lib/python/Zope/App/OFS/Content/SQLScript/SQLScript.py 1.6 => 1.7 ===
--- Zope3/lib/python/Zope/App/OFS/Content/SQLScript/SQLScript.py:1.6	Thu Aug  8 07:05:54 2002
+++ Zope3/lib/python/Zope/App/OFS/Content/SQLScript/SQLScript.py	Thu Aug  8 11:05:59 2002
@@ -33,6 +33,11 @@
 from DT_SQLTest import SQLTest
 from DT_SQLGroup import SQLGroup
 
+from time import time
+
+try: from Persistence.BTrees.IOBTree import IOBucket as Bucket
+except: Bucket = lambda:{}
+
 
 class SQLDTML(HTML):
     __name__ = 'SQLDTML'
@@ -52,11 +57,14 @@
 
     __implements__ = ISQLScript, IFileContent
 
-    def __init__(self, connectionName='', source='', arguments=''):
+    def __init__(self, connectionName='', source='', arguments='',
+                 maxCache=0, cacheTime=0):
         self.template = SQLDTML(source)
         self.setConnectionName(connectionName)
         # In our case arguments should be a string that is parsed
         self.setArguments(arguments)
+        self.setMaxCache(maxCache)
+        self.setCacheTime(cacheTime)
 
     def setArguments(self, arguments):
         'See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript'
@@ -88,11 +96,30 @@
     def setConnectionName(self, name):
         'See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript'
         self._connectionName = name
+        self._clearCache()
 
     def getConnectionName(self):
         'See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript'
         return self._connectionName
 
+    def setMaxCache(self, maxCache):
+        'See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript'
+        self._maxCache = maxCache
+        self._clearCache()
+
+    def getMaxCache(self):
+        'See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript'
+        return self._maxCache
+
+    def setCacheTime(self, cacheTime):
+        'See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript'
+        self._cacheTime = cacheTime
+        self._clearCache()
+
+    def getCacheTime(self):
+        'See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript'
+        return self._cacheTime
+
     def getConnection(self):
         'See Zope.App.RDB.ISQLCommand.ISQLCommand'
         connection_service = getService(self, "Connections")
@@ -138,11 +165,49 @@
 
         query = apply(self.template, (), arg_values)
 
-        return queryForResults(connection, query)
+        if self._maxCache > 0 and self._cacheTime > 0:
+            return self._cachedResult(connection, query)
+        else:
+            return queryForResults(connection, query)
 
     __call__ = ContextMethod(__call__)
 
 
+    def _clearCache(self):
+        'Clear the cache'
+        self._v_cache = {}, Bucket()
+
+    def _cachedResult(self, connection, query):
+        'Try to fetch query result from cache'
+        if not hasattr(self, '_v_cache'):
+            self._clearCache()
+        cache, tcache = self._v_cache
+        max_cache = self._maxCache
+        now = time()
+        t = now - self._cacheTime
+        if len(cache) > max_cache / 2:
+            keys = tcache.keys()
+            keys.reverse()
+            while keys and (len(keys) > max_cache or keys[-1] < t):
+                key = keys[-1]
+                q = tcache[key]
+                del tcache[key]
+                if int(cache[q][0]) == key:
+                    del cache[q]
+                del keys[-1]
+
+        if cache.has_key(query):
+            k, r = cache[query]
+            if k > t: return r
+
+        result = queryForResults(connection, query)
+        if self._cacheTime > 0:
+            tcache[int(now)] = query
+            cache[query] = now, result
+
+        return result
+
+
     # See Zope.App.OFS.Content.SQLScript.ISQLScript.ISQLScript
     arguments = property(getArgumentsString, setArguments, None,
                          "Set the arguments that are used for the SQL Script.")
@@ -150,4 +215,8 @@
                       "Set the SQL template source.")
     connectionName = property(getConnectionName, setConnectionName, None,
                               "Connection Name for the SQL scripts.")
+    maxCache = property(getMaxCache, setMaxCache, None,
+                        "Set the size of the SQL Script cache.")
+    cacheTime = property(getCacheTime, setCacheTime, None,
+                         "Set the time in seconds that results are cached.")