[Zodb-checkins] CVS: Zope/lib/python/ZODB - BaseStorage.py:1.20.4.3 Connection.py:1.72.4.1 POSException.py:1.12.4.4
Chris McDonough
chrism@zope.com
Tue, 10 Sep 2002 23:37:09 -0400
Update of /cvs-repository/Zope/lib/python/ZODB
In directory cvs.zope.org:/tmp/cvs-serv22446/lib/python/ZODB
Modified Files:
Tag: chrism-install-branch
BaseStorage.py Connection.py POSException.py
Log Message:
Merging chrism-install-branch with HEAD changes.
=== Zope/lib/python/ZODB/BaseStorage.py 1.20.4.2 => 1.20.4.3 ===
--- Zope/lib/python/ZODB/BaseStorage.py:1.20.4.2 Tue Sep 3 03:43:47 2002
+++ Zope/lib/python/ZODB/BaseStorage.py Tue Sep 10 23:36:38 2002
@@ -108,12 +108,14 @@
def tpc_abort(self, transaction):
self._lock_acquire()
try:
- if transaction is not self._transaction: return
+ if transaction is not self._transaction:
+ return
self._abort()
self._clear_temp()
- self._transaction=None
+ self._transaction = None
self._commit_lock_release()
- finally: self._lock_release()
+ finally:
+ self._lock_release()
def _abort(self):
"""Subclasses should redefine this to supply abort actions"""
@@ -122,34 +124,36 @@
def tpc_begin(self, transaction, tid=None, status=' '):
self._lock_acquire()
try:
- if self._transaction is transaction: return
+ if self._transaction is transaction:
+ return
self._lock_release()
self._commit_lock_acquire()
self._lock_acquire()
- self._transaction=transaction
+ self._transaction = transaction
self._clear_temp()
- user=transaction.user
- desc=transaction.description
- ext=transaction._extension
- if ext: ext=dumps(ext,1)
- else: ext=""
- self._ude=user, desc, ext
+ user = transaction.user
+ desc = transaction.description
+ ext = transaction._extension
+ if ext:
+ ext = dumps(ext,1)
+ else:
+ ext=""
+ self._ude = user, desc, ext
if tid is None:
- t=time.time()
- t=apply(TimeStamp,(time.gmtime(t)[:5]+(t%60,)))
- self._ts=t=t.laterThan(self._ts)
- self._serial=`t`
+ now = time.time()
+ t = TimeStamp(*(time.gmtime(now)[:5] + (now % 60,)))
+ self._ts = t = t.laterThan(self._ts)
+ self._serial = `t`
else:
- self._ts=TimeStamp(tid)
- self._serial=tid
-
- self._tstatus=status
+ self._ts = TimeStamp(tid)
+ self._serial = tid
+ self._tstatus = status
self._begin(self._serial, user, desc, ext)
-
- finally: self._lock_release()
+ finally:
+ self._lock_release()
def _begin(self, tid, u, d, e):
"""Subclasses should redefine this to supply transaction start actions.
@@ -159,7 +163,8 @@
def tpc_vote(self, transaction):
self._lock_acquire()
try:
- if transaction is not self._transaction: return
+ if transaction is not self._transaction:
+ return
self._vote()
finally:
self._lock_release()
@@ -172,16 +177,17 @@
def tpc_finish(self, transaction, f=None):
self._lock_acquire()
try:
- if transaction is not self._transaction: return
+ if transaction is not self._transaction:
+ return
try:
- if f is not None: f()
-
- u,d,e=self._ude
+ if f is not None:
+ f()
+ u, d, e = self._ude
self._finish(self._serial, u, d, e)
self._clear_temp()
finally:
- self._ude=None
- self._transaction=None
+ self._ude = None
+ self._transaction = None
self._commit_lock_release()
finally:
self._lock_release()
=== Zope/lib/python/ZODB/Connection.py 1.72 => 1.72.4.1 ===
--- Zope/lib/python/ZODB/Connection.py:1.72 Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/Connection.py Tue Sep 10 23:36:38 2002
@@ -268,28 +268,44 @@
self.__onCommitActions.append((method_name, args, kw))
get_transaction().register(self)
+ # NB: commit() is responsible for calling tpc_begin() on the storage.
+ # It uses self._begun to track whether it has been called. When
+ # self._begun is None, it has not been called.
+
+ # This arrangement allows us to handle the special case of a
+ # transaction with no modified objects. It is possible for
+ # registration to be occur unintentionally and for a persistent
+ # object to compensate by making itself as unchanged. When this
+ # happens, it's possible to commit a transaction with no modified
+ # objects.
+
+ # Since tpc_begin() may raise a ReadOnlyError, don't call it if there
+ # are no objects. This avoids spurious (?) errors when working with
+ # a read-only storage.
+
def commit(self, object, transaction):
if object is self:
+ if self._begun is None:
+ self._storage.tpc_begin(transaction)
+ self._begun = 1
+
# We registered ourself. Execute a commit action, if any.
if self.__onCommitActions is not None:
method_name, args, kw = self.__onCommitActions.pop(0)
apply(getattr(self, method_name), (transaction,) + args, kw)
return
- oid=object._p_oid
- invalid=self._invalid
+
+ oid = object._p_oid
+ invalid = self._invalid
if oid is None or object._p_jar is not self:
# new object
oid = self.new_oid()
- object._p_jar=self
- object._p_oid=oid
+ object._p_jar = self
+ object._p_oid = oid
self._creating.append(oid)
elif object._p_changed:
- if (
- (invalid(oid) and not hasattr(object, '_p_resolveConflict'))
- or
- invalid(None)
- ):
+ if invalid(oid) and not hasattr(object, '_p_resolveConflict'):
raise ConflictError(object=object)
self._invalidating.append(oid)
@@ -297,7 +313,11 @@
# Nothing to do
return
- stack=[object]
+ if self._begun is None:
+ self._storage.tpc_begin(transaction)
+ self._begun = 1
+
+ stack = [object]
# Create a special persistent_id that passes T and the subobject
# stack along:
@@ -351,12 +371,7 @@
self._creating.append(oid)
else:
#XXX We should never get here
- if (
- (invalid(oid) and
- not hasattr(object, '_p_resolveConflict'))
- or
- invalid(None)
- ):
+ if invalid(oid) and not hasattr(object, '_p_resolveConflict'):
raise ConflictError(object=object)
self._invalidating.append(oid)
@@ -517,8 +532,7 @@
# storage to make sure that we don't miss an invaildation
# notifications between the time we check and the time we
# read.
- invalid = self._invalid
- if invalid(oid) or invalid(None):
+ if self._invalid(oid):
if not hasattr(object.__class__, '_p_independent'):
get_transaction().register(self)
raise ReadConflictError(object=object)
@@ -602,33 +616,33 @@
if self.__onCommitActions is not None:
del self.__onCommitActions
self._storage.tpc_abort(transaction)
- cache=self._cache
- cache.invalidate(self._invalidated)
- cache.invalidate(self._invalidating)
+ self._cache.invalidate(self._invalidated)
+ self._cache.invalidate(self._invalidating)
self._invalidate_creating()
def tpc_begin(self, transaction, sub=None):
- if self._invalid(None): # Some nitwit invalidated everything!
- raise ConflictError("transaction already invalidated")
- self._invalidating=[]
- self._creating=[]
+ self._invalidating = []
+ self._creating = []
+ self._begun = None
if sub:
# Sub-transaction!
- _tmp=self._tmp
- if _tmp is None:
- _tmp=TmpStore.TmpStore(self._version)
- self._tmp=self._storage
- self._storage=_tmp
+ if self._tmp is None:
+ _tmp = TmpStore.TmpStore(self._version)
+ self._tmp = self._storage
+ self._storage = _tmp
_tmp.registerDB(self._db, 0)
- self._storage.tpc_begin(transaction)
+ # It's okay to always call tpc_begin() for a sub-transaction
+ # because this isn't the real storage.
+ self._storage.tpc_begin(transaction)
+ self._begun = 1
def tpc_vote(self, transaction):
if self.__onCommitActions is not None:
del self.__onCommitActions
try:
- vote=self._storage.tpc_vote
+ vote = self._storage.tpc_vote
except AttributeError:
return
s = vote(transaction)
=== Zope/lib/python/ZODB/POSException.py 1.12.4.3 => 1.12.4.4 ===
--- Zope/lib/python/ZODB/POSException.py:1.12.4.3 Tue Sep 3 03:43:47 2002
+++ Zope/lib/python/ZODB/POSException.py Tue Sep 10 23:36:38 2002
@@ -104,6 +104,24 @@
def get_serials(self):
return self.serials
+class DanglingReferenceError(TransactionError):
+ """The transaction stored an object A containing a reference to another
+ object B, but B does not exist
+
+ Instance attributes:
+
+ Aoid: oid of the object being written
+
+ Boid: referenced oid that does not have a corresponding object
+ """
+
+ def __init__(self,Aoid,Boid):
+ self.Aoid = Aoid
+ self.Boid = Boid
+
+ def __str__(self):
+ return "from %r to %r" % (self.Aoid,self.Boid)
+
class ReadConflictError(ConflictError):
"""A conflict was detected at read time.