[Zope3-checkins] CVS: ZODB4/ZODB - FileStorage.py:1.110.6.2

Jeremy Hylton jeremy@zope.com
Tue, 10 Dec 2002 17:04:31 -0500


Update of /cvs-repository/ZODB4/ZODB
In directory cvs.zope.org:/tmp/cvs-serv23438/ZODB

Modified Files:
      Tag: ZODB4-Q-branch
	FileStorage.py 
Log Message:
Another checkpoint in the Q saga.

Try to sanitize CorruptedDataError.  Define ctor with explicit oid and
buf arguments.

Add FileStorageFormatter class that should eventually collect all the
functionality for reading and writing the low-level file format,
including backpointers.

Start converting FileStorage to use FileStorageFormatter.  Currently
there are several pack errors and a couple of recover errors.



=== ZODB4/ZODB/FileStorage.py 1.110.6.1 => 1.110.6.2 === (482/582 lines abridged)
--- ZODB4/ZODB/FileStorage.py:1.110.6.1	Fri Dec  6 18:58:01 2002
+++ ZODB4/ZODB/FileStorage.py	Tue Dec 10 17:04:30 2002
@@ -198,7 +198,16 @@
     pass
 
 class CorruptedDataError(CorruptedFileStorageError):
-    pass
+
+    def __init__(self, oid=None, buf=None):
+        self.oid = oid
+        self.buf = buf
+
+    def __str__(self):
+        if self.oid:
+            return "Error reading oid %016x.  Found %r" % (self.oid, self.buf)
+        else:
+            return "Error reading unknown oid.  Found %r" % self.buf
 
 class FileStorageQuotaError(FileStorageError,
                             POSException.StorageSystemError):
@@ -211,7 +220,81 @@
     db = ZODB.DB.DB(fs, pool_size, cache_size)
     return db
 
+class FileStorageFormatter:
+    """Mixin class that can read and write the low-level format."""
+
+    # subclasses must provide _file
+    def _read_data_header(self, pos, oid=None):
+        self._file.seek(pos)
+        s = self._file.read(DATA_HDR_LEN)
+        if len(s) != DATA_HDR_LEN:
+            raise CorruptedDataError(oid, s)
+        h = DataHeader.fromString(s)
+        if oid is not None and oid != h.oid:
+            raise CorruptedDataError(oid, s)
+        if h.vlen:
+            s = self._file.read(16 + h.vlen)
+            h.parseVersion(s)
+        if not h.plen:
+            h.back = u64(self._file.read(8))
+        return h
+
+    def _write_data_header(self, file, oid, serial, prev, tloc, vlen, plen):
+        s = struct.pack(DATA_HDR, oid, serial, prev, tloc, vlen, plen)
+        file.write(s)
+
+    def _write_version_header(self, file, pnv, vprev, version):
+        s = struct.pack(">QQ", pnv, vprev)
+        file.write(s + version)

[-=- -=- -=- 482 lines omitted -=- -=- -=-]

             else:
-                bp = self._file.read(8)
-                if bp == z64:
-                    # If the backpointer is 0 (encoded as z64), then
-                    # this transaction undoes the object creation.  It
-                    # either aborts the version that created the
-                    # object or undid the transaction that created it.
-                    # Return None instead of a pickle to indicate
-                    # this.
+                print h.back
+                if not h.back:
+                    # If the backpointer is 0, then this transaction
+                    # undoes the object creation.  It either aborts
+                    # the version that created the object or undid the
+                    # transaction that created it.  Return None
+                    # instead of a pickle to indicate this.
                     data = None
                 else:
-                    data, _s, tid = _loadBackTxn(self._file, oid, bp)
-                    prev_txn = getTxnFromData(self._file, oid, bp)
+                    data, _s, tid = self._loadBackTxn(h.oid, h.back)
+                    prev_txn = self.getTxnFromData(h.oid, h.back)
 
-            r = Record(oid, serial, version, data, prev_txn)
+            r = Record(h.oid, h.serial, h.version, data, prev_txn)
 
             return r
 
@@ -2467,7 +2431,12 @@
 class DataHeader:
     """Header for a data record."""
 
-    __slots__ = "oid", "serial", "prev", "tloc", "vlen", "plen"
+    __slots__ = ("oid", "serial", "prev", "tloc", "vlen", "plen", "back",
+                 # These three attributes are only defined when vlen > 0
+                 "pnv", "vprev", "version")
+
+    version = ""
+    back = 0
 
     def __init__(self, oid, serial, prev, tloc, vlen, plen):
         self.oid = oid
@@ -2481,3 +2450,7 @@
         return cls(*struct.unpack(DATA_HDR, s))
         
     fromString = classmethod(fromString)
+
+    def parseVersion(self, buf):
+        self.pnv, self.vprev = struct.unpack(">QQ", buf[:16])
+        self.version = buf[16:]