[PATCH 3 of 5] transaction: use the location value when doing backup

Pierre-Yves David pierre-yves.david at ens-lyon.org
Thu Nov 13 17:39:19 CST 2014


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at fb.com>
# Date 1413605075 25200
#      Fri Oct 17 21:04:35 2014 -0700
# Node ID b86227ec8b547d605306421d8d293294b7659fc6
# Parent  f156e9a258e17284b5c6d8608346ca9e91077ee8
transaction: use the location value when doing backup

We finally use the 'location' value coupled with the 'vfsmap' to restore backup
for the right file.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -917,11 +917,13 @@ class localrepository(object):
     def recover(self):
         lock = self.lock()
         try:
             if self.svfs.exists("journal"):
                 self.ui.status(_("rolling back interrupted transaction\n"))
-                transaction.rollback(self.sopener, "journal",
+                vfsmap = {'': self.sopener,
+                          'plain': self.opener,}
+                transaction.rollback(self.sopener, vfsmap, "journal",
                                      self.ui.warn)
                 self.invalidate()
                 return True
             else:
                 self.ui.warn(_("no interrupted transaction available\n"))
@@ -973,11 +975,12 @@ class localrepository(object):
         if dryrun:
             return 0
 
         parents = self.dirstate.parents()
         self.destroying()
-        transaction.rollback(self.sopener, 'undo', ui.warn)
+        vfsmap = {'plain': self.opener}
+        transaction.rollback(self.sopener, vfsmap, 'undo', ui.warn)
         if self.vfs.exists('undo.bookmarks'):
             self.vfs.rename('undo.bookmarks', 'bookmarks')
         if self.svfs.exists('undo.phaseroots'):
             self.svfs.rename('undo.phaseroots', 'phaseroots')
         self.invalidate()
diff --git a/mercurial/transaction.py b/mercurial/transaction.py
--- a/mercurial/transaction.py
+++ b/mercurial/transaction.py
@@ -23,11 +23,12 @@ def active(func):
             raise error.Abort(_(
                 'cannot use transaction when it is already committed/aborted'))
         return func(self, *args, **kwds)
     return _active
 
-def _playback(journal, report, opener, entries, backupentries, unlink=True):
+def _playback(journal, report, opener, vfsmap, entries, backupentries,
+              unlink=True):
     for f, o, _ignore in entries:
         if o or not unlink:
             try:
                 fp = opener(f, 'a')
                 fp.truncate(o)
@@ -42,23 +43,24 @@ def _playback(journal, report, opener, e
                 if inst.errno != errno.ENOENT:
                     raise
 
     backupfiles = []
     for l, f, b, c in backupentries:
+        vfs = vfsmap[l]
         if f and b:
-            filepath = opener.join(f)
-            backuppath = opener.join(b)
+            filepath = vfs.join(f)
+            backuppath = vfs.join(b)
             try:
                 util.copyfile(backuppath, filepath)
                 backupfiles.append(b)
             except IOError:
                 report(_("failed to recover %s\n") % f)
                 raise
         else:
             target = f or b
             try:
-                opener.unlink(target)
+                vfs.unlink(target)
             except (IOError, OSError), inst:
                 if inst.errno != errno.ENOENT:
                     raise
 
     opener.unlink(journal)
@@ -103,13 +105,15 @@ class transaction(object):
         # a dict of arguments to be passed to hooks
         self.hookargs = {}
         self.file = opener.open(self.journal, "w")
 
         # a list of ('location', 'path', 'backuppath', cache) entries.
-        # if 'backuppath' is empty, no file existed at backup time
-        # if 'path' is empty, this is a temporary transaction file
-        # (location, and cache are current unused)
+        # - if 'backuppath' is empty, no file existed at backup time
+        # - if 'path' is empty, this is a temporary transaction file
+        # - if 'location' is not empty, the path is outside main opener reach.
+        #   use 'location' value as a key in a vfsmap to find the right 'vfs'
+        # (cache is currently unused)
         self._backupentries = []
         self._backupmap = {}
         self._backupjournal = "%s.backupfiles" % journal
         self._backupsfile = opener.open(self._backupjournal, 'w')
         self._backupsfile.write('%d\n' % version)
@@ -359,23 +363,25 @@ class transaction(object):
         if self.count != 0:
             return
         self.file.close()
         self._backupsfile.close()
         # cleanup temporary files
-        for _l, f, b, _c in self._backupentries:
-            if not f and b and self.opener.exists(b):
-                self.opener.unlink(b)
+        for l, f, b, _c in self._backupentries:
+            vfs = self._vfsmap[l]
+            if not f and b and vfs.exists(b):
+                vfs.unlink(b)
         self.entries = []
         if self.after:
             self.after()
         if self.opener.isfile(self.journal):
             self.opener.unlink(self.journal)
         if self.opener.isfile(self._backupjournal):
             self.opener.unlink(self._backupjournal)
             for _l, _f, b, _c in self._backupentries:
-                if b and self.opener.exists(b):
-                    self.opener.unlink(b)
+                vfs = self._vfsmap[l]
+                if b and vfs.exists(b):
+                    vfs.unlink(b)
         self._backupentries = []
         self.journal = None
         # run post close action
         categories = sorted(self._postclosecallback)
         for cat in categories:
@@ -406,20 +412,20 @@ class transaction(object):
                 return
 
             self.report(_("transaction abort!\n"))
 
             try:
-                _playback(self.journal, self.report, self.opener,
+                _playback(self.journal, self.report, self.opener, self._vfsmap,
                           self.entries, self._backupentries, False)
                 self.report(_("rollback completed\n"))
             except Exception:
                 self.report(_("rollback failed - please run hg recover\n"))
         finally:
             self.journal = None
 
 
-def rollback(opener, file, report):
+def rollback(opener, vfsmap, file, report):
     """Rolls back the transaction contained in the given file
 
     Reads the entries in the specified file, and the corresponding
     '*.backupfiles' file, to recover from an incomplete transaction.
 
@@ -457,6 +463,6 @@ def rollback(opener, file, report):
                         backupentries.append((l, f, b, bool(c)))
             else:
                 report(_("journal was created by a different version of "
                          "Mercurial"))
 
-    _playback(file, report, opener, entries, backupentries)
+    _playback(file, report, opener, vfsmap, entries, backupentries)


More information about the Mercurial-devel mailing list