transaction: allow registering a temporary transaction file
authorPierre-Yves David <pierre-yves.david@fb.com>
Wed, 05 Nov 2014 09:27:08 +0000
changeset 23291 03d2d6931836
parent 23290 59513ec76748
child 23292 e44399c494ab
transaction: allow registering a temporary transaction file During the transaction, files may be created to store or expose data involved in the transaction (eg: changelog index data are written in a 'changelog.i.a' for hooks). But we do not have an official way to record such file creation and make sure they are cleaned up. The lack of clean-up is currently okay because there is a single file involved and a single producer/consumer. However, as we want to expose more data (bookmarks, phases, obsmarker) we need something more solid. The 'backupentries' mechanism could handle that. Temporary files can be encoded as a backup of nothing '('', <temporarypath>)'. We "need" to attach it to the same mechanism as we use to be able to use temporary transaction files outside of .'store/' and 'backupentries' is expected to gain such feature. This changeset makes it clear that we should rename 'backupentries' to something more generic.
mercurial/transaction.py
--- a/mercurial/transaction.py	Thu Nov 13 10:22:47 2014 +0000
+++ b/mercurial/transaction.py	Wed Nov 05 09:27:08 2014 +0000
@@ -44,7 +44,7 @@
 
     backupfiles = []
     for f, b in backupentries:
-        if b:
+        if f and b:
             filepath = opener.join(f)
             backuppath = opener.join(b)
             try:
@@ -54,8 +54,9 @@
                 report(_("failed to recover %s\n") % f)
                 raise
         else:
+            target = f or b
             try:
-                opener.unlink(f)
+                opener.unlink(target)
             except (IOError, OSError), inst:
                 if inst.errno != errno.ENOENT:
                     raise
@@ -65,7 +66,8 @@
     if opener.exists(backuppath):
         opener.unlink(backuppath)
     for f in backupfiles:
-        opener.unlink(f)
+        if opener.exists(f):
+            opener.unlink(f)
 
 class transaction(object):
     def __init__(self, report, opener, journal, after=None, createmode=None,
@@ -99,6 +101,7 @@
 
         # a list of ('path', 'backuppath') entries.
         # if 'backuppath' is empty, no file existed at backup time
+        # if 'path' is empty, this is a temporary transaction file
         self._backupentries = []
         self._backupmap = {}
         self._backupjournal = "%s.backupfiles" % journal
@@ -200,6 +203,15 @@
         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))
+
+    @active
     def addfilegenerator(self, genid, filenames, genfunc, order=0, vfs=None):
         """add a function to generates some files at transaction commit
 
@@ -342,6 +354,10 @@
             return
         self.file.close()
         self._backupsfile.close()
+        # cleanup temporary files
+        for f, b in self._backupentries:
+            if not f and b and self.opener.exists(b):
+                self.opener.unlink(b)
         self.entries = []
         if self.after:
             self.after()
@@ -350,7 +366,7 @@
         if self.opener.isfile(self._backupjournal):
             self.opener.unlink(self._backupjournal)
             for _f, b in self._backupentries:
-                if b:
+                if b and self.opener.exists(b):
                     self.opener.unlink(b)
         self._backupentries = []
         self.journal = None