Mercurial > public > mercurial-scm > hg
comparison mercurial/exchange.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 | 9929af2b09b4 |
children | a470bbb4e3af |
comparison
equal
deleted
inserted
replaced
32708:90cb4ec8df64 | 32709:16ada4cbb1a9 |
---|---|
321 self.cgresult = None | 321 self.cgresult = None |
322 # Boolean value for the bookmark push | 322 # Boolean value for the bookmark push |
323 self.bkresult = None | 323 self.bkresult = None |
324 # discover.outgoing object (contains common and outgoing data) | 324 # discover.outgoing object (contains common and outgoing data) |
325 self.outgoing = None | 325 self.outgoing = None |
326 # all remote heads before the push | 326 # all remote topological heads before the push |
327 self.remoteheads = None | 327 self.remoteheads = None |
328 # Details of the remote branch pre and post push | |
329 # | |
330 # mapping: {'branch': ([remoteheads], | |
331 # [newheads], | |
332 # [unsyncedheads], | |
333 # [discardedheads])} | |
334 # - branch: the branch name | |
335 # - remoteheads: the list of remote heads known locally | |
336 # None if the branch is new | |
337 # - newheads: the new remote heads (known locally) with outgoing pushed | |
338 # - unsyncedheads: the list of remote heads unknown locally. | |
339 # - discardedheads: the list of remote heads made obsolete by the push | |
340 self.pushbranchmap = None | |
328 # testable as a boolean indicating if any nodes are missing locally. | 341 # testable as a boolean indicating if any nodes are missing locally. |
329 self.incoming = None | 342 self.incoming = None |
330 # phases changes that must be pushed along side the changesets | 343 # phases changes that must be pushed along side the changesets |
331 self.outdatedphases = None | 344 self.outdatedphases = None |
332 # phases changes that must be pushed if changeset push fails | 345 # phases changes that must be pushed if changeset push fails |
710 def _pushb2ctxcheckheads(pushop, bundler): | 723 def _pushb2ctxcheckheads(pushop, bundler): |
711 """Generate race condition checking parts | 724 """Generate race condition checking parts |
712 | 725 |
713 Exists as an independent function to aid extensions | 726 Exists as an independent function to aid extensions |
714 """ | 727 """ |
715 if not pushop.force: | 728 # * 'force' do not check for push race, |
716 bundler.newpart('check:heads', data=iter(pushop.remoteheads)) | 729 # * if we don't push anything, there are nothing to check. |
730 if not pushop.force and pushop.outgoing.missingheads: | |
731 allowunrelated = 'related' in bundler.capabilities.get('checkheads', ()) | |
732 if not allowunrelated: | |
733 bundler.newpart('check:heads', data=iter(pushop.remoteheads)) | |
734 else: | |
735 affected = set() | |
736 for branch, heads in pushop.pushbranchmap.iteritems(): | |
737 remoteheads, newheads, unsyncedheads, discardedheads = heads | |
738 if remoteheads is not None: | |
739 remote = set(remoteheads) | |
740 affected |= set(discardedheads) & remote | |
741 affected |= remote - set(newheads) | |
742 if affected: | |
743 data = iter(sorted(affected)) | |
744 bundler.newpart('check:updated-heads', data=data) | |
717 | 745 |
718 @b2partsgenerator('changeset') | 746 @b2partsgenerator('changeset') |
719 def _pushb2ctx(pushop, bundler): | 747 def _pushb2ctx(pushop, bundler): |
720 """handle changegroup push through bundle2 | 748 """handle changegroup push through bundle2 |
721 | 749 |