[Zope-Checkins] SVN: Zope/trunk/ Added date range index improvements from ``experimental.catalogqueryplan``.

Hanno Schlichting hannosch at hannosch.eu
Sat Oct 2 05:42:50 EDT 2010


Log message for revision 117157:
  Added date range index improvements from ``experimental.catalogqueryplan``.
  

Changed:
  U   Zope/trunk/doc/CHANGES.rst
  U   Zope/trunk/src/Products/PluginIndexes/DateRangeIndex/DateRangeIndex.py

-=-
Modified: Zope/trunk/doc/CHANGES.rst
===================================================================
--- Zope/trunk/doc/CHANGES.rst	2010-10-02 09:42:05 UTC (rev 117156)
+++ Zope/trunk/doc/CHANGES.rst	2010-10-02 09:42:50 UTC (rev 117157)
@@ -26,6 +26,8 @@
 Features Added
 ++++++++++++++
 
+- Added date range index improvements from ``experimental.catalogqueryplan``.
+
 - Changed policy on handling exceptions during ZCML parsing in ``Products``.
   We no longer catch any exceptions in non-debug mode.
 

Modified: Zope/trunk/src/Products/PluginIndexes/DateRangeIndex/DateRangeIndex.py
===================================================================
--- Zope/trunk/src/Products/PluginIndexes/DateRangeIndex/DateRangeIndex.py	2010-10-02 09:42:05 UTC (rev 117156)
+++ Zope/trunk/src/Products/PluginIndexes/DateRangeIndex/DateRangeIndex.py	2010-10-02 09:42:50 UTC (rev 117157)
@@ -20,10 +20,15 @@
 from AccessControl.Permissions import manage_zcatalog_indexes
 from AccessControl.Permissions import view
 from AccessControl.SecurityInfo import ClassSecurityInfo
+from Acquisition import aq_base
+from Acquisition import aq_get
+from Acquisition import aq_inner
+from Acquisition import aq_parent
 from App.Common import package_home
 from App.special_dtml import DTMLFile
 from BTrees.IIBTree import IISet
 from BTrees.IIBTree import IITreeSet
+from BTrees.IIBTree import difference
 from BTrees.IIBTree import intersection
 from BTrees.IIBTree import multiunion
 from BTrees.IOBTree import IOBTree
@@ -40,6 +45,12 @@
 MAX32 = int(2**31 - 1)
 
 
+class RequestCache(dict):
+
+    def __str__(self):
+        return "<RequestCache %s items>" % len(self)
+
+
 class DateRangeIndex(UnIndex):
 
     """Index for date ranges, such as the "effective-expiration" range in CMF.
@@ -240,6 +251,13 @@
 
         return tuple( result )
 
+    def _cache_key(self, catalog):
+        cid = catalog.getId()
+        counter = getattr(aq_base(catalog), 'getCounter', None)
+        if counter is not None:
+            return '%s_%s' % (cid, counter())
+        return cid
+
     def _apply_index(self, request, resultset=None):
         """
             Apply the index to query parameters given in 'request', which
@@ -253,33 +271,71 @@
             second object is a tuple containing the names of all data fields
             used.
         """
-        record = parseIndexRequest(request, self.id, self.query_options)
+        iid = self.id
+        record = parseIndexRequest(request, iid, self.query_options)
         if record.keys is None:
             return None
 
-        term        = self._convertDateTime( record.keys[0] )
+        term = self._convertDateTime(record.keys[0])
 
-        #
-        #   Aggregate sets for each bucket separately, to avoid
-        #   large-small union penalties.
-        #
-        until_only = multiunion( self._until_only.values( term ) )
-        since_only = multiunion( self._since_only.values( None, term ) )
-        until = multiunion( self._until.values( term ) )
+        REQUEST = aq_get(self, 'REQUEST', None)
+        if REQUEST is not None:
+            catalog = aq_parent(aq_parent(aq_inner(self)))
+            if catalog is not None:
+                key = self._cache_key(catalog)
+                cache = REQUEST.get(key, None)
+                tid = term / 10
+                if resultset is None:
+                    cachekey = '_daterangeindex_%s_%s' % (iid, tid)
+                else:
+                    cachekey = '_daterangeindex_inverse_%s_%s' % (iid, tid)
+                if cache is None:
+                    cache = REQUEST[key] = RequestCache()
+                else:
+                    cached = cache.get(cachekey, None)
+                    if cached is not None:
+                        if resultset is None:
+                            return (cached,
+                                    (self._since_field, self._until_field))
+                        else:
+                            return (difference(resultset, cached),
+                                    (self._since_field, self._until_field))
 
-        # Total result is bound by resultset
-        until = intersection(resultset, until)
-        since = multiunion(self._since.values(None, term))
-        bounded = intersection(until, since)
+        if resultset is None:
+            # Aggregate sets for each bucket separately, to avoid
+            # large-small union penalties.
+            until_only = multiunion(self._until_only.values(term))
+            since_only = multiunion(self._since_only.values(None, term))
+            until = multiunion(self._until.values(term))
 
-        #   Merge from smallest to largest.
-        result = multiunion([bounded, until_only, since_only, self._always])
+            # Total result is bound by resultset
+            if REQUEST is None:
+                until = intersection(resultset, until)
 
-        return result, ( self._since_field, self._until_field )
+            since = multiunion(self._since.values(None, term))
+            bounded = intersection(until, since)
 
-    #
-    #   Helper functions.
-    #
+            # Merge from smallest to largest.
+            result = multiunion([bounded, until_only, since_only,
+                                 self._always])
+            if REQUEST is not None and catalog is not None:
+                cache[cachekey] = result
+
+            return (result, (self._since_field, self._until_field))
+        else:
+            # Compute the inverse and subtract from res
+            until_only = multiunion(self._until_only.values(None, term))
+            since_only = multiunion(self._since_only.values(term))
+            until = multiunion(self._until.values(None, term))
+            since = multiunion(self._since.values(term))
+
+            result = multiunion([until_only, since_only, until,since])
+            if REQUEST is not None and catalog is not None:
+                cache[cachekey] = result
+
+            return (difference(resultset, result),
+                    (self._since_field, self._until_field))
+
     def _insertForwardIndexEntry( self, since, until, documentId ):
         """
             Insert 'documentId' into the appropriate set based on



More information about the Zope-Checkins mailing list