[Zodb-checkins] SVN: ZODB/trunk/ Merge rev 29291 from ZODB 3.3 branch.

Tim Peters tim.one at comcast.net
Thu Feb 24 17:48:58 EST 2005


Log message for revision 29293:
  Merge rev 29291 from ZODB 3.3 branch.
  
  Port from ZODB 3.2.
  
  Give fsIndex an efficient maxKey() implementation.
  
  This will (in a later checkin) be used to give FileStorage an "obviously
  correct" way to determine the largest oid used in an .fs.index file.
  

Changed:
  U   ZODB/trunk/NEWS.txt
  U   ZODB/trunk/src/ZODB/fsIndex.py
  U   ZODB/trunk/src/ZODB/tests/testfsIndex.py

-=-
Modified: ZODB/trunk/NEWS.txt
===================================================================
--- ZODB/trunk/NEWS.txt	2005-02-24 22:44:50 UTC (rev 29292)
+++ ZODB/trunk/NEWS.txt	2005-02-24 22:48:58 UTC (rev 29293)
@@ -96,7 +96,16 @@
 that have the same oid (object identifier).  ZODB should never do this,
 but it's possible for application code to force such an attempt.
 
+fsIndex
+-------
 
+An efficient ``maxKey()`` method was implemented for the ``fsIndex`` class.
+This makes it possible to determine the largest oid in a ``FileStorage``
+index efficiently, directly, and reliably, replacing a more delicate scheme
+that tried to keep track of this by saving an oid high water mark in the
+index file and incrementally updating it.
+
+
 What's new in ZODB3 3.3.1a1?
 ============================
 Release date: 11-Jan-2005

Modified: ZODB/trunk/src/ZODB/fsIndex.py
===================================================================
--- ZODB/trunk/src/ZODB/fsIndex.py	2005-02-24 22:44:50 UTC (rev 29292)
+++ ZODB/trunk/src/ZODB/fsIndex.py	2005-02-24 22:48:58 UTC (rev 29293)
@@ -24,7 +24,7 @@
 #     2. We limit the data size to 48 bits. This should allow databases
 #        as large as 256 terabytes.
 #
-# Mostof the space is consumed by items in the mappings from 2-byte
+# Most of the space is consumed by items in the mappings from 2-byte
 # suffix to 6-byte data. This should reduce the overall memory usage to
 # 8-16 bytes per OID.
 #
@@ -125,3 +125,32 @@
 
     def values(self):
         return list(self.itervalues())
+
+    def maxKey(self):
+        # This is less general than the BTree method of the same name:  we
+        # only care about the largest key in the entire tree.  By
+        # construction, that's the largest oid in use in the associated
+        # FileStorage.
+
+        keys = self._data.keys()
+        if not keys:
+            # This is the same exception a BTree maxKey() raises when the
+            # tree is empty.
+            raise ValueError("empty tree")
+
+        # We expect that keys is small, since each fsBTree in _data.values()
+        # can hold as many as 2**16 = 64K entries.  So this max() should go
+        # fast too.  Regardless, there's no faster way to find the largest
+        # prefix.
+        biggest_prefix = max(keys)
+        tree = self._data[biggest_prefix]
+
+        # Obscure:  what if tree is actually empty?  We're relying here on
+        # that this class doesn't implement __delitem__:  once a key gets
+        # into an fsIndex, the only way it can go away is by invoking
+        # clear().  Therefore nothing in _data.values() is ever empty.
+        #
+        # Note that because `tree` is an fsBTree, its maxKey() method is very
+        # efficient.
+        assert tree
+        return biggest_prefix + tree.maxKey()

Modified: ZODB/trunk/src/ZODB/tests/testfsIndex.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testfsIndex.py	2005-02-24 22:44:50 UTC (rev 29292)
+++ ZODB/trunk/src/ZODB/tests/testfsIndex.py	2005-02-24 22:48:58 UTC (rev 29293)
@@ -12,6 +12,8 @@
 #
 ##############################################################################
 import unittest
+import random
+
 from ZODB.fsIndex import fsIndex
 from ZODB.utils import p64
 
@@ -111,7 +113,23 @@
         for i, item in enumerate(items):
             self.assertEqual(item, (p64(i * 1000), (i * 1000L + 1)))
 
+    def testMaxKey(self):
+        index = self.index
+        index.clear()
 
+        # An empty index should complain.
+        self.assertRaises(ValueError, index.maxKey)
+
+        # Now build up a tree with random values, and check maxKey at each
+        # step.
+        correct_max = ""   # smaller than anything we'll add
+        for i in range(1000):
+            key = p64(random.randrange(100000000))
+            index[key] = i
+            correct_max = max(correct_max, key)
+            index_max = index.maxKey()
+            self.assertEqual(index_max, correct_max)
+
 def test_suite():
     loader=unittest.TestLoader()
     return loader.loadTestsFromTestCase(Test)



More information about the Zodb-checkins mailing list