mirror of
https://github.com/python/cpython.git
synced 2025-11-01 10:45:30 +00:00
* Use weakref's of DBCursor objects for the iterator cursors to avoid a
memory leak that would've occurred for all iterators that were destroyed before having iterated until they raised StopIteration. * Simplify some code. * Add new test cases to check for the memleak and ensure that mixing iteration with modification of the values for existing keys works.
This commit is contained in:
parent
83c187460e
commit
a703a21b48
3 changed files with 159 additions and 52 deletions
|
|
@ -3,6 +3,7 @@
|
|||
Adapted to unittest format and expanded scope by Raymond Hettinger
|
||||
"""
|
||||
import os, sys
|
||||
import copy
|
||||
import bsddb
|
||||
import dbhash # Just so we know it's imported
|
||||
import unittest
|
||||
|
|
@ -64,6 +65,56 @@ class TestBSDDB(unittest.TestCase):
|
|||
self.assertSetEquals(d.itervalues(), f.itervalues())
|
||||
self.assertSetEquals(d.iteritems(), f.iteritems())
|
||||
|
||||
def test_iter_while_modifying_values(self):
|
||||
if not hasattr(self.f, '__iter__'):
|
||||
return
|
||||
|
||||
di = iter(self.d)
|
||||
while 1:
|
||||
try:
|
||||
key = di.next()
|
||||
self.d[key] = 'modified '+key
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
# it should behave the same as a dict. modifying values
|
||||
# of existing keys should not break iteration. (adding
|
||||
# or removing keys should)
|
||||
fi = iter(self.f)
|
||||
while 1:
|
||||
try:
|
||||
key = fi.next()
|
||||
self.f[key] = 'modified '+key
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
self.test_mapping_iteration_methods()
|
||||
|
||||
def test_iteritems_while_modifying_values(self):
|
||||
if not hasattr(self.f, 'iteritems'):
|
||||
return
|
||||
|
||||
di = self.d.iteritems()
|
||||
while 1:
|
||||
try:
|
||||
k, v = di.next()
|
||||
self.d[k] = 'modified '+v
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
# it should behave the same as a dict. modifying values
|
||||
# of existing keys should not break iteration. (adding
|
||||
# or removing keys should)
|
||||
fi = self.f.iteritems()
|
||||
while 1:
|
||||
try:
|
||||
k, v = fi.next()
|
||||
self.f[k] = 'modified '+v
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
self.test_mapping_iteration_methods()
|
||||
|
||||
def test_first_next_looping(self):
|
||||
items = [self.f.first()]
|
||||
for i in xrange(1, len(self.f)):
|
||||
|
|
@ -111,15 +162,16 @@ class TestBSDDB(unittest.TestCase):
|
|||
# the cursor's read lock will deadlock the write lock request..
|
||||
|
||||
# test the iterator interface (if present)
|
||||
if hasattr(self, 'iteritems'):
|
||||
if hasattr(self.f, 'iteritems'):
|
||||
if debug: print "D"
|
||||
k,v = self.f.iteritems()
|
||||
i = self.f.iteritems()
|
||||
k,v = i.next()
|
||||
if debug: print "E"
|
||||
self.f[k] = "please don't deadlock"
|
||||
if debug: print "F"
|
||||
while 1:
|
||||
try:
|
||||
k,v = self.f.iteritems()
|
||||
k,v = i.next()
|
||||
except StopIteration:
|
||||
break
|
||||
if debug: print "F2"
|
||||
|
|
@ -144,6 +196,27 @@ class TestBSDDB(unittest.TestCase):
|
|||
self.f[k] = "be gone with ye deadlocks"
|
||||
self.assert_(self.f[k], "be gone with ye deadlocks")
|
||||
|
||||
def test_for_cursor_memleak(self):
|
||||
if not hasattr(self.f, 'iteritems'):
|
||||
return
|
||||
|
||||
# do the bsddb._DBWithCursor _iter_mixin internals leak cursors?
|
||||
nc1 = len(self.f._cursor_refs)
|
||||
# create iterator
|
||||
i = self.f.iteritems()
|
||||
nc2 = len(self.f._cursor_refs)
|
||||
# use the iterator (should run to the first yeild, creating the cursor)
|
||||
k, v = i.next()
|
||||
nc3 = len(self.f._cursor_refs)
|
||||
# destroy the iterator; this should cause the weakref callback
|
||||
# to remove the cursor object from self.f._cursor_refs
|
||||
del i
|
||||
nc4 = len(self.f._cursor_refs)
|
||||
|
||||
self.assertEqual(nc1, nc2)
|
||||
self.assertEqual(nc1, nc4)
|
||||
self.assert_(nc3 == nc1+1)
|
||||
|
||||
def test_popitem(self):
|
||||
k, v = self.f.popitem()
|
||||
self.assert_(k in self.d)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue