bundle2: make it possible have a global transaction for the unbundling
authorPierre-Yves David <pierre-yves.david@fb.com>
Wed, 02 Apr 2014 23:56:49 -0700
changeset 20952 b24ee5076b94
parent 20951 f977c732bf34
child 20953 8d853cad6b14
bundle2: make it possible have a global transaction for the unbundling We use the `gettransaction` method approach already used for pull. We need this because we do not know beforehand if the bundle needs a transaction to be created. And (1) we do not want to create a transaction for nothing. (2) Some bundle2 bundles may be read-only and do not require any lock or transaction to be held.
mercurial/bundle2.py
tests/test-bundle2.t
--- a/mercurial/bundle2.py	Fri Apr 04 17:47:19 2014 -0500
+++ b/mercurial/bundle2.py	Wed Apr 02 23:56:49 2014 -0700
@@ -238,12 +238,23 @@
     * a way to construct a bundle response when applicable.
     """
 
-    def __init__(self, repo):
+    def __init__(self, repo, transactiongetter):
         self.repo = repo
         self.ui = repo.ui
         self.records = unbundlerecords()
+        self.gettransaction = transactiongetter
 
-def processbundle(repo, unbundler):
+class TransactionUnavailable(RuntimeError):
+    pass
+
+def _notransaction():
+    """default method to get a transaction while processing a bundle
+
+    Raise an exception to highlight the fact that no transaction was expected
+    to be created"""
+    raise TransactionUnavailable()
+
+def processbundle(repo, unbundler, transactiongetter=_notransaction):
     """This function process a bundle, apply effect to/from a repo
 
     It iterates over each part then searches for and uses the proper handling
@@ -254,7 +265,7 @@
 
     Unknown Mandatory part will abort the process.
     """
-    op = bundleoperation(repo)
+    op = bundleoperation(repo, transactiongetter)
     # todo:
     # - replace this is a init function soon.
     # - exception catching
@@ -532,6 +543,12 @@
     This is a very early implementation that will massive rework before being
     inflicted to any end-user.
     """
+    # Make sure we trigger a transaction creation
+    #
+    # The addchangegroup function will get a transaction object by itself, but
+    # we need to make sure we trigger the creation of a transaction object used
+    # for the whole processing scope.
+    op.gettransaction()
     data = StringIO.StringIO(part.data)
     data.seek(0)
     cg = changegroup.readbundle(data, 'bundle2part')
--- a/tests/test-bundle2.t	Fri Apr 04 17:47:19 2014 -0500
+++ b/tests/test-bundle2.t	Wed Apr 02 23:56:49 2014 -0700
@@ -96,13 +96,18 @@
   > def cmdunbundle2(ui, repo):
   >     """process a bundle2 stream from stdin on the current repo"""
   >     try:
+  >         tr = None
   >         lock = repo.lock()
+  >         tr = repo.transaction('processbundle')
   >         try:
   >             unbundler = bundle2.unbundle20(ui, sys.stdin)
-  >             op = bundle2.processbundle(repo, unbundler)
+  >             op = bundle2.processbundle(repo, unbundler, lambda: tr)
+  >             tr.close()
   >         except KeyError, exc:
   >             raise util.Abort('missing support for %s' % exc)
   >     finally:
+  >         if tr is not None:
+  >             tr.release()
   >         lock.release()
   >         remains = sys.stdin.read()
   >         ui.write('%i unread bytes\n' % len(remains))