mercurial/setdiscovery.py
changeset 41167 870a89c6909d
parent 41162 cc1f545c4075
child 41168 1d30be90c9dc
equal deleted inserted replaced
41166:9365b8cb90e0 41167:870a89c6909d
   165     """an object representing ongoing discovery
   165     """an object representing ongoing discovery
   166 
   166 
   167     Feed with data from the remote repository, this object keep track of the
   167     Feed with data from the remote repository, this object keep track of the
   168     current set of changeset in various states:
   168     current set of changeset in various states:
   169 
   169 
   170     - common: own nodes I know we both know
   170     - common:    own nodes I know we both know
       
   171     - undecided: own nodes where I don't know if remote knows them
   171     """
   172     """
   172 
   173 
   173     def __init__(self, repo):
   174     def __init__(self, repo, targetheads):
   174         self._repo = repo
   175         self._repo = repo
       
   176         self._targetheads = targetheads
   175         self._common = repo.changelog.incrementalmissingrevs()
   177         self._common = repo.changelog.incrementalmissingrevs()
       
   178         self._undecided = None
   176 
   179 
   177     def addcommons(self, commons):
   180     def addcommons(self, commons):
   178         """registrer nodes known as common"""
   181         """registrer nodes known as common"""
   179         self._common.addbases(commons)
   182         self._common.addbases(commons)
   180 
   183 
   181     def hasinfo(self):
   184     def hasinfo(self):
   182         """return True is we have any clue about the remote state"""
   185         """return True is we have any clue about the remote state"""
   183         return self._common.hasbases()
   186         return self._common.hasbases()
       
   187 
       
   188     @property
       
   189     def undecided(self):
       
   190         if self._undecided is not None:
       
   191             return self._undecided
       
   192         self._undecided = set(self._common.missingancestors(self._targetheads))
       
   193         return self._undecided
   184 
   194 
   185     def commonheads(self):
   195     def commonheads(self):
   186         """the heads of the known common set"""
   196         """the heads of the known common set"""
   187         # heads(common) == heads(common.bases) since common represents
   197         # heads(common) == heads(common.bases) since common represents
   188         # common.bases and all its ancestors
   198         # common.bases and all its ancestors
   254         ownheadhashes = [clnode(r) for r in ownheads]
   264         ownheadhashes = [clnode(r) for r in ownheads]
   255         return ownheadhashes, True, srvheadhashes
   265         return ownheadhashes, True, srvheadhashes
   256 
   266 
   257     # full blown discovery
   267     # full blown discovery
   258 
   268 
   259     disco = partialdiscovery(local)
   269     disco = partialdiscovery(local, ownheads)
   260     # treat remote heads (and maybe own heads) as a first implicit sample
   270     # treat remote heads (and maybe own heads) as a first implicit sample
   261     # response
   271     # response
   262     disco.addcommons(srvheads)
   272     disco.addcommons(srvheads)
   263     commoninsample = set(n for i, n in enumerate(sample) if yesno[i])
   273     commoninsample = set(n for i, n in enumerate(sample) if yesno[i])
   264     disco.addcommons(commoninsample)
   274     disco.addcommons(commoninsample)
   265     # own nodes where I don't know if remote knows them
       
   266     undecided = set(disco._common.missingancestors(ownheads))
       
   267     # own nodes I know remote lacks
   275     # own nodes I know remote lacks
   268     missing = set()
   276     missing = set()
   269 
   277 
   270     full = False
   278     full = False
   271     progress = ui.makeprogress(_('searching'), unit=_('queries'))
   279     progress = ui.makeprogress(_('searching'), unit=_('queries'))
   272     while undecided:
   280     while disco.undecided:
   273 
   281 
   274         if sample:
   282         if sample:
   275             missinginsample = [n for i, n in enumerate(sample) if not yesno[i]]
   283             missinginsample = [n for i, n in enumerate(sample) if not yesno[i]]
   276 
   284 
   277             if missing:
   285             if missing:
   278                 missing.update(local.revs('descendants(%ld) - descendants(%ld)',
   286                 missing.update(local.revs('descendants(%ld) - descendants(%ld)',
   279                                           missinginsample, missing))
   287                                           missinginsample, missing))
   280             else:
   288             else:
   281                 missing.update(local.revs('descendants(%ld)', missinginsample))
   289                 missing.update(local.revs('descendants(%ld)', missinginsample))
   282 
   290 
   283             undecided.difference_update(missing)
   291             disco.undecided.difference_update(missing)
   284 
   292 
   285         if not undecided:
   293         if not disco.undecided:
   286             break
   294             break
   287 
   295 
   288         if full or disco.hasinfo():
   296         if full or disco.hasinfo():
   289             if full:
   297             if full:
   290                 ui.note(_("sampling from both directions\n"))
   298                 ui.note(_("sampling from both directions\n"))
   295         else:
   303         else:
   296             # use even cheaper initial sample
   304             # use even cheaper initial sample
   297             ui.debug("taking quick initial sample\n")
   305             ui.debug("taking quick initial sample\n")
   298             samplefunc = _takequicksample
   306             samplefunc = _takequicksample
   299             targetsize = initialsamplesize
   307             targetsize = initialsamplesize
   300         sample = samplefunc(local, ownheads, undecided, targetsize)
   308         sample = samplefunc(local, ownheads, disco.undecided, targetsize)
   301 
   309 
   302         roundtrips += 1
   310         roundtrips += 1
   303         progress.update(roundtrips)
   311         progress.update(roundtrips)
   304         ui.debug("query %i; still undecided: %i, sample size is: %i\n"
   312         ui.debug("query %i; still undecided: %i, sample size is: %i\n"
   305                  % (roundtrips, len(undecided), len(sample)))
   313                  % (roundtrips, len(disco.undecided), len(sample)))
   306         # indices between sample and externalized version must match
   314         # indices between sample and externalized version must match
   307         sample = list(sample)
   315         sample = list(sample)
   308 
   316 
   309         with remote.commandexecutor() as e:
   317         with remote.commandexecutor() as e:
   310             yesno = e.callcommand('known', {
   318             yesno = e.callcommand('known', {
   314         full = True
   322         full = True
   315 
   323 
   316         if sample:
   324         if sample:
   317             commoninsample = set(n for i, n in enumerate(sample) if yesno[i])
   325             commoninsample = set(n for i, n in enumerate(sample) if yesno[i])
   318             disco.addcommons(commoninsample)
   326             disco.addcommons(commoninsample)
   319             disco._common.removeancestorsfrom(undecided)
   327             disco._common.removeancestorsfrom(disco.undecided)
   320 
   328 
   321     result = disco.commonheads()
   329     result = disco.commonheads()
   322     elapsed = util.timer() - start
   330     elapsed = util.timer() - start
   323     progress.complete()
   331     progress.complete()
   324     ui.debug("%d total queries in %.4fs\n" % (roundtrips, elapsed))
   332     ui.debug("%d total queries in %.4fs\n" % (roundtrips, elapsed))