[Zodb-checkins] CVS: ZODB3/ZODB - serialize.py:1.1.2.3
Connection.py:1.98.6.14
Jeremy Hylton
cvs-admin at zope.org
Thu Oct 30 14:29:43 EST 2003
Update of /cvs-repository/ZODB3/ZODB
In directory cvs.zope.org:/tmp/cvs-serv5951/ZODB
Modified Files:
Tag: zodb33-devel-branch
serialize.py Connection.py
Log Message:
Move code for reading data records into serialize.
=== ZODB3/ZODB/serialize.py 1.1.2.2 => 1.1.2.3 ===
--- ZODB3/ZODB/serialize.py:1.1.2.2 Thu Oct 30 11:53:36 2003
+++ ZODB3/ZODB/serialize.py Thu Oct 30 14:29:42 2003
@@ -60,6 +60,13 @@
from ZODB.coptimizations import new_persistent_id
+_marker = object()
+
+def myhasattr(obj, attr):
+ """Returns True or False or raises an exception."""
+ val = getattr(obj, attr, _marker)
+ return val is not _marker
+
def getClassMetadata(obj):
klass = obj.__class__
if issubclass(klass, type):
@@ -100,7 +107,7 @@
self._stack = []
self._p.persistent_id = new_persistent_id(jar, self._stack)
if jar is not None:
- assert hasattr(jar, "new_oid")
+ assert myhasattr(jar, "new_oid")
self._jar = jar
def serialize(self, obj):
@@ -144,3 +151,102 @@
else:
raise StopIteration
+class BaseObjectReader:
+
+ def _persistent_load(self, oid):
+ # subclasses must define _persistent_load().
+ raise NotImplementedError
+
+ def _get_class(self, module, name):
+ # subclasses must define _get_class()
+ raise NotImplementedError
+
+ def _get_unpickler(self, pickle):
+ file = cStringIO.StringIO(pickle)
+ unpickler = cPickle.Unpickler(file)
+ unpickler.persistent_load = self._persistent_load
+ return unpickler
+
+ def _new_object(self, klass, args):
+ if not args and not myhasattr(klass, "__getinitargs__"):
+ obj = klass.__new__(klass)
+ else:
+ obj = klass(*args)
+ if klass is not type:
+ obj.__dict__.clear()
+
+ return obj
+
+ def getClassName(self, pickle):
+ unpickler = self._get_unpickler(pickle)
+ cls, newargs = unpickler.load()
+ return cls.__name__
+
+ def getGhost(self, pickle):
+ unpickler = self._get_unpickler(pickle)
+ klass, args = unpickler.load()
+ if isinstance(klass, tuple):
+ klass = self._get_class(*klass)
+
+ return self._new_object(klass, args)
+
+ def getState(self, pickle):
+ unpickler = self._get_unpickler(pickle)
+ unpickler.load() # skip the class metadata
+ return unpickler.load()
+
+ def setGhostState(self, obj, pickle):
+ state = self.getState(pickle)
+ obj.__setstate__(state)
+
+ def getObject(self, pickle):
+ unpickler = self._get_unpickler(pickle)
+ klass, args = unpickler.load()
+ obj = self._new_object(klass, args)
+ state = unpickler.load()
+ obj.__setstate__(state)
+ return obj
+
+class ConnectionObjectReader(BaseObjectReader):
+
+ def __init__(self, conn, cache, factory):
+ self._conn = conn
+ self._cache = cache
+ self._factory = factory
+
+ def _get_class(self, module, name):
+ return self._factory(self._conn, module, name)
+
+ def _persistent_load(self, oid):
+ if isinstance(oid, tuple):
+ # Quick instance reference. We know all we need to know
+ # to create the instance w/o hitting the db, so go for it!
+ oid, klass_info = oid
+ obj = self._cache.get(oid, None) # XXX it's not a dict
+ if obj is not None:
+ return obj
+
+ klass = self._get_class(*klass_info)
+ # XXX Why doesn't this have args?
+ obj = self._new_object(klass, None)
+ # XXX This doesn't address the last fallback that used to
+ # exist:
+## # Eek, we couldn't get the class. Hm. Maybe there's
+## # more current data in the object's actual record!
+## return self._conn[oid]
+
+ # XXX should be done by connection
+ obj._p_oid = oid
+ obj._p_jar = self._conn
+ # When an object is created, it is put in the UPTODATE
+ # state. We must explicitly deactivate it to turn it into
+ # a ghost.
+ obj._p_changed = None
+
+ self._cache[oid] = obj
+ return obj
+
+ obj = self._cache.get(oid)
+ if obj is not None:
+ return obj
+ return self._conn[oid]
=== ZODB3/ZODB/Connection.py 1.98.6.13 => 1.98.6.14 ===
--- ZODB3/ZODB/Connection.py:1.98.6.13 Tue Oct 28 16:28:32 2003
+++ ZODB3/ZODB/Connection.py Thu Oct 30 14:29:42 2003
@@ -15,8 +15,6 @@
$Id$"""
-from cPickle import Unpickler, Pickler
-from cStringIO import StringIO
import sys
import threading
from time import time
@@ -32,7 +30,8 @@
from ZODB.TmpStore import TmpStore
from ZODB.Transaction import Transaction, get_transaction
from ZODB.utils import oid_repr, z64
-from ZODB.serialize import ObjectWriter, getClassMetadata
+from ZODB.serialize \
+ import ObjectWriter, getClassMetadata, ConnectionObjectReader
global_code_timestamp = 0
@@ -134,71 +133,16 @@
if obj is not None:
return obj
- __traceback_info__ = oid,
p, serial = self._storage.load(oid, self._version)
- __traceback_info__ = oid, p
- file=StringIO(p)
- unpickler=Unpickler(file)
- unpickler.persistent_load=self._persistent_load
+ obj = self._reader.getGhost(p)
- object = unpickler.load()
+ obj._p_oid = oid
+ obj._p_jar = self
+ obj._p_changed = None
+ obj._p_serial = serial
- klass, args = object
-
- if isinstance(klass, tuple):
- module, name = klass
- klass=self._db._classFactory(self, module, name)
-
- if (args is None or not args and not hasattr(klass,'__getinitargs__')):
- object = klass.__new__(klass)
- else:
- object = klass(*args)
- if klass is not type:
- object.__dict__.clear()
-
- object._p_oid = oid
- object._p_jar = self
- object._p_changed = None
- object._p_serial = serial
-
- self._cache[oid] = object
- if oid == z64:
- self._root_=object # keep a ref
- return object
-
- def _persistent_load(self, oid):
- __traceback_info__ = oid
-
- if isinstance(oid, tuple):
- # Quick instance reference. We know all we need to know
- # to create the instance wo hitting the db, so go for it!
- oid, klass = oid
- obj = self._cache.get(oid, None)
- if obj is not None:
- return obj
-
- if isinstance(klass, tuple):
- module, name = klass
- try:
- klass = self._db._classFactory(self, module, name)
- except:
- # Eek, we couldn't get the class. Hm. Maybe there's
- # more current data in the object's actual record!
- return self[oid]
-
- object = klass.__new__(klass)
- object._p_oid = oid
- object._p_jar = self
- object._p_changed = None
-
- self._cache[oid] = object
-
- return object
-
- obj = self._cache.get(oid, None)
- if obj is not None:
- return obj
- return self[oid]
+ self._cache[oid] = obj
+ return obj
def sortKey(self):
# XXX will raise an exception if the DB hasn't been set
@@ -213,16 +157,18 @@
Any objects modified since the last transaction are invalidated.
"""
- self._db=odb
- self._storage=s=odb._storage
+ self._db = odb
+ self._reader = ConnectionObjectReader(self, self._cache,
+ self._db._classFactory)
+ self._storage = odb._storage
self._sortKey = odb._storage.sortKey
- self.new_oid=s.new_oid
+ self.new_oid = odb._storage.new_oid
if self._code_timestamp != global_code_timestamp:
# New code is in place. Start a new cache.
self._resetCache()
else:
self._flush_invalidations()
- self._opened=time()
+ self._opened = time()
return self
@@ -474,7 +420,7 @@
p, serial = self._storage.load(oid, self._version)
self._load_count = self._load_count + 1
invalid = self._is_invalidated(obj)
- self._set_ghost_state(obj, p)
+ self._reader.setGhostState(obj, p)
obj._p_serial = serial
if invalid:
self._handle_independent(obj)
@@ -508,19 +454,6 @@
finally:
self._inv_lock.release()
- def _set_ghost_state(self, obj, p):
- file = StringIO(p)
- unpickler = Unpickler(file)
- unpickler.persistent_load = self._persistent_load
- unpickler.load()
- state = unpickler.load()
-
- setstate = getattr(obj, "__setstate__", None)
- if setstate is None:
- obj.update(state)
- else:
- setstate(state)
-
def _handle_independent(self, obj):
# Helper method for setstate() handles possibly independent objects
# Call _p_independent(), if it returns True, setstate() wins.
@@ -539,42 +472,27 @@
self.getTransaction().register(obj)
raise ReadConflictError(object=obj)
- def oldstate(self, object, serial):
- oid=object._p_oid
- p = self._storage.loadSerial(oid, serial)
- file=StringIO(p)
- unpickler=Unpickler(file)
- unpickler.persistent_load=self._persistent_load
- unpickler.load()
- return unpickler.load()
-
- def setklassstate(self, object):
+ def oldstate(self, obj, serial):
+ p = self._storage.loadSerial(obj._p_oid, serial)
+ return self._reader.getState(p)
+
+ def setklassstate(self, obj):
+ # Special case code to handle ZClasses, I think.
+ # Called the cache when an object of type type is invalidated.
try:
- oid=object._p_oid
- __traceback_info__=oid
+ oid = obj._p_oid
p, serial = self._storage.load(oid, self._version)
- file=StringIO(p)
- unpickler=Unpickler(file)
- unpickler.persistent_load=self._persistent_load
-
- copy = unpickler.load()
-
- klass, args = copy
-
- if klass is not type:
- LOG('ZODB',ERROR,
- "Unexpected klass when setting class state on %s"
- % getattr(object,'__name__','(?)'))
- return
-
- copy = klass(*args)
- object.__dict__.clear()
- object.__dict__.update(copy.__dict__)
-
- object._p_oid=oid
- object._p_jar=self
- object._p_changed=0
- object._p_serial=serial
+
+ # We call getGhost(), but we actually get a non-ghost back.
+ # The object is a class, which can't actually be ghosted.
+ copy = self._reader.getGhost(p)
+ obj.__dict__.clear()
+ obj.__dict__.update(copy.__dict__)
+
+ obj._p_oid = oid
+ obj._p_jar = self
+ obj._p_changed = 0
+ obj._p_serial = serial
except:
LOG('ZODB',ERROR, 'setklassstate failed', error=sys.exc_info())
raise
More information about the Zodb-checkins
mailing list