[Zope-CVS] CVS: Products/AdaptableStorage/zodb - ASConnection.py:1.22 ASStorage.py:1.11 consts.py:1.6

Shane Hathaway shane@zope.com
Sat, 1 Mar 2003 10:23:42 -0500


Update of /cvs-repository/Products/AdaptableStorage/zodb
In directory cvs.zope.org:/tmp/cvs-serv19690/zodb

Modified Files:
	ASConnection.py ASStorage.py consts.py 
Log Message:
Renamed the 'serial' concept to 'hash' because it's easier to explain in
documentation.  Also expanded ILoadEvent so that gateways can return the
hash without loading the entire object.


=== Products/AdaptableStorage/zodb/ASConnection.py 1.21 => 1.22 ===
--- Products/AdaptableStorage/zodb/ASConnection.py:1.21	Fri Feb 21 12:16:50 2003
+++ Products/AdaptableStorage/zodb/ASConnection.py	Sat Mar  1 10:23:42 2003
@@ -25,11 +25,12 @@
 from Acquisition import aq_base
 from ZODB import Persistent
 from ZODB.POSException \
-     import ConflictError, ReadConflictError, InvalidObjectReference
+     import ConflictError, ReadConflictError, InvalidObjectReference, \
+     StorageError
 from ZODB.Connection import Connection
 from zLOG import LOG, ERROR
 
-from consts import SERIAL0, DEBUG
+from consts import HASH0, DEBUG
 from mapper_public import IKeyedObjectSystem, SerializationEvent, \
      DeserializationEvent
 
@@ -249,7 +250,7 @@
             if ext_refs:
                 for (ext_keychain, ext_ref) in ext_refs:
                     if (not ext_ref._p_serial
-                        or ext_ref._p_serial == SERIAL0):
+                        or ext_ref._p_serial == HASH0):
                         ext_oid = oid_encoder.encode(ext_keychain)
                         if ext_ref._p_jar:
                             if ext_ref._p_jar != self:
@@ -433,6 +434,22 @@
 
     def classFactory(self, module, name):
         return self._db._classFactory(self, module, name)
+
+
+    def checkSerials(self):
+        """Verifies that all cached objects are in sync with the data.
+
+        This is useful for finding gateways that generate inconsistent
+        hashes.
+        """
+        for oid, ob in self._cache.items():
+            if ob._p_changed is not None:
+                p, serial = self._storage.load(oid, self._version)
+                if serial != ob._p_serial:
+                    keychain = self._db._oid_encoder.decode(oid)
+                    raise StorageError(
+                        "Inconsistent hash for keychain %s" % repr(keychain))
+    
 
     def exportFile(self, oid, file=None):
         raise NotImplementedError, 'ZEXP Export not implemented'


=== Products/AdaptableStorage/zodb/ASStorage.py 1.10 => 1.11 ===
--- Products/AdaptableStorage/zodb/ASStorage.py:1.10	Thu Jan  9 09:34:08 2003
+++ Products/AdaptableStorage/zodb/ASStorage.py	Sat Mar  1 10:23:42 2003
@@ -25,7 +25,7 @@
      import MapperEvent, LoadEvent, StoreEvent, \
      ITPCConnection, NoStateFoundError
 
-from consts import SERIAL0, SERIAL1, DEBUG
+from consts import HASH0, HASH1, DEBUG
 from OIDEncoder import OIDEncoder
 from interfaces.public import IResourceAccess, IOIDEncoder
 
@@ -75,15 +75,18 @@
     def getMapperResource(self):
         return self._mapper_resource
 
