Commit 4e7b5aba authored by Shane Hathaway's avatar Shane Hathaway

Fixed the optimization in the catalog that iterates over the sort index

rather than the result set when the result set is much larger than the
sort index.  Added a test and cleaned up the test framework.
parent 4a4e022c
...@@ -23,7 +23,7 @@ from zLOG import LOG, ERROR ...@@ -23,7 +23,7 @@ from zLOG import LOG, ERROR
from Lazy import LazyMap, LazyFilter, LazyCat from Lazy import LazyMap, LazyFilter, LazyCat
from CatalogBrains import AbstractCatalogBrain, NoBrainer from CatalogBrains import AbstractCatalogBrain, NoBrainer
from BTrees.IIBTree import intersection, weightedIntersection from BTrees.IIBTree import intersection, weightedIntersection, IISet
from BTrees.OIBTree import OIBTree from BTrees.OIBTree import OIBTree
from BTrees.IOBTree import IOBTree from BTrees.IOBTree import IOBTree
import BTrees.Length import BTrees.Length
...@@ -549,9 +549,19 @@ class Catalog(Persistent, Acquisition.Implicit, ExtensionClass.Base): ...@@ -549,9 +549,19 @@ class Catalog(Persistent, Acquisition.Implicit, ExtensionClass.Base):
if (len(rs) > (len(sort_index) * 4)): if (len(rs) > (len(sort_index) * 4)):
# The result set is much larger than the sorted index, # The result set is much larger than the sorted index,
# so iterate over the sorted index for speed. # so iterate over the sorted index for speed.
try:
intersection(rs, IISet(()))
except TypeError:
# rs is not an object in the IIBTree family.
# Try to turn rs into an IISet.
if hasattr(rs, 'keys'):
rs = rs.keys()
rs = IISet(rs)
for k, intset in sort_index.items(): for k, intset in sort_index.items():
# We have an index that has a set of values for # We have an index that has a set of values for
# each sort key, so we interset with each set and # each sort key, so we intersect with each set and
# get a sorted sequence of the intersections. # get a sorted sequence of the intersections.
intset = _intersection(rs, intset) intset = _intersection(rs, intset)
if intset: if intset:
...@@ -630,7 +640,8 @@ class Catalog(Persistent, Acquisition.Implicit, ExtensionClass.Base): ...@@ -630,7 +640,8 @@ class Catalog(Persistent, Acquisition.Implicit, ExtensionClass.Base):
used = self._indexedSearch(args, sort_index, r.append, used) used = self._indexedSearch(args, sort_index, r.append, used)
if not _merge: if not _merge:
# Postpone merging and sorting. This provides a way to # Postpone merging and sorting. This provides a way to
# sort results merged from multiple catalogs. # efficiently sort results merged from multiple queries
# or multiple catalogs.
return r return r
else: else:
has_sort_keys = 0 has_sort_keys = 0
......
...@@ -307,6 +307,14 @@ class TestCatalogObject(unittest.TestCase): ...@@ -307,6 +307,14 @@ class TestCatalogObject(unittest.TestCase):
a = self._catalog(att3='att3', att2='att2') a = self._catalog(att3='att3', att2='att2')
assert len(a) == self.upper assert len(a) == self.upper
def testLargeSortedResultSetWithSmallIndex(self):
# This exercises the optimization in the catalog that iterates
# over the sort index rather than the result set when the result
# set is much larger than the sort index.
a = self._catalog(sort_on='att1')
self.assertEqual(len(a), self.upper)
class objRS(ExtensionClass.Base): class objRS(ExtensionClass.Base):
def __init__(self,num): def __init__(self,num):
...@@ -350,8 +358,5 @@ def test_suite(): ...@@ -350,8 +358,5 @@ def test_suite():
suite.addTest( unittest.makeSuite( testRS ) ) suite.addTest( unittest.makeSuite( testRS ) )
return suite return suite
def main():
unittest.TextTestRunner().run(test_suite())
if __name__ == '__main__': if __name__ == '__main__':
main() unittest.main(defaultTest='test_suite')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment