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

Olle olle.lundberg at gmail.com
Sat Oct 18 06:55:58 CDT 2014


On Sat, Oct 18, 2014 at 1:44 PM, Pierre-Yves David <
pierre-yves.david at ens-lyon.org> wrote:

> # 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 f533386d7f84a8e5ad1885d654d5983d81302b79
> # Parent  580364627689487b0c13185a28d925f676fa0526
> transaction: use "location" when doing backup
>
> Same logic here, we stop passing vfs object as arguments and use the
> location
> identifier to backup the right file. We persist this in the transaction
> state
> file.  As this is a format change (3 values per entry instead of 2) we
> change
> the file name to "backupfiles2".
>
> Note that backup of empty file is handled by the "entries" list, not
> "backupentries" and will improve that in the next changeset.
>
> Some more compatibility layer between "backupfiles" and "backupfiles2" may
> come
> in the futur.
>
> diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
> --- a/mercurial/localrepo.py
> +++ b/mercurial/localrepo.py
> @@ -915,11 +915,12 @@ 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 = {'store': 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"))
> @@ -971,11 +972,12 @@ class localrepository(object):
>          if dryrun:
>              return 0
>
>          parents = self.dirstate.parents()
>          self.destroying()
> -        transaction.rollback(self.sopener, 'undo', ui.warn)
> +        vfsmap = {'store': self.sopener, '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
> @@ -21,11 +21,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):
>
Inside parens there is no need to use a backslash to denote a line
continuation.

>      for f, o, _ignore in entries:
>          if o or not unlink:
>              try:
>                  fp = opener(f, 'a')
>                  fp.truncate(o)
> @@ -39,22 +40,23 @@ def _playback(journal, report, opener, e
>              except (IOError, OSError), inst:
>                  if inst.errno != errno.ENOENT:
>                      raise
>
>      backupfiles = []
> -    for f, b, _ignore in backupentries:
> -        filepath = opener.join(f)
> -        backuppath = opener.join(b)
> +    for l, f, b, _ignore in backupentries:
> +        vfs = vfsmap[l]
> +        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
>
>      opener.unlink(journal)
> -    backuppath = "%s.backupfiles" % journal
> +    backuppath = "%s.backupfiles2" % journal
>      if opener.exists(backuppath):
>          opener.unlink(backuppath)
>      for f in backupfiles:
>          opener.unlink(f)
>
> @@ -90,11 +92,11 @@ class transaction(object):
>          self.journal = journal
>          self._queue = []
>          # a dict of arguments to be passed to hooks
>          self.hookargs = {}
>
> -        self.backupjournal = "%s.backupfiles" % journal
> +        self.backupjournal = "%s.backupfiles2" % journal
>          self.file = opener.open(self.journal, "w")
>          self.backupsfile = opener.open(self.backupjournal, 'w')
>          if createmode is not None:
>              opener.chmod(self.journal, createmode & 0666)
>              opener.chmod(self.backupjournal, createmode & 0666)
> @@ -119,18 +121,18 @@ class transaction(object):
>          offsets = []
>          backups = []
>          for f, o, _data in q[0]:
>              offsets.append((f, o))
>
> -        for f, b, _data in q[1]:
> -            backups.append((f, b))
> +        for l, f, b, _data in q[1]:
> +            backups.append((l, f, b))
>
>          d = ''.join(['%s\0%d\n' % (f, o) for f, o in offsets])
>          self.file.write(d)
>          self.file.flush()
>
> -        d = ''.join(['%s\0%s\0' % (f, b) for f, b in backups])
> +        d = ''.join(['%s\0%s\0%s\0' % entry for entry in backups])
>          self.backupsfile.write(d)
>          self.backupsfile.flush()
>
>      @active
>      def add(self, file, offset, data=None):
> @@ -145,11 +147,11 @@ class transaction(object):
>          # add enough data to the journal to do the truncate
>          self.file.write("%s\0%d\n" % (file, offset))
>          self.file.flush()
>
>      @active
> -    def addbackup(self, file, hardlink=True, vfs=None):
> +    def addbackup(self, file, hardlink=True, location='store'):
>          """Adds a backup of the file to the transaction
>
>          Calling addbackup() creates a hardlink backup of the specified
> file
>          that is used to recover the file in the event of the transaction
>          aborting.
> @@ -159,12 +161,11 @@ class transaction(object):
>          """
>
>          if file in self.map or file in self.backupmap:
>              return
>          backupfile = "%s.backup.%s" % (self.journal, file)
> -        if vfs is None:
> -            vfs = self.opener
> +        vfs = self._vfsmap[location]
>          if vfs.exists(file):
>              filepath = vfs.join(file)
>              backuppath = self.opener.join(backupfile)
>              util.copyfiles(filepath, backuppath, hardlink=hardlink)
>          else:
> @@ -173,13 +174,13 @@ class transaction(object):
>
>          if self._queue:
>              self._queue[-1][1].append((file, backupfile))
>              return
>
> -        self.backupentries.append((file, backupfile, None))
> +        self.backupentries.append((location, file, backupfile, None))
>          self.backupmap[file] = len(self.backupentries) - 1
> -        self.backupsfile.write("%s\0%s\0" % (file, backupfile))
> +        self.backupsfile.write("%s\0%s\0%s\0" % (location, file,
> backupfile))
>          self.backupsfile.flush()
>
>      @active
>      def addfilegenerator(self, genid, filenames, genfunc, order=0,
>                           location='store'):
> @@ -278,12 +279,13 @@ class transaction(object):
>              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 _f, b, _ignore in self.backupentries:
> -                self.opener.unlink(b)
> +            for l, _f, b, _ignore in self.backupentries:
> +                vfs = self._vfsmap[l]
> +                vfs.unlink(b)
>          self.backupentries = []
>          self.journal = None
>
>      @active
>      def abort(self):
> @@ -310,20 +312,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.
>
> @@ -350,10 +352,10 @@ def rollback(opener, file, report):
>      if opener.exists(backupjournal):
>          fp = opener.open(backupjournal)
>          data = fp.read()
>          if len(data) > 0:
>              parts = data.split('\0')
> -            for i in xrange(0, len(parts), 2):
> -                f, b = parts[i:i + 1]
> -                backupentries.append((f, b, None))
> +            for i in xrange(0, len(parts), 3):
> +                f, b = parts[i:i + 2]
> +                backupentries.append((l, f, b, None))
>
> -    _playback(file, report, opener, entries, backupentries)
> +    _playback(file, report, opener, vfsmap, entries, backupentries)
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
>



-- 
Olle
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20141018/c882c90d/attachment.html>


More information about the Mercurial-devel mailing list