pull: move transaction logic into the pull object
authorPierre-Yves David <pierre-yves.david@logilab.fr>
Fri, 31 Jan 2014 01:04:05 -0800
changeset 20477 2607a21bb40b
parent 20476 1180c6ec5695
child 20478 80628d4069be
pull: move transaction logic into the pull object Most local change that occurs during a pull are doing within a `transaction`. Currently this mean (1) adding new changeset (2) adding obsolescence markers. We want the two operations to be done in the same transaction. However we do not want to create a transaction if nothing is added to the repo. Creating an empty transaction would drop the previous transaction data and confuse tool and people who are still using rollback. So the current pull code has some logic to create and handle this transaction on demand. We are moving this logic in to the `pulloperation` object itself to simplify this lazy creation logic through all different par of the push. Note that, in the future, other part of pull (phases, bookmark) will probably want to be part of the transaction too.
mercurial/exchange.py
--- a/mercurial/exchange.py	Thu Jan 30 17:38:41 2014 -0800
+++ b/mercurial/exchange.py	Fri Jan 31 01:04:05 2014 -0800
@@ -391,6 +391,26 @@
         self.heads = heads
         # do we force pull?
         self.force = force
+        # the name the pull transaction
+        self._trname = 'pull\n' + util.hidepassword(remote.url())
+        # hold the transaction once created
+        self._tr = None
+
+    def gettransaction(self):
+        """get appropriate pull transaction, creating it if needed"""
+        if self._tr is None:
+            self._tr = self.repo.transaction(self._trname)
+        return self._tr
+
+    def closetransaction(self):
+        """close transaction if created"""
+        if self._tr is not None:
+            self._tr.close()
+
+    def releasetransaction(self):
+        """release transaction if created"""
+        if self._tr is not None:
+            self._tr.release()
 
 def pull(repo, remote, heads=None, force=False):
     pullop = pulloperation(repo, remote, heads, force)
@@ -402,10 +422,6 @@
                     " %s") % (', '.join(sorted(missing)))
             raise util.Abort(msg)
 
-    # don't open transaction for nothing or you break future useful
-    # rollback call
-    tr = None
-    trname = 'pull\n' + util.hidepassword(pullop.remote.url())
     lock = pullop.repo.lock()
     try:
         tmp = discovery.findcommonincoming(pullop.repo.unfiltered(),
@@ -417,7 +433,10 @@
             pullop.repo.ui.status(_("no changes found\n"))
             result = 0
         else:
-            tr = pullop.repo.transaction(trname)
+            # We delay the open of the transaction as late as possible so we
+            # don't open transaction for nothing or you break future useful
+            # rollback call
+            pullop.gettransaction()
             if pullop.heads is None and list(common) == [nullid]:
                 pullop.repo.ui.status(_("requesting all changes\n"))
             elif (pullop.heads is None
@@ -465,20 +484,11 @@
             # should be seen as public
             phases.advanceboundary(pullop.repo, phases.public, subset)
 
-        def gettransaction():
-            if tr is None:
-                return pullop.repo.transaction(trname)
-            return tr
-
-        obstr = _pullobsolete(pullop.repo, pullop.remote, gettransaction)
-        if obstr is not None:
-            tr = obstr
-
-        if tr is not None:
-            tr.close()
+        _pullobsolete(pullop.repo, pullop.remote,
+                      pullop.gettransaction)
+        pullop.closetransaction()
     finally:
-        if tr is not None:
-            tr.release()
+        pullop.releasetransaction()
         lock.release()
 
     return result