[Zope3-checkins] CVS: Zope3/src/zodb/storage/file - format.py:1.1.2.4

Jeremy Hylton jeremy@zope.com
Mon, 21 Apr 2003 15:11:14 -0400


Update of /cvs-repository/Zope3/src/zodb/storage/file
In directory cvs.zope.org:/tmp/cvs-serv3271

Modified Files:
      Tag: jeremy-new-pack-branch
	format.py 
Log Message:
Add consistency checking routines.


=== Zope3/src/zodb/storage/file/format.py 1.1.2.3 => 1.1.2.4 ===
--- Zope3/src/zodb/storage/file/format.py:1.1.2.3	Fri Apr 18 12:13:13 2003
+++ Zope3/src/zodb/storage/file/format.py	Mon Apr 21 15:11:13 2003
@@ -123,9 +123,10 @@
 import logging
 import struct
 
-from zodb.interfaces import ZERO, MAXTID, POSKeyError
+from zodb.interfaces import ZERO, MAXTID, POSKeyError, _fmt_oid
 from zodb.utils import u64, p64
 from zodb.storage.base import splitrefs
+from zodb.storage.file.errors import CorruptedError
 
 # the struct formats for the headers
 TRANS_HDR = ">8sQcHHH"
@@ -440,6 +441,40 @@
         # seek to transaction header, where tid is first 8 bytes
         return self._file.read(8)
 
+    def fail(self, pos, msg, *args):
+        s = ("%s:%s:" + msg) % ((self._name, pos) + args)
+        logger.error(s)
+        raise CorruptedError(s)
+
+    def checkTxn(self, th, pos):
+        if th.tid <= self.ltid:
+            self.fail(pos, "time-stamp reduction: %s <= %s",
+                      _fmt_oid(th.tid), _fmt_oid(self.ltid))
+        self.ltid = th.tid
+        if th.status == "c":
+            self.fail(pos, "transaction with checkpoint flag set")
+        if not (th.status == " " or th.status == "p"):
+            self.fail(pos, "invalid transaction status: %r", th.status)
+        if th.tlen < th.headerlen():
+            self.fail(pos, "invalid transaction header: "
+                      "txnlen (%d) < headerlen(%d)", th.tlen, th.headerlen())
+
+    def checkData(self, th, tpos, dh, pos):
+        tend = tpos + th.tlen
+        if dh.tloc != tpos:
+            self.fail(pos, "data record does not point to transaction header"
+                      ": %d != %d", dh.tloc, tpos)
+        if pos + dh.recordlen() > tpos + th.tlen:
+            self.fail(pos, "data record size exceeds transaction size: "
+                      "%d > %d", pos + dh.recordlen(), tpos + th.tlen)
+        if dh.prev >= pos:
+            self.fail(pos, "invalid previous pointer: %d", dh.prev)
+        if dh.back:
+            if dh.back >= pos:
+                self.fail(pos, "invalid back pointer: %d", dh.prev)
+            if dh.nrefs or dh.plen:
+                self.fail(pos, "data record has back pointer and data")
+            
 class DataHeader:
     """Header for a data record."""