[Zope-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 Zope-Checkins mailing list