[PATCH 5 of 6] transaction: refactor transaction.abort and rollback to use the same code

Henrik Stuart hg at hstuart.dk
Wed Apr 22 02:58:47 CDT 2009


# HG changeset patch
# User Henrik Stuart <hg at hstuart.dk>
# Date 1240384801 -7200
# Node ID 6e2e7f523c56f0caf1a8d7400ba1e1d33919f0f1
# Parent  ad6799ba14f825b373aac1f74e9229dc4481e208
transaction: refactor transaction.abort and rollback to use the same code

This adds a change to the way that abort is processed, as it will not continue
truncating files beyond the first failure, otherwise the respective
functionality is maintained, i.e. abort will not unlink files, but rollback
will.

Co-contributor: Sune Foldager <cryo at cyanite.org>

diff -r ad6799ba14f8 -r 6e2e7f523c56 mercurial/transaction.py
--- a/mercurial/transaction.py	Wed Apr 22 08:55:38 2009 +0200
+++ b/mercurial/transaction.py	Wed Apr 22 09:20:01 2009 +0200
@@ -24,6 +24,20 @@
         return func(*args, **kwds)
     return _active
 
+def _journal_playback(journal, opener, entries, unlink=True):
+    for f, o, ignore in entries:
+        if o or not unlink:
+            opener(f, 'a').truncate(o)
+        else:
+            try:
+                fn = opener(f).name
+                os.unlink(fn)
+            except OSError, inst:
+                if inst.errno != errno.ENOENT:
+                    raise
+
+    os.unlink(journal)
+
 class transaction(object):
     def __init__(self, report, opener, journal, after=None, createmode=None):
         self.journal = None
@@ -108,40 +122,20 @@
 
         self.report(_("transaction abort!\n"))
 
-        failed = False
-        for f, o, ignore in self.entries:
-            try:
-                self.opener(f, "a").truncate(o)
-            except:
-                failed = True
-                self.report(_("failed to truncate %s\n") % f)
-
-        self.entries = []
-
-        if not failed:
-            os.unlink(self.journal)
+        try:
+            _journal_playback(self.journal, self.opener, self.entries, False)
             self.report(_("rollback completed\n"))
-        else:
+        except:
             self.report(_("rollback failed - please run hg recover\n"))
-
-        self.journal = None
+        finally:
+            self.journal = None
 
 
 def rollback(opener, file):
-    files = {}
+    entries = []
+
     for l in open(file).readlines():
         f, o = l.split('\0')
-        files[f] = int(o)
-    for f in files:
-        o = files[f]
-        if o:
-            opener(f, "a").truncate(int(o))
-        else:
-            try:
-                fn = opener(f).name
-                os.unlink(fn)
-            except OSError, inst:
-                if inst.errno != errno.ENOENT:
-                    raise
-    os.unlink(file)
+        entries.append((f, int(o), None))
 
+    _journal_playback(file, opener, entries)
diff -r ad6799ba14f8 -r 6e2e7f523c56 tests/test-repair-strip
--- a/tests/test-repair-strip	Wed Apr 22 08:55:38 2009 +0200
+++ b/tests/test-repair-strip	Wed Apr 22 09:20:01 2009 +0200
@@ -28,9 +28,12 @@
 echo b > b
 hg -q ci -m "b" -A
 
+echo b2 >> b
+hg -q ci -m "b2" -A
+
 echo c > c
 hg -q ci -m "c" -A
 
-teststrip 0 1 w .hg/store/data/b.i
-teststrip 0 1 r .hg/store/data/b.i
-teststrip 0 1 w .hg/store/00changelog.i
+teststrip 0 2 w .hg/store/data/b.i
+teststrip 0 2 r .hg/store/data/b.i
+teststrip 0 2 w .hg/store/00manifest.i
diff -r ad6799ba14f8 -r 6e2e7f523c56 tests/test-repair-strip.out
--- a/tests/test-repair-strip.out	Wed Apr 22 08:55:38 2009 +0200
+++ b/tests/test-repair-strip.out	Wed Apr 22 09:20:01 2009 +0200
@@ -1,4 +1,4 @@
-% before update 0, strip 1
+% before update 0, strip 2
 changeset:   0:cb9a9f314b8b
 user:        test
 date:        Thu Jan 01 00:00:00 1970 +0000
