From f0fc47c11986a0fa60b24c0fb62bd8b5a5306edd Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 10 May 2021 13:19:14 -0400 Subject: Correct cache key for proxy_owner, with_context_options Fixed issue in subquery loader strategy which prevented caching from working correctly. This would have been seen in the logs as a "generated" message instead of "cached" for all subqueryload SQL emitted, which by saturating the cache with new keys would degrade overall performance; it also would produce "LRU size alert" warnings. In this issue we also observe that the local LRU cache for lazyloader and selectinloader will get used for all subsequent loads as well, which makes it more likely to hit the limit of 30. However rather than trying to work this out, it would be better if we removed the loader-local LRU caches altogether once we are confident these are working well. Fixes: #6459 Change-Id: Id953e8f75536bb87f7e3315929cebcd8f84a5a50 --- lib/sqlalchemy/sql/traversals.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'lib/sqlalchemy/sql/traversals.py') diff --git a/lib/sqlalchemy/sql/traversals.py b/lib/sqlalchemy/sql/traversals.py index e8a805285..e64eff6a4 100644 --- a/lib/sqlalchemy/sql/traversals.py +++ b/lib/sqlalchemy/sql/traversals.py @@ -310,6 +310,12 @@ class CacheKey(namedtuple("CacheKey", ["key", "bindparams"])): def __eq__(self, other): return self.key == other.key + @classmethod + def _diff_tuples(cls, left, right): + ck1 = CacheKey(left, []) + ck2 = CacheKey(right, []) + return ck1._diff(ck2) + def _whats_different(self, other): k1 = self.key @@ -413,6 +419,11 @@ class _CacheKey(ExtendedInternalTraversal): visit_propagate_attrs = PROPAGATE_ATTRS + def visit_with_context_options( + self, attrname, obj, parent, anon_map, bindparams + ): + return tuple((fn.__code__, c_key) for fn, c_key in obj) + def visit_inspectable(self, attrname, obj, parent, anon_map, bindparams): return (attrname, inspect(obj)._gen_cache_key(anon_map, bindparams)) @@ -1209,6 +1220,13 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): else: return left == right + def visit_with_context_options( + self, attrname, left_parent, left, right_parent, right, **kw + ): + return tuple((fn.__code__, c_key) for fn, c_key in left) == tuple( + (fn.__code__, c_key) for fn, c_key in right + ) + def visit_plain_obj( self, attrname, left_parent, left, right_parent, right, **kw ): -- cgit v1.2.1