[Zodb-checkins] CVS: ZODB3/ZODB - utils.py:1.14 POSException.py:1.15 FileStorage.py:1.119 Connection.py:1.80 ConflictResolution.py:1.17

Jeremy Hylton jeremy@zope.com
Tue, 3 Dec 2002 13:36:30 -0500


Update of /cvs-repository/ZODB3/ZODB
In directory cvs.zope.org:/tmp/cvs-serv21022/ZODB

Modified Files:
	utils.py POSException.py FileStorage.py Connection.py 
	ConflictResolution.py 
Log Message:
Finish synchronizing FileStorage and POSException between ZODB3 and ZODB4.

There are few differences between the two files, except for necessary
differences because of API changes.  This change involves backporting
the new UndoError style from ZODB4.



=== ZODB3/ZODB/utils.py 1.13 => 1.14 ===
--- ZODB3/ZODB/utils.py:1.13	Tue Nov  5 16:50:50 2002
+++ ZODB3/ZODB/utils.py	Tue Dec  3 13:36:29 2002
@@ -17,6 +17,8 @@
 
 from struct import pack, unpack
 
+z64 = '\0'*8
+
 if sys.version >= (2, 2):
 
     # Note that the distinction between ints and longs is blurred in


=== ZODB3/ZODB/POSException.py 1.14 => 1.15 ===
--- ZODB3/ZODB/POSException.py:1.14	Thu Sep  5 06:19:40 2002
+++ ZODB3/ZODB/POSException.py	Tue Dec  3 13:36:29 2002
@@ -11,23 +11,28 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""BoboPOS-defined exceptions
+"""ZODB-defined exceptions
 
 $Id$"""
-__version__ = '$Revision$'.split()[-2:][0]
 
-from string import join
 from types import StringType, DictType
-from ZODB import utils
+import ZODB.utils
 
-class POSError(Exception):
+def _fmt_oid(oid):
+    return "%016x" % ZODB.utils.u64(oid)
+
+def _fmt_undo(oid, reason):
+    s = reason and (": %s" % reason) or ""
+    return "Undo error %s%s" % (_fmt_oid(oid), s)
+
+class POSError(StandardError):
     """Persistent object system error."""
 
 class POSKeyError(KeyError, POSError):
     """Key not found in database."""
 
     def __str__(self):
-        return "%016x" % utils.U64(self.args[0])
+        return _fmt_oid(self.args[0])
 
 class TransactionError(POSError):
     """An error occured due to normal transaction processing."""
@@ -78,12 +83,12 @@
     def __str__(self):
         extras = []
         if self.oid:
-            extras.append("oid %016x" % utils.U64(self.oid))
+            extras.append("oid %s" % _fmt_oid(self.oid))
         if self.class_name:
             extras.append("class %s" % self.class_name)
         if self.serials:
-            extras.append("serial was %016x, now %016x" %
-                          tuple(map(utils.U64, self.serials)))
+            extras.append("serial was %s, now %s" %
+                          tuple(map(_fmt_oid, self.serials)))
         if extras:
             return "%s (%s)" % (self.message, ", ".join(extras))
         else:
@@ -104,27 +109,8 @@
     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.
