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.
--- 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