From patchwork Thu Nov 13 23:39:17 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [1,of,5] transaction: change the on disk format for backupentries From: Pierre-Yves David X-Patchwork-Id: 6722 Message-Id: To: mercurial-devel@selenic.com Cc: Pierre-Yves David Date: Thu, 13 Nov 2014 23:39:17 +0000 # HG changeset patch # User Pierre-Yves David # Date 1415152366 0 # Wed Nov 05 01:52:46 2014 +0000 # Node ID dba745ba04b9bc614d422e2e88b362a3bbda6948 # Parent e44399c494ab23cefb8c99087529f9b4b06d398e transaction: change the on disk format for backupentries We need to store new data to improve the current transaction logic: - location: We want to generate and backup file outside of the 'store' (eg: bookmarks, or various cache files). This requires knowing and preserving where each file is located. The value of this new field is a string. It will be used as a key for a vfs mapping. - cache: We would like to handle cache file in the transaction code. This Will help to have cache consistent with the repository state and avoid performance issue on big repository like Mozilla. However, failure to handle cache file should not result in a transaction failure. We add a new field that carry this information. The value is boolean, A True value mean any error while handling this file can be ignored. Those two mechanisms are not implemented yet, but they are now persisted in the on disk file. Support for new mechanisms is coming in later changeset. We update the file format now and will introduce the new features in later changeset. The format version is set to 0 until we actually support the new feature. This will prevent misunderstanding between incomplete and final client. Support for reading both version 1 and (future) version 2 could be achieved (using default value when reading version 1) but has not been seen as necessary for now. diff --git a/mercurial/transaction.py b/mercurial/transaction.py --- a/mercurial/transaction.py +++ b/mercurial/transaction.py @@ -13,11 +13,11 @@ from i18n import _ import errno import error, util -version = 1 +version = 0 def active(func): def _active(self, *args, **kwds): if self.count == 0: raise error.Abort(_( @@ -41,11 +41,11 @@ def _playback(journal, report, opener, e except (IOError, OSError), inst: if inst.errno != errno.ENOENT: raise backupfiles = [] - for f, b in backupentries: + for l, f, b, c in backupentries: if f and b: filepath = opener.join(f) backuppath = opener.join(b) try: util.copyfile(backuppath, filepath) @@ -97,13 +97,14 @@ class transaction(object): self._queue = [] # a dict of arguments to be passed to hooks self.hookargs = {} self.file = opener.open(self.journal, "w") - # a list of ('path', 'backuppath') entries. + # 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) self._backupentries = [] self._backupmap = {} self._backupjournal = "%s.backupfiles" % journal self._backupsfile = opener.open(self._backupjournal, 'w') self._backupsfile.write('%d\n' % version) @@ -191,27 +192,27 @@ class transaction(object): backuppath = self.opener.join(backupfile) util.copyfiles(filepath, backuppath, hardlink=hardlink) else: backupfile = '' - self._addbackupentry((file, backupfile)) + self._addbackupentry(('', file, backupfile, False)) def _addbackupentry(self, entry): """register a new backup entry and write it to disk""" self._backupentries.append(entry) self._backupmap[file] = len(self._backupentries) - 1 - self._backupsfile.write("%s\0%s\n" % entry) + self._backupsfile.write("%s\0%s\0%s\0%d\n" % entry) self._backupsfile.flush() @active def registertmp(self, tmpfile): """register a temporary transaction file Such file will be delete when the transaction exit (on both failure and success). """ - self._addbackupentry(('', tmpfile)) + self._addbackupentry(('', '', tmpfile, False)) @active def addfilegenerator(self, genid, filenames, genfunc, order=0, vfs=None): """add a function to generates some files at transaction commit @@ -353,21 +354,21 @@ class transaction(object): if self.count != 0: return self.file.close() self._backupsfile.close() # cleanup temporary files - for f, b in self._backupentries: + for _l, f, b, _c in self._backupentries: if not f and b and self.opener.exists(b): self.opener.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 _f, b in self._backupentries: + for _l, _f, b, _c in self._backupentries: if b and self.opener.exists(b): self.opener.unlink(b) self._backupentries = [] self.journal = None # run post close action @@ -445,12 +446,12 @@ def rollback(opener, file, report): if ver == str(version): for line in lines[1:]: if line: # Shave off the trailing newline line = line[:-1] - f, b = line.split('\0') - backupentries.append((f, b)) + l, f, b, c = line.split('\0') + backupentries.append((l, f, b, bool(c))) else: - report(_("journal was created by a newer version of " + report(_("journal was created by a different version of " "Mercurial")) _playback(file, report, opener, entries, backupentries)