From 77c8def8720db6ab2260e1e48b86d0642219e9ff Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 5 Mar 2011 12:19:40 -0500 Subject: [PATCH] - Tightened the iterate vs. remove mutex around the identity map iteration, attempting to reduce the chance of an (extremely rare) reentrant gc operation causing a deadlock. Might remove the mutex in 0.7. [ticket:2087] --- CHANGES | 6 ++++ lib/sqlalchemy/orm/identity.py | 65 +++++++++++++++++----------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/CHANGES b/CHANGES index 54a546cf58..71243e7033 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,12 @@ CHANGES 0.6.7 ===== - orm + - Tightened the iterate vs. remove mutex around the + identity map iteration, attempting to reduce the + chance of an (extremely rare) reentrant gc operation + causing a deadlock. Might remove the mutex in + 0.7. [ticket:2087] + - Added a `name` argument to `Query.subquery()`, to allow a fixed name to be assigned to the alias object. [ticket:2030] diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py index 33f781092e..5df405fb5b 100644 --- a/lib/sqlalchemy/orm/identity.py +++ b/lib/sqlalchemy/orm/identity.py @@ -140,7 +140,9 @@ class WeakInstanceDict(IdentityMap): self._remove_mutex.acquire() try: if dict.pop(self, state.key) is not state: - raise AssertionError("State %s is not present in this identity map" % state) + raise AssertionError( + "State %s is not present in this identity map" % state + ) finally: self._remove_mutex.release() @@ -162,49 +164,46 @@ class WeakInstanceDict(IdentityMap): return default return o - - def items(self): + def _items(self): + values = self.all_states() + result = [] + for state in values: + value = state.obj() + if value is not None: + result.append((state.key, value)) + return result + + def _values(self): + values = self.all_states() + result = [] + for state in values: + value = state.obj() + if value is not None: + result.append(value) + + return result + + # Py3K + #def items(self): + # return iter(self._items()) + # + #def values(self): + # return iter(self._values()) # Py2K - return list(self.iteritems()) - + items = _items def iteritems(self): - # end Py2K - self._remove_mutex.acquire() - try: - result = [] - for state in dict.values(self): - value = state.obj() - if value is not None: - result.append((state.key, value)) - - return iter(result) - finally: - self._remove_mutex.release() - - def values(self): - # Py2K - return list(self.itervalues()) + return iter(self.items()) + values = _values def itervalues(self): + return iter(self.values()) # end Py2K - self._remove_mutex.acquire() - try: - result = [] - for state in dict.values(self): - value = state.obj() - if value is not None: - result.append(value) - - return iter(result) - finally: - self._remove_mutex.release() def all_states(self): self._remove_mutex.acquire() try: # Py3K # return list(dict.values(self)) - # Py2K return dict.values(self) # end Py2K -- 2.47.2