transaction: refactor transaction.abort and rollback to use the same code
authorHenrik Stuart <hg@hstuart.dk>
Mon, 04 May 2009 15:31:57 +0200
changeset 8294 48a382c23226
parent 8293 f00573bc93f8
child 8295 1ea7e7d90007
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@cyanite.org>
mercurial/localrepo.py
mercurial/transaction.py
tests/test-repair-strip.out
--- a/mercurial/localrepo.py	Mon May 04 13:47:12 2009 +0200
+++ b/mercurial/localrepo.py	Mon May 04 15:31:57 2009 +0200
@@ -624,7 +624,7 @@
         try:
             if os.path.exists(self.sjoin("journal")):
                 self.ui.status(_("rolling back interrupted transaction\n"))
-                transaction.rollback(self.sopener, self.sjoin("journal"))
+                transaction.rollback(self.sopener, self.sjoin("journal"), self.ui.warn)
                 self.invalidate()
                 return True
             else:
@@ -640,7 +640,7 @@
             lock = self.lock()
             if os.path.exists(self.sjoin("undo")):
                 self.ui.status(_("rolling back last transaction\n"))
-                transaction.rollback(self.sopener, self.sjoin("undo"))
+                transaction.rollback(self.sopener, self.sjoin("undo"), self.ui.warn)
                 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
                 try:
                     branch = self.opener("undo.branch").read()
--- a/mercurial/transaction.py	Mon May 04 13:47:12 2009 +0200
+++ b/mercurial/transaction.py	Mon May 04 15:31:57 2009 +0200
@@ -23,6 +23,23 @@
         return func(self, *args, **kwds)
     return _active
 
+def _playback(journal, report, opener, entries, unlink=True):
+    for f, o, ignore in entries:
+        if o or not unlink:
+            try:
+                opener(f, 'a').truncate(o)
+            except:
+                report(_("failed to truncate %s\n") % f)
+                raise
+        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
@@ -101,40 +118,21 @@
 
         self.report(_("transaction abort!\n"))
 
-        failed = False
-        for f, o, ignore in self.entries:
+        try:
             try:
-                self.opener(f, "a").truncate(o)
+                _playback(self.journal, self.report, self.opener, self.entries, False)
+                self.report(_("rollback completed\n"))
             except:
-                failed = True
-                self.report(_("failed to truncate %s\n") % f)
-
-        self.entries = []
-
-        if not failed:
-            os.unlink(self.journal)
-            self.report(_("rollback completed\n"))
-        else:
-            self.report(_("rollback failed - please run hg recover\n"))
-
-        self.journal = None
+                self.report(_("rollback failed - please run hg recover\n"))
+        finally:
+            self.journal = None
 
 
-def rollback(opener, file):
-    files = {}
+def rollback(opener, file, report):
+    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))
 
+    _playback(file, report, opener, entries)
--- a/tests/test-repair-strip.out	Mon May 04 13:47:12 2009 +0200
+++ b/tests/test-repair-strip.out	Mon May 04 15:31:57 2009 +0200
@@ -17,8 +17,9 @@
  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
-1 warnings encountered!
+2 warnings encountered!
 2 integrity errors encountered!
 % journal contents
 00changelog.i
@@ -63,15 +64,15 @@
  manifest@?: rev 2 points to nonexistent changeset 2
  manifest@?: rev 3 points to nonexistent changeset 3
 crosschecking files in changesets and manifests
- c@?: in manifest but not in changeset
+ c@3: in manifest but not in changeset
 checking files
- b@2: 736c29771fba in manifests not found
- data/c.i@?: missing revlog!
- ?: empty or missing c
- c@3: 149da44f2a4e in manifests not found
-3 files, 2 changesets, 2 total revisions
-7 integrity errors encountered!
-(first damaged changeset appears to be 2)
+ b@?: rev 1 points to nonexistent changeset 2
+ (expected 1)
+ c@?: rev 0 points to nonexistent changeset 3
+3 files, 2 changesets, 4 total revisions
+1 warnings encountered!
+5 integrity errors encountered!
+(first damaged changeset appears to be 3)
 % journal contents
 00changelog.i
 00manifest.i