[Zodb-checkins] CVS: Zope3/src/zodb - serialize.py:1.10 conflict.py:1.8
Jeremy Hylton
jeremy@zope.com
Fri, 7 Mar 2003 18:09:53 -0500
Update of /cvs-repository/Zope3/src/zodb
In directory cvs.zope.org:/tmp/cvs-serv11711/zodb
Modified Files:
serialize.py conflict.py
Log Message:
Simplify getClassMetadata() and uncover a small tarpit.
The getClassMetadata() was using hasattr() and that was swallowing a
lot of exceptions. (Reminder: Never use hasattr() :-). The problem,
described in comments in the code, is that getClassMetadata() is
called on ghost objects where we can't check for a __getnewargs__().
Something needs to be done about this, but put a band-aid on it for
now.
=== Zope3/src/zodb/serialize.py 1.9 => 1.10 ===
--- Zope3/src/zodb/serialize.py:1.9 Thu Mar 6 15:34:25 2003
+++ Zope3/src/zodb/serialize.py Fri Mar 7 18:09:51 2003
@@ -62,14 +62,36 @@
from types import StringType, TupleType
import logging
-def getClassMetadata(obj=None, klass=None):
- if klass is None:
- klass = obj.__class__
- # 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
+def getClassMetadata(obj):
+ """Return 2-tuple that identifies class for ghost creation.
+
+ The 2-tuple contains the class of obj and a sequence of
+ arguments to pass to the class's __new__() to create a new
+ instance. If __new__() takes no extra arguments, the second
+ element of the tuple is None.
+ """
+ # XXX This is a hack. If the object is in a ghost state,
+ # we can't know whether its has a __getnewargs__ without
+ # loading the object -- but loading the object could fail
+ # with a ReadConflictError. Perhaps this can go away
+ # when MVCC is here.
+
+ # It happens to be the case that the only class I know of
+ # that defines a __getnewargs__() does not allow its instances
+ # to be ghosts. Maybe that is sufficient.
+
+ # Another alternative is to not store the class metadata
+ # with the object for references where we can't determine
+ # the full metadata. These objects would require a database
+ # load in order to create ghosts.
+
+ if obj._p_state == 3:
+ newargs = None
+ else:
+ newargs = getattr(obj, "__getnewargs__", None)
+ if newargs is not None:
+ newargs = newargs()
+ return obj.__class__, newargs
class RootJar:
def newObjectId(self):
@@ -115,7 +137,7 @@
# -- but I can't because the type doesn't have a canonical name.
# Instead, we'll assert that an oid must always be a string
if not (oid is None or isinstance(oid, StringType)):
- # XXX log a warning
+ logging.warn("unexpected _p_oid: %r", oid)
return None
if oid is None or obj._p_jar is not self._jar:
=== Zope3/src/zodb/conflict.py 1.7 => 1.8 ===
--- Zope3/src/zodb/conflict.py:1.7 Tue Feb 25 13:55:02 2003
+++ Zope3/src/zodb/conflict.py Fri Mar 7 18:09:51 2003
@@ -23,7 +23,7 @@
import logging
from zodb.interfaces import ConflictError
-from zodb.serialize import BaseObjectReader, ObjectWriter, getClassMetadata
+from zodb.serialize import BaseObjectReader, ObjectWriter
ResolvedSerial = "rs"
@@ -43,6 +43,7 @@
def __init__(self, ghost, state):
self._class = ghost.__class__
self._state = state
+ self._p_state = 0 # required to make getClassMetadata() happy
def __getattribute__(self, name):
if name == "__class__":
@@ -97,8 +98,10 @@
# In a ZEO environment, this method isn't as useful. If the
# method is called from a client, it will always return False,
# because the conflict resolution code runs on the server.
- meta = getClassMetadata(klass=klass)
- return meta in cls.bad_classes
+
+ # This method depends on the representation of class metadata
+ # that is otherwise only used inside zodb.serialize.
+ return (klass, None) in cls.bad_classes
unresolvable = classmethod(unresolvable)