[Zodb-checkins] CVS: Zope3/src/zodb - serialize.py:1.2.4.1
Jeremy Hylton
jeremy@zope.com
Tue, 21 Jan 2003 11:16:50 -0500
Update of /cvs-repository/Zope3/src/zodb
In directory cvs.zope.org:/tmp/cvs-serv24765/src/zodb
Modified Files:
Tag: new-pickle-branch
serialize.py
Log Message:
Change object serialization format.
ZODB pickles objects using a custom format. Each object pickle had
two parts: the class metadata and the object state. The class
description must provide enough information to call the class's
``__new__`` and create an empty object. Once the object exists as a
ghost, its state is passed to ``__setstate__``.
The class metadata is a two-tuple containing the class object and a
tuple of arguments to pass to ``__new__``. The second element may be
None if the only argument to ``__new__`` is the class. Since the
first argument is a class, it will normally be pickled as a global
reference. If the class is itself a persistent object, then the first
part of its instances class metadata will be a persistent reference to
the class.
=== Zope3/src/zodb/serialize.py 1.2 => 1.2.4.1 ===
--- Zope3/src/zodb/serialize.py:1.2 Wed Dec 25 09:12:16 2002
+++ Zope3/src/zodb/serialize.py Tue Jan 21 11:16:46 2003
@@ -21,31 +21,38 @@
ghost allows many persistent objects to be loaded while minimizing the
memory consumption of referenced but otherwise unused objects.
-Object introspection
---------------------
-
-XXX Need to define what properties an object must have to be usable
-with the ObjectWriter. Should document how it determines what the
-class and state of an object are.
-
Pickle format
-------------
ZODB pickles objects using a custom format. Each object pickle had
-two parts: the class description and the object state. The class
+two parts: the class metadata and the object state. The class
description must provide enough information to call the class's
-``__new__`` and create an empty object. Once the object exists, its
-state is passed to ``__getstate__``.
+``__new__`` and create an empty object. Once the object exists as a
+ghost, its state is passed to ``__setstate__``.
-The class metadata is a three-tuple contained the module name, the
-class name, and a tuple of arguments to pass to ``__new__``. The last
-element may be None if the only argument to ``__new__`` is the class.
+The class metadata is a two-tuple containing the class object and a
+tuple of arguments to pass to ``__new__``. The second element may be
+None if the only argument to ``__new__`` is the class. Since the
+first argument is a class, it will normally be pickled as a global
+reference. If the class is itself a persistent object, then the first
+part of its instances class metadata will be a persistent reference to
+the class.
Persistent references
---------------------
+
A persistent reference is a pair containing an oid and class metadata.
-XXX Need to write more about when they are used and when plain oids
-are used.
+When one persistent object pickle refers to another persistent object,
+the database uses a persistent reference. The format allows a
+significant optimization, because ghosts can be created directly from
+persistent references. If the reference was just an oid, a database
+access would be required to determine the class of the ghost.
+
+Because the persistent reference includes the class, it is not
+possible to change the class of a persistent object. If a transaction
+changed the class of an object, a new record with new class metadata
+would be written but all the old references would still include the
+old class.
"""
__metaclass__ = type
@@ -55,24 +62,14 @@
from types import StringType, TupleType
import logging
-def getClass(module, name):
- mod = __import__(module)
- parts = module.split(".")
- for part in parts[1:]:
- mod = getattr(mod, part)
- return getattr(mod, name)
-
def getClassMetadata(obj=None, klass=None):
if klass is None:
klass = obj.__class__
- module = klass.__module__
- classname = klass.__name__
- # XXX what if obj is None and we were passed klass?
- if hasattr(obj, "__getnewargs__"):
- newargs = obj.__getnewargs__()
- else:
- newargs = None
- return module, classname, newargs
+ # XXX Not sure I understand the obj==None casse
+ newargs = None
+ if obj is not None and hasattr(obj, "__getnewargs__"):
+ newargs = obj.__getnewargs__()
+ return klass, newargs
class RootJar:
def new_oid(self):
@@ -176,8 +173,7 @@
unpickler.persistent_load = self._persistent_load
return unpickler
- def _new_object(self, module, classname, newargs=None):
- klass = getClass(module, classname)
+ def _new_object(self, klass, newargs=None):
if newargs is None:
obj = klass.__new__(klass)
else:
@@ -192,8 +188,8 @@
def getGhost(self, pickle):
unpickler = self._get_unpickler(pickle)
- module, classname, newargs = unpickler.load()
- return self._new_object(module, classname, newargs)
+ klass, newargs = unpickler.load()
+ return self._new_object(klass, newargs)
def getState(self, pickle):
unpickler = self._get_unpickler(pickle)
@@ -207,8 +203,8 @@
def getObject(self, pickle):
unpickler = self._get_unpickler(pickle)
- module, classname, newargs = unpickler.load()
- obj = self._new_object(module, classname, newargs)
+ klass, newargs = unpickler.load()
+ obj = self._new_object(klass, newargs)
state = unpickler.load()
obj.__setstate__(state)
return obj