+    """Conflict detected when object was loaded.
 
     An attempt was made to read an object that has changed in another
     transaction (eg. another thread or process).
@@ -144,6 +130,27 @@
         ConflictError.__init__(self, message="BTrees conflict error")
         self.btree = btree_args
 
+class DanglingReferenceError(TransactionError):
+    """An object has a persistent reference to a missing object.
+
+    If an object is stored and it has a reference to another object
+    that does not exist (for example, it was deleted by pack), this
+    exception may be raised.  Whether a storage supports this feature,
+    it a quality of implementation issue.
+
+    Instance attributes:
+    referer: oid of the object being written
+    missing: referenced oid that does not have a corresponding object
+    """
+
+    def __init__(self, Aoid, Boid):
+        self.referer = Aoid
+        self.missing = Boid
+
+    def __str__(self):
+        return "from %s to %s" % (_fmt_oid(self.referer),
+                                  _fmt_oid(self.missing))
+
 class VersionError(POSError):
     """An error in handling versions occurred."""
 
@@ -159,26 +166,24 @@
 
 class UndoError(POSError):
     """An attempt was made to undo a non-undoable transaction."""
-    def __init__(self, *reason):
-        if len(reason) == 1: reason=reason[0]
-        self.__reason=reason
-
-    def __repr__(self):
-        reason=self.__reason
-        if type(reason) is not DictType:
-            if reason: return str(reason)
-            return "non-undoable transaction"
-        r=[]
-        for oid, reason in reason.items():
-            if reason:
-                r.append("Couldn't undo change to %s because %s"
-                         % (`oid`, reason))
-            else:
-                r.append("Couldn't undo change to %s" % (`oid`))
 
-        return join(r,'\n')
+    def __init__(self, oid, reason=None):
+        self._oid = oid
+        self._reason = reason
+
+    def __str__(self):
+        return _fmt_undo(self._oid, self._reason)
+
+class MultipleUndoErrors(UndoError):
+    """Several undo errors occured during a single transaction."""
+    
+    def __init__(self, errs):
+        # provide an oid and reason for clients that only look at that
+        UndoError.__init__(self, *errs[0])
+        self._errs = errs
 
-    __str__=__repr__
+    def __str__(self):
+        return "\n".join([_fmt_undo(*pair) for pair in self._errs])
 
 class StorageError(POSError):
     """Base class for storage based exceptions."""
@@ -200,9 +205,6 @@
 
 class ExportError(POSError):
     """An export file doesn't have the right format."""
-
-class Unimplemented(POSError):
-    """An unimplemented feature was used."""
 
 class Unsupported(POSError):
     """An feature that is unsupported bt the storage was used."""


=== ZODB3/ZODB/FileStorage.py 1.118 => 1.119 === (575/675 lines abridged)
--- ZODB3/ZODB/FileStorage.py:1.118	Mon Dec  2 17:45:49 2002
+++ ZODB3/ZODB/FileStorage.py	Tue Dec  3 13:36:29 2002
@@ -133,10 +133,10 @@
     fsync = None
 
 from ZODB import BaseStorage, ConflictResolution, POSException
-from ZODB.POSException import UndoError, POSKeyError
+from ZODB.POSException import UndoError, POSKeyError, MultipleUndoErrors
 from ZODB.TimeStamp import TimeStamp
 from ZODB.lock_file import lock_file
-from ZODB.utils import t32, p64, U64, cp
+from ZODB.utils import p64, u64, cp, z64
 
 try:
     from ZODB.fsIndex import fsIndex
@@ -144,9 +144,9 @@
     def fsIndex():
         return {}
 
-from zLOG import LOG, BLATHER, WARNING, ERROR, PANIC, register_subsystem
+from zLOG import LOG, BLATHER, WARNING, ERROR, PANIC
 
-z64='\0'*8
+t32 = 1L << 32
 # the struct formats for the headers
 TRANS_HDR = ">8s8scHHH"
 DATA_HDR = ">8s8s8s8sH8s"
@@ -173,7 +173,7 @@
 def panic(message, *data):
     message = message % data
     LOG('ZODB FS', PANIC, "%s ERROR: %s\n" % (packed_version, message))
-    raise CorruptedTransactionError, message
+    raise CorruptedTransactionError(message)
 
 class FileStorageError(POSException.StorageError):
     pass
@@ -191,8 +191,11 @@
                                 POSException.StorageSystemError):
     """Corrupted file storage."""
 
-class CorruptedTransactionError(CorruptedFileStorageError): pass
-class CorruptedDataError(CorruptedFileStorageError): pass
+class CorruptedTransactionError(CorruptedFileStorageError):
+    pass
+
+class CorruptedDataError(CorruptedFileStorageError):
+    pass
 
 class FileStorageQuotaError(FileStorageError,
                             POSException.StorageSystemError):

[-=- -=- -=- 575 lines omitted -=- -=- -=-]

                 # Hm, the data were truncated or the checkpoint flag wasn't
