Mercurial > public > mercurial-scm > hg
diff mercurial/bundle2.py @ 32709:16ada4cbb1a9
push: add a way to allow concurrent pushes on unrelated heads
Client has a mechanism for the server to check that nothing changed server side
since the client prepared a push. That check is wide and any head changed on
the server will lead to an aborted push. We introduce a way for the client to
send a less strict checking. That logic will check that no heads impacted by
the push have been affected. If other unrelated heads (including named branches
heads) have been affected, the push will proceed.
This is very helpful for repositories with high developers traffic on different
heads, a common setup.
That behavior is currently controlled by an experimental option. The config
should live in the "server" section but bike-shedding of the name will happen
in the next changesets. Servers advertise this capability through a new bundle2
capability 'checkeads', using the value 'related'.
The 'test-push-race.t' is updated to check that new capabilities on the
documented cases.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Mon, 29 May 2017 05:53:58 +0200 |
parents | 37d70ba1d9d1 |
children | a7851519ea02 |
line wrap: on
line diff
--- a/mercurial/bundle2.py Mon May 29 05:52:13 2017 +0200 +++ b/mercurial/bundle2.py Mon May 29 05:53:58 2017 +0200 @@ -1323,6 +1323,8 @@ caps['obsmarkers'] = supportedformat if allowpushback: caps['pushback'] = () + if not repo.ui.configbool('experimental', 'checkheads-strict', True): + caps['checkheads'] = ('related',) return caps def bundle2caps(remote): @@ -1603,6 +1605,35 @@ raise error.PushRaced('repository changed while pushing - ' 'please try again') +@parthandler('check:updated-heads') +def handlecheckupdatedheads(op, inpart): + """check for race on the heads touched by a push + + This is similar to 'check:heads' but focus on the heads actually updated + during the push. If other activities happen on unrelated heads, it is + ignored. + + This allow server with high traffic to avoid push contention as long as + unrelated parts of the graph are involved.""" + h = inpart.read(20) + heads = [] + while len(h) == 20: + heads.append(h) + h = inpart.read(20) + assert not h + # trigger a transaction so that we are guaranteed to have the lock now. + if op.ui.configbool('experimental', 'bundle2lazylocking'): + op.gettransaction() + + currentheads = set() + for ls in op.repo.branchmap().itervalues(): + currentheads.update(ls) + + for h in heads: + if h not in currentheads: + raise error.PushRaced('repository changed while pushing - ' + 'please try again') + @parthandler('output') def handleoutput(op, inpart): """forward output captured on the server to the client"""