]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- identity_map._mutable_attrs is a plain dict since we manage weakref removal explicitly
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Oct 2008 02:02:51 +0000 (02:02 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Oct 2008 02:02:51 +0000 (02:02 +0000)
- call list() around iteration of _mutable_attrs to guard against async gc.collect() while check_modified() is running

CHANGES
lib/sqlalchemy/orm/identity.py
test/orm/memusage.py

diff --git a/CHANGES b/CHANGES
index 6ce7d07c7afac50d471fbf229ada70ac8efccd11..c129c065292da70162d68c0ef9fa738ef69511d7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -43,6 +43,10 @@ CHANGES
 
     - Fixed session.transaction.commit() on a autocommit=False
       session not starting a new transaction.
+      
+    - Some adjustments to Session.identity_map's weak referencing
+      behavior to reduce asynchronous GC side effects.
+      
 - sql
     - column.in_(someselect) can now be used as a columns-clause
       expression without the subquery bleeding into the FROM clause
index 6369d5a3c28fb5acdee4c105ae6df4efd51607fc..4232821612e4d0b3b055d71a50834b2c086de782 100644 (file)
@@ -12,7 +12,7 @@ from sqlalchemy.orm import attributes
 
 class IdentityMap(dict):
     def __init__(self):
-        self._mutable_attrs = weakref.WeakKeyDictionary()
+        self._mutable_attrs = {}
         self.modified = False
         
     def add(self, state):
@@ -41,7 +41,7 @@ class IdentityMap(dict):
         """return True if any InstanceStates present have been marked as 'modified'."""
         
         if not self.modified:
-            for state in self._mutable_attrs:
+            for state in list(self._mutable_attrs):
                 if state.check_modified():
                     return True
             else:
index 6348f22371be9de97029916d47ffe58059a47391..ab6a5e2c0aca17df3588529ba67b60cfdcbc9339 100644 (file)
@@ -1,11 +1,11 @@
 import testenv; testenv.configure_for_tests()
 import gc
-from sqlalchemy.orm import mapper, relation, create_session, clear_mappers
+from sqlalchemy.orm import mapper, relation, create_session, clear_mappers, sessionmaker
 from sqlalchemy.orm.mapper import _mapper_registry
 from sqlalchemy.orm.session import _sessions
-
+import operator
 from testlib import testing
-from testlib.sa import MetaData, Table, Column, Integer, String, ForeignKey
+from testlib.sa import MetaData, Table, Column, Integer, String, ForeignKey, PickleType
 from orm import _base
 
 
@@ -300,6 +300,53 @@ class MemUsageTest(EnsureZeroed):
             metadata.drop_all()
         assert_no_mappers()
 
+    def test_mutable_identity(self):
+        metadata = MetaData(testing.db)
 
+        table1 = Table("mytable", metadata,
+            Column('col1', Integer, primary_key=True),
+            Column('col2', PickleType(comparator=operator.eq))
+            )
+        
+        class Foo(object):
+            def __init__(self, col2):
+                self.col2 = col2
+        
+        mapper(Foo, table1)
+        metadata.create_all()
+        
+        session = sessionmaker()()
+        
+        def go():
+            obj = [
+                Foo({'a':1}),
+                Foo({'b':1}),
+                Foo({'c':1}),
+                Foo({'d':1}),
+                Foo({'e':1}),
+                Foo({'f':1}),
+                Foo({'g':1}),
+                Foo({'h':1}),
+                Foo({'i':1}),
+                Foo({'j':1}),
+                Foo({'k':1}),
+                Foo({'l':1}),
+            ]
+            
+            session.add_all(obj)
+            session.commit()
+            
+            testing.eq_(len(session.identity_map._mutable_attrs), 12)
+            testing.eq_(len(session.identity_map), 12)
+            obj = None
+            gc.collect()
+            testing.eq_(len(session.identity_map._mutable_attrs), 0)
+            testing.eq_(len(session.identity_map), 0)
+            
+        try:
+            go()
+        finally:
+            metadata.drop_all()
+        
 if __name__ == '__main__':
     testenv.main()