@@ -6,17 +6,20 @@
 
 saving bundle to 
 transaction abort!
-failed to truncate data/b.i
 rollback failed - please run hg recover
 abort: Permission denied .hg/store/data/b.i
-% after update 0, strip 1
+% after update 0, strip 2
 checking changesets
 checking manifests
 crosschecking files in changesets and manifests
 checking files
-warning: orphan revlog 'data/b.i'
-1 files, 1 changesets, 1 total revisions
-1 warnings encountered!
+ b@?: rev 1 points to nonexistent changeset 2
+ (expected 1)
+ b@?: 736c29771fba not in manifests
+warning: orphan revlog 'data/c.i'
+2 files, 2 changesets, 3 total revisions
+2 warnings encountered!
+2 integrity errors encountered!
 % journal contents
 00changelog.i
 00manifest.i
@@ -27,23 +30,23 @@
 checking manifests
 crosschecking files in changesets and manifests
 checking files
-1 files, 1 changesets, 1 total revisions
-% before update 0, strip 1
+2 files, 2 changesets, 2 total revisions
+% before update 0, strip 2
 changeset:   0:cb9a9f314b8b
 user:        test
 date:        Thu Jan 01 00:00:00 1970 +0000
 summary:     a
 
 abort: Permission denied .hg/store/data/b.i
-% after update 0, strip 1
+% after update 0, strip 2
 checking changesets
 checking manifests
 crosschecking files in changesets and manifests
 checking files
-3 files, 3 changesets, 3 total revisions
+3 files, 4 changesets, 4 total revisions
 % journal contents
 cat: .hg/store/journal: No such file or directory
-% before update 0, strip 1
+% before update 0, strip 2
 changeset:   0:cb9a9f314b8b
 user:        test
 date:        Thu Jan 01 00:00:00 1970 +0000
@@ -51,25 +54,24 @@
 
 saving bundle to 
 transaction abort!
-failed to truncate 00changelog.i
 rollback failed - please run hg recover
-abort: Permission denied .hg/store/00changelog.i
-% after update 0, strip 1
+abort: Permission denied .hg/store/00manifest.i
+% after update 0, strip 2
 checking changesets
 checking manifests
+ manifest@?: rev 2 points to nonexistent changeset 2
+ manifest@?: rev 3 points to nonexistent changeset 3
 crosschecking files in changesets and manifests
- 1: changeset refers to unknown manifest a539ce0c1a22
- 2: changeset refers to unknown manifest e3738bf54399
- b at 1: in changeset but not in manifest
- c at 2: in changeset but not in manifest
+ c at 3: in manifest but not in changeset
 checking files
- data/b.i at 1: missing revlog!
- 0: empty or missing b
- data/c.i at 2: missing revlog!
- 0: empty or missing c
-3 files, 3 changesets, 1 total revisions
-8 integrity errors encountered!
-(first damaged changeset appears to be 0)
+ b@?: rev 1 points to nonexistent changeset 2
+ (expected 1)
+ ?: missing revlog for file 'c'
+warning: orphan revlog 'data/c.i'
+3 files, 2 changesets, 3 total revisions
+2 warnings encountered!
+5 integrity errors encountered!
+(first damaged changeset appears to be 3)
 % journal contents
 00changelog.i
 00manifest.i
@@ -80,4 +82,4 @@
 checking manifests
 crosschecking files in changesets and manifests
 checking files
-1 files, 1 changesets, 1 total revisions
+2 files, 2 changesets, 2 total revisions


More information about the Mercurial-devel mailing list