[Checkins] SVN: gocept.zeoraid/trunk/ - Fix another recovery issue by using the correct previous Tid of a data

Christian Theune ct at gocept.com
Thu Jul 2 13:08:31 EDT 2009


Log message for revision 101400:
  - Fix another recovery issue by using the correct previous Tid of a data
    record.
  
    Improve logging during recovery.
  
  - Show current recovery process in the management `details` command.
  
  - Fix recipe test to not mention the removed ZODB external anymore.
  
  - Don't require the ZEO configuration file to be named again, determine
    automatically.
  

Changed:
  U   gocept.zeoraid/trunk/CHANGES.txt
  U   gocept.zeoraid/trunk/setup.py
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/recovery.py
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/controller.py
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/recipe.txt
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/stresstest.py
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_recovery.py

-=-
Modified: gocept.zeoraid/trunk/CHANGES.txt
===================================================================
--- gocept.zeoraid/trunk/CHANGES.txt	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/CHANGES.txt	2009-07-02 17:08:31 UTC (rev 101400)
@@ -2,6 +2,21 @@
 Change History
 ==============
 
+1.0b3 (unreleased)
+------------------
+
+- Fix another recovery issue by using the correct previous Tid of a data
+  record.
+
+  Improve logging during recovery.
+
+- Show current recovery process in the management `details` command.
+
+- Fix recipe test to not mention the removed ZODB external anymore.
+
+- Don't require the ZEO configuration file to be named again, determine
+  automatically.
+
 1.0b2 (2009-07-02)
 ------------------
 

Modified: gocept.zeoraid/trunk/setup.py
===================================================================
--- gocept.zeoraid/trunk/setup.py	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/setup.py	2009-07-02 17:08:31 UTC (rev 101400)
@@ -19,7 +19,7 @@
 name = "gocept.zeoraid"
 setup(
     name = name,
-    version = "1.0b2dev",
+    version = "1.0b3dev",
     author = "Christian Theune",
     author_email = "ct at gocept.com",
     description = "A ZODB storage for replication using RAID techniques.",

Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/recovery.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/recovery.py	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/recovery.py	2009-07-02 17:08:31 UTC (rev 101400)
@@ -13,6 +13,7 @@
 ##############################################################################
 """Online storage recovery."""
 
+import logging
 import tempfile
 
 import transaction
@@ -21,7 +22,9 @@
 
 import gocept.zeoraid.storage
 
+logger = logging.getLogger('gocept.zeoraid.recovery')
 
+
 def continuous_storage_iterator(storage):
     seen = ZODB.utils.z64
     while seen < storage.lastTransaction():
@@ -94,7 +97,7 @@
                         'in source transaction %r.' % (
                         name, source_value, target_value, source_txn.tid))
 
-            yield ('verify', source_txn.tid)
+            yield ('verify', ZODB.utils.tid_repr(source_txn.tid))
 
         yield ('verified',)
 
@@ -115,9 +118,17 @@
             finally:
                 self.source.tpc_abort(t)
 
+            logger.debug('Recovering transaction %s' %
+                    ZODB.utils.tid_repr(txn_info.tid))
             self.target.tpc_begin(txn_info, txn_info.tid, txn_info.status)
 
             for r in txn_info:
