[Zodb-checkins] SVN: ZODB/branches/adamg-btree-keeps-reference/src/BTrees/tests/testBTrees.py added a test that shows that the Btree keeps a reference to objects

Adam Groszer agroszer at gmail.com
Wed Aug 26 12:57:00 EDT 2009


Log message for revision 103237:
  added a test that shows that the Btree keeps a reference to objects

Changed:
  U   ZODB/branches/adamg-btree-keeps-reference/src/BTrees/tests/testBTrees.py

-=-
Modified: ZODB/branches/adamg-btree-keeps-reference/src/BTrees/tests/testBTrees.py
===================================================================
--- ZODB/branches/adamg-btree-keeps-reference/src/BTrees/tests/testBTrees.py	2009-08-26 16:54:53 UTC (rev 103236)
+++ ZODB/branches/adamg-btree-keeps-reference/src/BTrees/tests/testBTrees.py	2009-08-26 16:56:59 UTC (rev 103237)
@@ -11,6 +11,7 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
+import gc
 import pickle
 import random
 import StringIO
@@ -1569,7 +1570,23 @@
             # at some unrelated line.
             del t   # trigger destructor
 
+LP294788_ids = {}
 
+class ToBeDeleted(object):
+    def __init__(self, id):
+        assert type(id) is int #we don't want to store any object ref here
+        self.id = id
+
+        global LP294788_ids
+        LP294788_ids[id] = 1
+
+    def __del__(self):
+        global LP294788_ids
+        #this might raise KeyError if the LP294788_ids dict is cleaned before
+        #the object gets GC'ed, but this should not happen
+        del LP294788_ids[self.id]
+
+
 class BugFixes(TestCase):
 
     # Collector 1843.  Error returns were effectively ignored in
@@ -1582,7 +1599,164 @@
         # This one used to segfault.
         self.assertRaises(TypeError, t.keys, 0, "")
 
+    def test_LP294788(self):
+        # https://bugs.launchpad.net/bugs/294788
+        # BTree keeps some deleted objects referenced
 
+        # The logic here together with the ToBeDeleted class is that
+        # a separate reference dict is populated on object creation
+        # and removed in __del__
+        # That means what's left in the reference dict is never GC'ed
+        # therefore referenced somewhere
+        # To simulate real life, some random data is used to exercise the tree
+
+        t = OOBTree()
+
+        random.seed('OOBTree')
+
+        global LP294788_ids
+
+        # /// BTree keys are integers, value is an object
+        LP294788_ids = {}
+        ids = {}
+        for i in xrange(1024):
+            if random.random() > 0.1:
+                #add
+                id = None
+                while id is None or ids.has_key(id):
+                    id = random.randint(0,1000000)
+
+                ids[id] = 1
+                t[id] = ToBeDeleted(id)
+            else:
+                #del
+                id = random.choice(ids.keys())
+                del t[id]
+                del ids[id]
+
+        ids = ids.keys()
+        random.shuffle(ids)
+        for id in ids:
+            del t[id]
+        ids = None
+
+        #to be on the safe side run a full GC
+        gc.collect()
+
+        #print LP294788_ids
+
+        self.assertEqual(len(t), 0)
+        self.assertEqual(len(LP294788_ids), 0)
+        # \\\
+
+        # /// BTree keys are integers, value is a tuple having an object
+        LP294788_ids = {}
+        ids = {}
+        for i in xrange(1024):
+            if random.random() > 0.1:
+                #add
+                id = None
+                while id is None or ids.has_key(id):
+                    id = random.randint(0,1000000)
+
+                ids[id] = 1
+                t[id] = (id, ToBeDeleted(id), u'somename')
+            else:
+                #del
+                id = random.choice(ids.keys())
+                del t[id]
+                del ids[id]
+
+        ids = ids.keys()
+        random.shuffle(ids)
+        for id in ids:
+            del t[id]
+        ids = None
+
+        #to be on the safe side run a full GC
+        gc.collect()
+
+        #print LP294788_ids
+
+        self.assertEqual(len(t), 0)
+        self.assertEqual(len(LP294788_ids), 0)
+        # \\\
+
+
+        # /// BTree keys are objects, value is an int
+        t = OOBTree()
+        LP294788_ids = {}
+        ids = {}
+        for i in xrange(1024):
+            if random.random() > 0.1:
+                #add
+                id = None
+                while id is None or ids.has_key(id):
+                    id = random.randint(0,1000000)
+
+                obj = ToBeDeleted(id)
+                ids[obj] = 1
+                t[obj] = 1
+            else:
+                #del
+                obj = random.choice(ids.keys())
+                del ids[obj]
+                del t[obj]
+
+        ids = ids.keys()
+        random.shuffle(ids)
+        for id in ids:
+            del t[id]
+        #release all refs
+        ids = None
+
+        #to be on the safe side run a full GC
+        gc.collect()
+
+        #print LP294788_ids
+
+        self.assertEqual(len(t), 0)
+        self.assertEqual(len(LP294788_ids), 0)
+        # \\\
+
+        # /// BTree keys are tuples having objects, value is an int
+        t = OOBTree()
+        LP294788_ids = {}
+        ids = {}
+        for i in xrange(1024):
+            if random.random() > 0.1:
+                #add
+                id = None
+                while id is None or ids.has_key(id):
+                    id = random.randint(0,1000000)
+
+                key = (id, ToBeDeleted(id), u'somename')
+                ids[key] = 1
+                t[key] = 1
+            else:
+                #del
+                key = random.choice(ids.keys())
+                del ids[key]
+                del t[key]
+
+        ids = ids.keys()
+        random.shuffle(ids)
+        for id in ids:
+            del t[id]
+        #release all refs
+        ids = None
+
+        #to be on the safe side run a full GC
+        gc.collect()
+
+        #print LP294788_ids
+
+        self.assertEqual(len(t), 0)
+        self.assertEqual(len(LP294788_ids), 0)
+        # \\\
+
+
+
 class IIBTreeTest(BTreeTests):
     def setUp(self):
         self.t = IIBTree()
@@ -1618,7 +1792,7 @@
             self.t = OIBTree()
         def getTwoKeys(self):
             return object(), object()
-    
+
 class LLBTreeTest(BTreeTests, TestLongIntKeys, TestLongIntValues):
     def setUp(self):
         self.t = LLBTree()



More information about the Zodb-checkins mailing list