summaryrefslogtreecommitdiff
path: root/test/aaa_profiling/test_memusage.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/aaa_profiling/test_memusage.py')
-rw-r--r--test/aaa_profiling/test_memusage.py167
1 files changed, 167 insertions, 0 deletions
diff --git a/test/aaa_profiling/test_memusage.py b/test/aaa_profiling/test_memusage.py
index 4756a3fd5..d30ccb3b8 100644
--- a/test/aaa_profiling/test_memusage.py
+++ b/test/aaa_profiling/test_memusage.py
@@ -2,6 +2,7 @@ import decimal
import gc
import itertools
import multiprocessing
+import pickle
import weakref
import sqlalchemy as sa
@@ -38,6 +39,7 @@ from sqlalchemy.sql.visitors import replacement_traverse
from sqlalchemy.testing import engines
from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import pickleable
from sqlalchemy.testing.fixtures import fixture_session
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
@@ -1778,3 +1780,168 @@ class MiscMemoryIntensiveTests(fixtures.TestBase):
s.flush()
eq_(s.scalar(select(func.count("*")).select_from(User.__table__)), 0)
s.commit()
+
+
+class WeakIdentityMapTest(_fixtures.FixtureTest):
+ run_inserts = None
+
+ @testing.requires.predictable_gc
+ def test_weakref(self):
+ """test the weak-referencing identity map, which strongly-
+ references modified items."""
+
+ users, User = self.tables.users, self.classes.User
+
+ s = fixture_session()
+ self.mapper_registry.map_imperatively(User, users)
+ gc_collect()
+
+ s.add(User(name="ed"))
+ s.flush()
+ assert not s.dirty
+
+ user = s.query(User).one()
+
+ # heisenberg the GC a little bit, since #7823 caused a lot more
+ # GC when mappings are set up, larger test suite started failing
+ # on this being gc'ed
+ user_is = user._sa_instance_state
+ del user
+ gc_collect()
+ gc_collect()
+ gc_collect()
+ assert user_is.obj() is None
+
+ assert len(s.identity_map) == 0
+
+ user = s.query(User).one()
+ user.name = "fred"
+ del user
+ gc_collect()
+ assert len(s.identity_map) == 1
+ assert len(s.dirty) == 1
+ assert None not in s.dirty
+ s.flush()
+ gc_collect()
+ assert not s.dirty
+ assert not s.identity_map
+
+ user = s.query(User).one()
+ assert user.name == "fred"
+ assert s.identity_map
+
+ @testing.requires.predictable_gc
+ def test_weakref_pickled(self):
+ users, User = self.tables.users, pickleable.User
+
+ s = fixture_session()
+ self.mapper_registry.map_imperatively(User, users)
+ gc_collect()
+
+ s.add(User(name="ed"))
+ s.flush()
+ assert not s.dirty
+
+ user = s.query(User).one()
+ user.name = "fred"
+ s.expunge(user)
+
+ u2 = pickle.loads(pickle.dumps(user))
+
+ del user
+ s.add(u2)
+
+ del u2
+ gc_collect()
+
+ assert len(s.identity_map) == 1
+ assert len(s.dirty) == 1
+ assert None not in s.dirty
+ s.flush()
+ gc_collect()
+ assert not s.dirty
+
+ assert not s.identity_map
+
+ @testing.requires.predictable_gc
+ def test_weakref_with_cycles_o2m(self):
+ Address, addresses, users, User = (
+ self.classes.Address,
+ self.tables.addresses,
+ self.tables.users,
+ self.classes.User,
+ )
+
+ s = fixture_session()
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties={"addresses": relationship(Address, backref="user")},
+ )
+ self.mapper_registry.map_imperatively(Address, addresses)
+ gc_collect()
+
+ s.add(User(name="ed", addresses=[Address(email_address="ed1")]))
+ s.commit()
+
+ user = s.query(User).options(joinedload(User.addresses)).one()
+ user.addresses[0].user # lazyload
+ eq_(user, User(name="ed", addresses=[Address(email_address="ed1")]))
+
+ del user
+ gc_collect()
+ assert len(s.identity_map) == 0
+
+ user = s.query(User).options(joinedload(User.addresses)).one()
+ user.addresses[0].email_address = "ed2"
+ user.addresses[0].user # lazyload
+ del user
+ gc_collect()
+ assert len(s.identity_map) == 2
+
+ s.commit()
+ user = s.query(User).options(joinedload(User.addresses)).one()
+ eq_(user, User(name="ed", addresses=[Address(email_address="ed2")]))
+
+ @testing.requires.predictable_gc
+ def test_weakref_with_cycles_o2o(self):
+ Address, addresses, users, User = (
+ self.classes.Address,
+ self.tables.addresses,
+ self.tables.users,
+ self.classes.User,
+ )
+
+ s = fixture_session()
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties={
+ "address": relationship(Address, backref="user", uselist=False)
+ },
+ )
+ self.mapper_registry.map_imperatively(Address, addresses)
+ gc_collect()
+
+ s.add(User(name="ed", address=Address(email_address="ed1")))
+ s.commit()
+
+ user = s.query(User).options(joinedload(User.address)).one()
+ user.address.user
+ eq_(user, User(name="ed", address=Address(email_address="ed1")))
+
+ del user
+ gc_collect()
+ assert len(s.identity_map) == 0
+
+ user = s.query(User).options(joinedload(User.address)).one()
+ user.address.email_address = "ed2"
+ user.address.user # lazyload
+
+ del user
+ gc_collect()
+ assert len(s.identity_map) == 2
+
+ s.commit()
+ user = s.query(User).options(joinedload(User.address)).one()
+ eq_(user, User(name="ed", address=Address(email_address="ed2")))