+                before = self.source.loadBefore(r.oid, txn_info.tid)
+                if before is not None:
+                    _, prev_tid, _ = before
+                else:
+                    prev_tid = None
+
                 if self.recover_blobs:
                     try:
                         blob_file_name = self.source.loadBlob(
@@ -130,11 +141,14 @@
                         gocept.zeoraid.storage.optimistic_copy(blob_file_name,
                                                                temp_file_name)
                         self.target.storeBlob(
-                            r.oid, r.tid, r.data, temp_file_name, r.version,
+                            r.oid, prev_tid, r.data, temp_file_name, r.version,
                             txn_info)
                         continue
-                self.target.store(r.oid, r.tid, r.data, r.version, txn_info)
 
+                # XXX Charlie Clark has a database that conflicts so we need
+                # to reconsider using store here.
+                self.target.store(r.oid, prev_tid, r.data, r.version, txn_info)
+
             self.target.tpc_vote(txn_info)
             self.target.tpc_finish(txn_info)
 

Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/controller.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/controller.py	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/controller.py	2009-07-02 17:08:31 UTC (rev 101400)
@@ -33,7 +33,7 @@
 
     disable <storage> -- Disable a storage
 
-    reload </path/to/zeo.conf> -- Reload a specified zeo.conf file
+    reload -- Reload this raid storage's configuration from the zeo.conf
 
 """
 
@@ -59,12 +59,12 @@
         print self.raid.raid_status()
 
     def cmd_details(self):
-        ok, recovering, failed = self.raid.raid_details()
+        ok, recovering, failed, recovery_status = self.raid.raid_details()
         print "RAID status:"
         print "\t", self.raid.raid_status()
         print "Storage status:"
         print "\toptimal\t\t", ok
-        print "\trecovering\t", recovering
+        print "\trecovering\t", recovering, recovery_status
         print "\tfailed\t\t", failed
 
     def cmd_recover(self, storage):
@@ -73,8 +73,8 @@
     def cmd_disable(self, storage):
         print self.raid.raid_disable(storage)
 
-    def cmd_reload(self, path):
-        print self.raid.raid_reload(path)
+    def cmd_reload(self):
+        self.raid.raid_reload()
 
 def main(host="127.0.0.1", port=8100, storage="1"):
     usage = "usage: %prog [options] command [command-options]"

Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/recipe.txt
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/recipe.txt	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/recipe.txt	2009-07-02 17:08:31 UTC (rev 101400)
@@ -112,7 +112,6 @@
     import sys
     sys.path[0:0] = [
       '.../src',
-      '.../externals/ZODB/src',
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
@@ -125,6 +124,7 @@
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
+      '/sample-pyN.N.egg',
       ]
     <BLANKLINE>
     import gocept.zeoraid.scripts.controller
@@ -210,7 +210,6 @@
     import sys
     sys.path[0:0] = [
       '.../src',
-      '.../externals/ZODB/src',
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
@@ -223,6 +222,7 @@
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
       '/sample-pyN.N.egg',
+      '/sample-pyN.N.egg',
       ]
     <BLANKLINE>
     import gocept.zeoraid.scripts.controller

Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/stresstest.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/stresstest.py	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/scripts/stresstest.py	2009-07-02 17:08:31 UTC (rev 101400)
@@ -6,10 +6,13 @@
 import ZEO.zrpc.error
 import ZEO.Exceptions
 import ZODB.utils
+import logging
+logging.getLogger().addHandler(logging.StreamHandler())
+logging.getLogger().setLevel(0)
 
 
-storage = ClientStorage([('127.0.0.1', 8100)],#, ('127.0.0.1', 8201)],
-                        storage='1')
+storage = ClientStorage([('127.0.0.1', 8200), ('127.0.0.1', 8201)],
+                        storage='main')
 db = DB(storage)
 conn = db.open()
 root = conn.root()
@@ -26,5 +29,4 @@
         transaction.abort()
         continue
     print root['x']
-    print ZODB.utils.oid_repr(storage.lastTransaction())
     time.sleep(1)

Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py	2009-07-02 17:08:31 UTC (rev 101400)
@@ -173,6 +173,7 @@
 
         # No storage is recovering initially
         self.storage_recovering = None
+        self.recovery_status = ''
 
     # IStorage
 
@@ -570,7 +571,8 @@
 
     @ensure_open_storage
     def raid_details(self):
-        return [self.storages_optimal, self.storage_recovering, self.storages_degraded]
+        return [self.storages_optimal, self.storage_recovering,
+                self.storages_degraded, self.recovery_status]
 
     @ensure_open_storage
     def raid_disable(self, name):
@@ -788,6 +790,7 @@
             self, storage, self._finalize_recovery,
             recover_blobs=(self.blob_fshelper and not self.shared_blob_dir))
         for msg in recovery():
+            self.recovery_status = msg
             logger.debug(str(msg))
 
     def _finalize_recovery(self, storage):

Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_recovery.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_recovery.py	2009-07-02 15:59:34 UTC (rev 101399)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_recovery.py	2009-07-02 17:08:31 UTC (rev 101400)
@@ -50,6 +50,11 @@
                 test.assertEquals(getattr(source_record, name),
                                   getattr(target_record, name))
 
+            # Check that the loadBefores return the same information
+            test.assertEquals(
+                source.loadBefore(source_record.oid, source_record.tid),
+                target.loadBefore(target_record.oid, target_record.tid))
+
             if not hasattr(source, 'loadBlob'):
                 continue
             try:
@@ -117,8 +122,15 @@
     shared = False
 
     def store(self, storages, tid=None, status=' ', user=None,
-              description=None, extension={}):
-        oid = storages[0].new_oid()
+              description=None, extension={}, oid=None):
+        if oid is None:
+            oid = storages[0].new_oid()
+
+        try:
+            data, base_tid = storages[0].load(oid, '')
+        except ZODB.POSException.POSKeyError:
+            base_tid = ZODB.utils.z64
+
         data = ZODB.tests.MinPO.MinPO(7)
         data = ZODB.tests.StorageTestBase.zodb_pickle(data)
         # Begin the transaction
@@ -139,9 +151,9 @@
                     blob_file.write('I am a happy blob.')
                     blob_file.close()
                     r1 = storage.storeBlob(
-                        oid, ZODB.utils.z64, data, blob_file_name, '', t)
+                        oid, base_tid, data, blob_file_name, '', t)
                 else:
-                    r1 = storage.store(oid, ZODB.utils.z64, data, '', t)
+                    r1 = storage.store(oid, base_tid, data, '', t)
                 # Finish the transaction
                 r2 = storage.tpc_vote(t)
                 tid = ZODB.tests.StorageTestBase.handle_serials(oid, r1, r2)
@@ -151,7 +163,7 @@
             for storage in storages:
                 storage.tpc_abort(t)
             raise
-        return tid
+        return tid, oid
 
     def compare(self, source, target):
         compare(self, source, target)
@@ -172,7 +184,6 @@
             shutil.rmtree(path)
 
     def setup_raid(self):
-
         if self.use_blobs:
             blob_dir = tempfile.mkdtemp()
             self.temp_paths.append(blob_dir)
@@ -228,25 +239,25 @@
         self.assertRaises(ValueError, recovery.next)
 
     def test_verify_status_mismatch(self):
-        tid = self.store([self.source])
+        tid, _ = self.store([self.source])
         self.store([self.target], tid=tid, status='p')
         recovery = self.recovery()
         self.assertRaises(ValueError, recovery.next)
 
     def test_verify_user_mismatch(self):
-        tid = self.store([self.source])
+        tid, _ = self.store([self.source])
         self.store([self.target], tid=tid, user='Hans')
         recovery = self.recovery()
         self.assertRaises(ValueError, recovery.next)
 
     def test_verify_description_mismatch(self):
-        tid = self.store([self.source])
+        tid, _ = self.store([self.source])
         self.store([self.target], tid=tid, description='foo bar')
         recovery = self.recovery()
         self.assertRaises(ValueError, recovery.next)
 
     def test_verify_extension_mismatch(self):
-        tid = self.store([self.source])
+        tid, _ = self.store([self.source])
         self.store([self.target], tid=tid, extension=dict(foo=3))
         recovery = self.recovery()
         self.assertRaises(ValueError, recovery.next)
@@ -260,11 +271,13 @@
 
     def test_recover_simple(self):
         self.store([self.source, self.target])
-        self.store([self.source])
+        _, oid = self.store([self.source])
+        self.store([self.source], oid=oid)
         recovery = self.recovery()
         self.assertEquals('verify', recovery.next()[0])
         self.assertEquals('verified', recovery.next()[0])
         self.assertEquals('recover', recovery.next()[0])
+        self.assertEquals('recover', recovery.next()[0])
         self.assertEquals('recovered', recovery.next()[0])
         self.compare(self.source, self.target)
 



More information about the Checkins mailing list