Skip to content

Commit

Permalink
Connection.setstate passes the object's OID as a parameter to the hel…
Browse files Browse the repository at this point in the history
…per Connection._setstate.

This is a performance optimization for PyPy (profiling shows many recursive calls to Persistent.__getattribute__, and recursive calls seem to trouble the PyPy JIT; this eliminates many of them when loading objects):

"Transaction",                 AFTER       BEFORE
"Add 3000 Objects",             20205      18505
"Update 3000 Objects",          24191      18807
"Read 3000 Warm Objects",       28920      26671
"Read 3000 Cold Objects",       28745      27487
"Read 3000 Hot Objects",        29563      27487
"Read 3000 Steamin' Objects", 1033758     916587
  • Loading branch information
jamadden committed May 20, 2015
1 parent 8840c09 commit 228604d
Showing 1 changed file with 11 additions and 8 deletions.
19 changes: 11 additions & 8 deletions src/ZODB/Connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,16 +866,19 @@ def setstate(self, obj):
raise

try:
self._setstate(obj)
self._setstate(obj, oid)
except ConflictError:
raise
except:
self._log.exception("Couldn't load state for %s %s",
className(obj), oid_repr(oid))
raise

def _setstate(self, obj):
def _setstate(self, obj, oid):
# Helper for setstate(), which provides logging of failures.
# We accept the oid param, which must be the same as obj._p_oid,
# as a performance optimization for the pure-Python persistent implementation
# where accessing an attribute involves __getattribute__ calls

# The control flow is complicated here to avoid loading an
# object revision that we are sure we aren't going to use. As
Expand All @@ -890,7 +893,7 @@ def _setstate(self, obj):
if self.before is not None:
# Load data that was current before the time we have.
before = self.before
t = self._storage.loadBefore(obj._p_oid, before)
t = self._storage.loadBefore(oid, before)
if t is None:
raise POSKeyError() # historical connection!
p, serial, end = t
Expand All @@ -903,16 +906,16 @@ def _setstate(self, obj):
if self._invalidatedCache:
raise ReadConflictError()

if (obj._p_oid in self._invalidated):
if (oid in self._invalidated):
self._load_before_or_conflict(obj)
return

p, serial = self._storage.load(obj._p_oid, '')
p, serial = self._storage.load(oid, '')
self._load_count += 1

self._inv_lock.acquire()
try:
invalid = obj._p_oid in self._invalidated
invalid = oid in self._invalidated
finally:
self._inv_lock.release()

Expand All @@ -922,13 +925,13 @@ def _setstate(self, obj):

self._reader.setGhostState(obj, p)
obj._p_serial = serial
self._cache.update_object_size_estimation(obj._p_oid, len(p))
self._cache.update_object_size_estimation(oid, len(p))
obj._p_estimated_size = len(p)

# Blob support
if isinstance(obj, Blob):
obj._p_blob_uncommitted = None
obj._p_blob_committed = self._storage.loadBlob(obj._p_oid, serial)
obj._p_blob_committed = self._storage.loadBlob(oid, serial)

def _load_before_or_conflict(self, obj):
"""Load non-current state for obj or raise ReadConflictError."""
Expand Down

0 comments on commit 228604d

Please sign in to comment.