@@ -2288,7 +2291,7 @@
                 # the end and read what should be the transaction
                 # length of the last transaction.
                 seek(-8, 2)
-                rtl=U64(read(8))
+                rtl=u64(read(8))
                 # Now check to see if the redundant transaction length is
                 # reasonable:
                 if self._file_size - rtl < pos or rtl < TRANS_HDR_LEN:
@@ -2346,8 +2349,8 @@
         raise IndexError, index
 
 class RecordIterator(Iterator, BaseStorage.TransactionRecord):
-    """Iterate over the transactions in a FileStorage file.
-    """
+    """Iterate over the transactions in a FileStorage file."""
+    
     def __init__(self, tid, status, user, desc, ext, pos, tend, file, tpos):
         self.tid = tid
         self.status = status
@@ -2366,15 +2369,15 @@
             self._file.seek(pos)
             h = self._file.read(DATA_HDR_LEN)
             oid, serial, sprev, stloc, vlen, splen = unpack(DATA_HDR, h)
-            prev = U64(sprev)
-            tloc = U64(stloc)
-            plen = U64(splen)
+            prev = u64(sprev)
+            tloc = u64(stloc)
+            plen = u64(splen)
             dlen = DATA_HDR_LEN + (plen or 8)
 
             if vlen:
                 dlen += (16 + vlen)
                 tmp = self._file.read(16)
-                pv = U64(tmp[8:16])
+                pv = u64(tmp[8:16])
                 version = self._file.read(vlen)
             else:
                 version = ''
@@ -2447,7 +2450,7 @@
     def _readnext(self):
         """Read the next record from the storage."""
         self.file.seek(self.pos - 8)
-        self.pos -= U64(self.file.read(8)) + 8
+        self.pos -= u64(self.file.read(8)) + 8
         self.file.seek(self.pos)
         h = self.file.read(TRANS_HDR_LEN)
         tid, tl, status, ul, dl, el = struct.unpack(TRANS_HDR, h)


=== ZODB3/ZODB/Connection.py 1.79 => 1.80 ===
--- ZODB3/ZODB/Connection.py:1.79	Mon Nov 18 18:17:40 2002
+++ ZODB3/ZODB/Connection.py	Tue Dec  3 13:36:29 2002
@@ -40,7 +40,7 @@
     global global_code_timestamp
     global_code_timestamp = time()
 
-ExtensionKlass=Base.__class__
+ExtensionKlass = Base.__class__
 
 class Connection(ExportImport.ExportImport):
     """Object managers for individual object space.


=== ZODB3/ZODB/ConflictResolution.py 1.16 => 1.17 ===
--- ZODB3/ZODB/ConflictResolution.py:1.16	Mon Nov 18 18:17:40 2002
+++ ZODB3/ZODB/ConflictResolution.py	Tue Dec  3 13:36:29 2002
@@ -92,7 +92,7 @@
         unpickler.persistent_load = prfactory.persistent_load
         class_tuple = unpickler.load()[0]
         if bad_class(class_tuple):
-            return 0
+            return None
         newstate = unpickler.load()
         klass = load_class(class_tuple)
         inst = klass.__basicnew__()
@@ -101,7 +101,7 @@
             resolve = inst._p_resolveConflict
         except AttributeError:
             bad_classes[class_tuple] = 1
-            return 0
+            return None
 
         old = state(self, oid, oldSerial, prfactory)
         committed = state(self, oid, committedSerial, prfactory, committedData)
@@ -115,7 +115,7 @@
         pickler.dump(resolved)
         return file.getvalue(1)
     except ConflictError:
-        return 0
+        return None
     except:
         # If anything else went wrong, catch it here and avoid passing an
         # arbitrary exception back to the client.  The error here will mask
@@ -124,7 +124,7 @@
         # the error so that any problems can be fixed.
         zLOG.LOG("Conflict Resolution", zLOG.ERROR,
                  "Unexpected error", error=sys.exc_info())
-        return 0
+        return None
 
 class ConflictResolvingStorage:
     "Mix-in class that provides conflict resolution handling for storages"