-    def hashSerial(self, serial):
-        """Returns an 8-byte checksum.
+    def hash64(self, value):
+        """Returns an 8-byte hash value.
         """
-        h = '%08x' % hash(serial)
+        h = '%08x' % hash(value)
+        if h == HASH0:
+            # Avoid the special zero hash.
+            h = HASH1
         if DEBUG:
-            print 'hash of %r is %r' % (serial, h)
+            print '64-bit hash of %r is %r' % (value, h)
         return h
 
-    def _load(self, root_mapper, keychain):
+    def _load(self, root_mapper, keychain, hash_only=0):
         mapper = root_mapper
         mapper_names = []
         # Follow the keychain to find the right mapper.
@@ -97,8 +100,10 @@
             mapper_names.append(sub_mapper_name)
             mapper = mapper.getSubMapper(sub_mapper_name)
         event = LoadEvent(mapper, keychain)
-        full_state, serial = mapper.getGateway().load(event)
-        return full_state, serial, classification, mapper_names
+        if hash_only:
+            event.hash_only = 1
+        full_state, hash_value = mapper.getGateway().load(event)
+        return full_state, hash_value, classification, mapper_names
 
 
     def load(self, oid, version):
@@ -108,21 +113,21 @@
         try:
             keychain = self._oid_encoder.decode(oid)
             root_mapper = self._mapper_resource.access(self)
-            full_state, serial, classification, mapper_names = self._load(
+            full_state, hash_value, classification, mapper_names = self._load(
                 root_mapper, keychain)
             file = StringIO()
             p = Pickler(file)
             p.dump((classification, mapper_names))
             p.dump(full_state)
             data = file.getvalue()
-            h = self.hashSerial(serial)
+            h = self.hash64(hash_value)
             if DEBUG:
                 print 'loaded', `oid`, `h`
             return data, h
         finally:
             self._lock_release()
 
-    def store(self, oid, serial_hash, data, version, transaction):
+    def store(self, oid, h64, data, version, transaction):
         if transaction is not self._transaction:
             raise POSException.StorageTransactionError(self, transaction)
 
@@ -135,32 +140,32 @@
             keychain = self._oid_encoder.decode(oid)
 
             # First detect conflicts.
-            # The "serial" argument, if its value is not 0,
-            # was previously generated by hashSerial().
+            # The "h64" argument, if its value is not 0,
+            # was previously generated by hash64().
             if DEBUG:
-                print 'storing', `oid`, `serial_hash`
-            if serial_hash != SERIAL0:
-                # Overwriting an old object.  Use the serial to verify
+                print 'storing', `oid`, `h64`
+            if h64 != HASH0:
+                # Overwriting an old object.  Use the hash to verify
                 # that the new data was derived from the old data.
-                info = self._load(root_mapper, keychain)
-                old_state, old_serial = info[:2]
-                old_serial_hash = self.hashSerial(old_serial)
-                if serial_hash != old_serial_hash:
+                info = self._load(root_mapper, keychain, 1)
+                old_state, old_hash = info[:2]
+                old_h64 = self.hash64(old_hash)
+                if h64 != old_h64:
                     raise POSException.ConflictError(
                         "Storing %s based on old data. %s != %s" % (
                         repr(keychain),
-                        repr(serial_hash), repr(old_serial_hash)))
+                        repr(h64), repr(old_h64)))
             else:
                 # A new object.  Attempts to load should lead to
-                # NoStateFoundError or a serial of None, otherwise
+                # NoStateFoundError or a hash of None, otherwise
                 # there's a conflict.
                 try:
-                    info = self._load(root_mapper, keychain)
+                    info = self._load(root_mapper, keychain, 1)
                 except NoStateFoundError:
                     pass
                 else:
-                    old_serial = info[1]
-                    if old_serial is not None:
+                    old_hash = info[1]
+                    if old_hash is not None:
                         raise POSException.ConflictError(
                             "%s already exists" % repr(keychain))
 
@@ -176,16 +181,16 @@
                 cfr = mapper.getClassifier()
                 mapper = mapper.getSubMapper(mapper_name)
             event = StoreEvent(mapper, keychain)
-            new_serial = mapper.getGateway().store(event, state)
+            new_hash = mapper.getGateway().store(event, state)
             if cfr is not None:
                 cfr.store(event, classification)
-            new_hash = self.hashSerial(new_serial)
+            new_h64 = self.hash64(new_hash)
         finally:
             self._lock_release()
 
         if DEBUG:
-            print 'stored', `oid`, `serial_hash`, `new_hash`
-        return new_hash
+            print 'stored', `oid`, `h64`, `new_h64`
+        return new_h64
 
     def new_oid(self):
         # Try to use the root keychain generator to make a keychain.


=== Products/AdaptableStorage/zodb/consts.py 1.5 => 1.6 ===
--- Products/AdaptableStorage/zodb/consts.py:1.5	Tue Jan 14 12:47:09 2003
+++ Products/AdaptableStorage/zodb/consts.py	Sat Mar  1 10:23:42 2003
@@ -18,8 +18,11 @@
 
 import os
 
-DEBUG = not not os.environ.get('ZODB_MAPPER_DEBUG')
+if os.environ.get('ZODB_MAPPER_DEBUG'):
+    DEBUG = 1
+else:
+    DEBUG = 0
 
-SERIAL0 = '\0' * 8
-SERIAL1 = '\0' * 7 + '\001'
 ROOT_OID = '\0' * 8
+HASH0 = '\0' * 8
+HASH1 = '\0' * 7 + '\001'