[Zodb-checkins] CVS: ZODB4/ZODB - ConflictResolution.py:1.13 Connection.py:1.78 DB.py:1.52 FileStorage.py:1.98
Jeremy Hylton
jeremy@zope.com
Thu, 19 Sep 2002 14:22:05 -0400
Update of /cvs-repository/ZODB4/ZODB
In directory cvs.zope.org:/tmp/cvs-serv22608/ZODB
Modified Files:
ConflictResolution.py Connection.py DB.py FileStorage.py
Log Message:
Use new Serialize module for unpickling.
ConflictResolution:
Simplify PersistentReferenceFactory.
Use the ResolveUnpickler to get a resolve method and get state
from pickles.
Connection:
Each Connection gets a ConnectionUnpickler instance.
Delete all unpickling code.
Change failure return value of tryToResolveConflict() to None.
DB:
Delete _classFactory method. It's now a function in Serialize.
Hack: Change the way the root is created. This needs to be
cleaner.
=== ZODB4/ZODB/ConflictResolution.py 1.12 => 1.13 ===
--- ZODB4/ZODB/ConflictResolution.py:1.12 Thu Sep 5 16:20:01 2002
+++ ZODB4/ZODB/ConflictResolution.py Thu Sep 19 14:22:04 2002
@@ -15,20 +15,9 @@
from cPickle import Unpickler, Pickler
from Transaction.Exceptions import ConflictError
+from ZODB.Serialize import ResolveUnpickler
-bad_classes={}
-def bad_class(class_tuple):
- if (class_tuple in bad_classes) or class_tuple[0][0] == '*':
- # if we've seen the class before or if it's a ZClass, we know that
- # we can't resolve the conflict
- return 1
-
-ResolvedSerial='rs'
-
-def _classFactory(location, name,
- _silly=('__doc__',), _globals={}):
- return getattr(__import__(location, _globals, _globals, _silly),
- name)
+ResolvedSerial = 'rs'
def state(storage, oid, serial, prfactory, p=''):
p=p or storage.loadSerial(oid, serial)
@@ -39,7 +28,6 @@
state=unpickler.load()
return state
-
class PersistentReference:
def __repr__(self):
@@ -53,22 +41,18 @@
data = None
def __call__(self, oid):
- data = self.data
- if not data:
- data = self.data = {}
+ if self.data is None:
+ self.data = {}
- r = data.get(oid, None)
+ r = self.data.get(oid)
if r is None:
r = PersistentReference()
r.data = oid
- data[oid] = r
+ self.data[oid] = r
return r
-def persistent_id(object,
- PersistentReference=PersistentReference,
- getattr=getattr
- ):
+def persistent_id(object):
if getattr(object, '__class__', 0) is not PersistentReference:
return None
return object.data
@@ -78,36 +62,23 @@
def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle,
committedData=''):
- try:
- file = StringIO(newpickle)
- unpickler = Unpickler(file)
- prfactory = PersistentReferenceFactory()
- unpickler.persistent_load = prfactory
- class_tuple = unpickler.load()[0]
- if bad_class(class_tuple):
- return 0
-
- newstate = unpickler.load()
- klass = _classFactory(class_tuple[0], class_tuple[1])
- inst = klass.__new__(klass)
-
+ unpickler = ResolveUnpickler(PersistentReferenceFactory(),
+ can_resolve_class)
+ resolve = unpickler.getResolveMethod(newpickle)
+ if resolve is None:
+ return None
+ else:
try:
- resolve = inst._p_resolveConflict
- except AttributeError:
- bad_classes[class_tuple] = 1
- return 0
-
- old = state(self, oid, oldSerial, prfactory)
- committed = state(self, oid, committedSerial, prfactory,
- committedData)
-
- resolved = resolve(old, committed, newstate)
-
- file = StringIO()
- pickler = Pickler(file,1)
- pickler.persistent_id = persistent_id
- pickler.dump(class_tuple)
- pickler.dump(resolved)
- return file.getvalue(1)
- except ConflictError:
- return 0
+ p = self.loadSerial(oid, oldSerial)
+ old = unpickler.getState(p)
+ committed = unpickler.getState(committedData)
+ resolved = resolve(old, committed, newstate)
+
+ file = StringIO()
+ pickler = Pickler(file,1)
+ pickler.persistent_id = persistent_id
+ pickler.dump(class_tuple)
+ pickler.dump(resolved)
+ return file.getvalue(1)
+ except ConflictError:
+ return None
=== ZODB4/ZODB/Connection.py 1.77 => 1.78 ===
--- ZODB4/ZODB/Connection.py:1.77 Tue Sep 17 17:44:25 2002
+++ ZODB4/ZODB/Connection.py Thu Sep 19 14:22:04 2002
@@ -48,12 +48,14 @@
from ZODB.ConflictResolution import ResolvedSerial
from ZODB.IConnection import IConnection
from ZODB.POSException import ConflictError
+from ZODB.Serialize import ConnectionUnpickler, \
+ new_persistent_id, getClassMetadata
from Transaction import get_transaction
from Persistence.Cache import Cache
from zLOG import LOG, ERROR, BLATHER, INFO
-from cPickle import Unpickler, Pickler
+import cPickle
from cStringIO import StringIO
import sys
import time
@@ -96,6 +98,7 @@
self.new_oid = db._storage.new_oid
self._version = version
self._cache = cache = Cache(cache_size, cache_deactivate_after)
+ self._unpickler = ConnectionUnpickler(self, self._cache)
# _invalidated queues invalidate messages delivered from the DB
self._invalidated = Set()
@@ -116,79 +119,6 @@
def root(self):
return self['\0\0\0\0\0\0\0\0']
- def _persistent_load(self, oid):
- # persistent_load function to pass to Unpickler
- if isinstance(oid, TupleType):
- # 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 = oid
- object = self._cache.get(oid)
- if object is not None:
- return object
-
- if isinstance(klass, TupleType):
- module, name = klass
- try:
- klass = self._db._classFactory(self, module, name)
- except: # XXX except what?
- LOG('ZODB', INFO, "Couldn't load class %s.%s" % (
- module, name), error=sys.exc_info())
- # Couldn't get the class. More current data may
- # be in the object's actual record.
- return self[oid]
-
- # CXX This isn't quite right, but I'm not sure what is.
- # The contacts are a bit unclear.
- object = klass.__new__(klass)
-
- object._p_oid = oid
- object._p_jar = self
- object._p_changed = None
-
- self._cache[oid] = object
-
- return object
-
- object = self._cache.get(oid)
- if object is not None:
- return object
- return self[oid]
-
- def _get_unpickler(self, p):
- file = StringIO(p)
- unpickler = Unpickler(file)
- unpickler.persistent_load = self._persistent_load
- return unpickler
-
- def _unpickle_object(self, p):
- unpickler = self._get_unpickler(p)
- klass, args = unpickler.load()
-
- if isinstance(klass, TupleType):
- module, name = klass
- klass = self._db._classFactory(self, module, name)
-
- if (args is None or
- not args and not hasattr(klass, '__getinitargs__')):
- # XXX (jeremy) Not sure what the comment below means.
- # CXX This isn't quite right, but I'm not sure what is.
- # The contacts are a bit unclear.
- object = klass.__new__(klass)
- else:
- object = klass(*args)
- # XXX What does is the following test supposed to
- # accomplish?
- if klass is not type:
- object.__dict__.clear()
-
- return object
-
- def _unpickle_state(self, p):
- unpickler = self._get_unpickler(p)
- unpickler.load() # returns klass, args
- state = unpickler.load()
- return state
-
def __getitem__(self, oid):
# assume that a cache cannot store None as a valid object
object = self._cache.get(oid)
@@ -196,7 +126,7 @@
return object
p, serial = self._storage.load(oid, self._version)
- object = self._unpickle_object(p)
+ object = self._unpickler.getGhost(p)
object._p_oid = oid
object._p_jar = self
@@ -240,15 +170,7 @@
else:
invalid = 0
- state = self._unpickle_state(p)
-
- if hasattr(object, '__setstate__'):
- object.__setstate__(state)
- else:
- d = object.__dict__
- for k, v in state.iteritems():
- d[k] = v
-
+ self._unpickler.setGhostState(object, p)
object._p_serial = serial
if invalid:
@@ -359,7 +281,7 @@
stack = [object]
file = StringIO()
- pickler = Pickler(file, 1)
+ pickler = cPickle.Pickler(file, 1)
pickler.persistent_id = new_persistent_id(self, stack)
while stack:
@@ -380,22 +302,12 @@
raise ConflictError(oid=oid)
self._modified.add(oid)
- klass = pobject.__class__
-
- if hasattr(klass, '__getinitargs__'):
- args = pobject.__getinitargs__()
- len(args) # XXX Assert it's a sequence
- else:
- args = None # New no-constructor protocol!
-
- module = getattr(klass,'__module__','')
- if module:
- klass = module, klass.__name__
+ module, classname, newargs = getClassMetadata(pobject)
state = pobject.__getstate__()
file.seek(0)
pickler.clear_memo()
- pickler.dump((klass, args))
+ pickler.dump((module, classname, newargs))
pickler.dump(state)
p = file.getvalue(1)
s = self._storage.store(oid, serial, p, self._version, transaction)
@@ -586,58 +498,6 @@
self._invalidated.clear()
self._cache.incrgc() # This is a good time to do some GC
-def new_persistent_id(self, stack):
- # XXX need a doc string. not sure if the one for persistent_id()
- # below is correct.
-
- # Create a special persistent_id that captures T and the subobject
- # stack in a closure.
-
- def persistent_id(object):
- """Test if an object is persistent, returning an oid if it is.
-
- This function is used by the pickler to test whether an object
- is persistent. If it isn't, the function returns None and the
- object is included in the pickle for the current persistent
- object.
-
- If it is persistent, it returns the oid and sometimes a tuple
- with other stuff.
- """
-
- if (not hasattr(object, '_p_oid') or
- isinstance(object, ClassType)):
- return None
-
- oid = object._p_oid
-
- # I'd like to write something like this --
- # if isinstance(oid, types.MemberDescriptor):
- # -- 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 (isinstance(oid, StringType) or oid is None):
- return None
-
- if oid is None or object._p_jar is not self:
- oid = self.new_oid()
- object._p_jar = self
- object._p_oid = oid
- stack.append(object)
-
- klass = object.__class__
-
- if klass is type:
- return oid
- if hasattr(klass, '__getinitargs__'):
- return oid
- module = getattr(klass,'__module__', '')
- if module:
- klass = module, klass.__name__
-
- return oid, klass
-
- return persistent_id
-
class Rollback:
"""Rollback changes associated with savepoint"""
=== ZODB4/ZODB/DB.py 1.51 => 1.52 ===
--- ZODB4/ZODB/DB.py:1.51 Mon Aug 5 16:08:38 2002
+++ ZODB4/ZODB/DB.py Thu Sep 19 14:22:04 2002
@@ -84,7 +84,7 @@
# The pickle must be in the special ZODB format.
file = cStringIO.StringIO()
p = cPickle.Pickler(file, 1)
- p.dump((root.__class__, None))
+ p.dump((root.__class__.__module__, root.__class__.__name__, None))
p.dump(root.__getstate__())
t = Transaction()
t.note("initial database creation")
@@ -110,11 +110,6 @@
if m[1]: m=m[0]/m[1]
else: m=None
return m
-
- def _classFactory(self, connection, location, name,
- _silly=('__doc__',), _globals={}):
- return getattr(__import__(location, _globals, _globals, _silly),
- name)
def _closeConnection(self, connection):
"""Return a connection to the pool"""
=== ZODB4/ZODB/FileStorage.py 1.97 => 1.98 ===
--- ZODB4/ZODB/FileStorage.py:1.97 Thu Aug 1 12:23:53 2002
+++ ZODB4/ZODB/FileStorage.py Thu Sep 19 14:22:04 2002
@@ -680,7 +680,7 @@
if serial != oserial:
data=self.tryToResolveConflict(oid, oserial, serial, data)
- if not data:
+ if data is None:
raise POSException.ConflictError(oid=oid,
serials=(oserial, serial))
else: