##// END OF EJS Templates
setdiscovery: limit lines to 80 characters
Steven Brown -
r14206:2bf60f15 default
parent child Browse files
Show More
@@ -1,242 +1,248 b''
1 # dagutil.py - dag utilities for mercurial
1 # dagutil.py - dag utilities for mercurial
2 #
2 #
3 # Copyright 2010 Benoit Boissinot <bboissin@gmail.com>
3 # Copyright 2010 Benoit Boissinot <bboissin@gmail.com>
4 # and Peter Arrenbrecht <peter@arrenbrecht.ch>
4 # and Peter Arrenbrecht <peter@arrenbrecht.ch>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from node import nullrev
9 from node import nullrev
10
10
11
11
12 class basedag(object):
12 class basedag(object):
13 '''generic interface for DAGs
13 '''generic interface for DAGs
14
14
15 terms:
15 terms:
16 "ix" (short for index) identifies a nodes internally,
16 "ix" (short for index) identifies a nodes internally,
17 "id" identifies one externally.
17 "id" identifies one externally.
18
18
19 All params are ixs unless explicitly suffixed otherwise.
19 All params are ixs unless explicitly suffixed otherwise.
20 Pluralized params are lists or sets.
20 Pluralized params are lists or sets.
21 '''
21 '''
22
22
23 def __init__(self):
23 def __init__(self):
24 self._inverse = None
24 self._inverse = None
25
25
26 def nodeset(self):
26 def nodeset(self):
27 '''set of all node idxs'''
27 '''set of all node idxs'''
28 raise NotImplementedError()
28 raise NotImplementedError()
29
29
30 def heads(self):
30 def heads(self):
31 '''list of head ixs'''
31 '''list of head ixs'''
32 raise NotImplementedError()
32 raise NotImplementedError()
33
33
34 def parents(self, ix):
34 def parents(self, ix):
35 '''list of parents ixs of ix'''
35 '''list of parents ixs of ix'''
36 raise NotImplementedError()
36 raise NotImplementedError()
37
37
38 def inverse(self):
38 def inverse(self):
39 '''inverse DAG, where parents becomes children, etc.'''
39 '''inverse DAG, where parents becomes children, etc.'''
40 raise NotImplementedError()
40 raise NotImplementedError()
41
41
42 def ancestorset(self, starts, stops=None):
42 def ancestorset(self, starts, stops=None):
43 '''set of all ancestors of starts (incl), but stop walk at stops (excl)'''
43 '''
44 set of all ancestors of starts (incl), but stop walk at stops (excl)
45 '''
44 raise NotImplementedError()
46 raise NotImplementedError()
45
47
46 def descendantset(self, starts, stops=None):
48 def descendantset(self, starts, stops=None):
47 '''set of all descendants of starts (incl), but stop walk at stops (excl)'''
49 '''
50 set of all descendants of starts (incl), but stop walk at stops (excl)
51 '''
48 return self.inverse().ancestorset(starts, stops)
52 return self.inverse().ancestorset(starts, stops)
49
53
50 def headsetofconnecteds(self, ixs):
54 def headsetofconnecteds(self, ixs):
51 '''subset of connected list of ixs so that no node has a descendant in it
55 '''
56 subset of connected list of ixs so that no node has a descendant in it
52
57
53 By "connected list" we mean that if an ancestor and a descendant are in
58 By "connected list" we mean that if an ancestor and a descendant are in
54 the list, then so is at least one path connecting them.'''
59 the list, then so is at least one path connecting them.
60 '''
55 raise NotImplementedError()
61 raise NotImplementedError()
56
62
57 def externalize(self, ix):
63 def externalize(self, ix):
58 '''return a list of (or set if given a set) of node ids'''
64 '''return a list of (or set if given a set) of node ids'''
59 return self._externalize(ix)
65 return self._externalize(ix)
60
66
61 def externalizeall(self, ixs):
67 def externalizeall(self, ixs):
62 '''return a list of (or set if given a set) of node ids'''
68 '''return a list of (or set if given a set) of node ids'''
63 ids = self._externalizeall(ixs)
69 ids = self._externalizeall(ixs)
64 if isinstance(ixs, set):
70 if isinstance(ixs, set):
65 return set(ids)
71 return set(ids)
66 return list(ids)
72 return list(ids)
67
73
68 def internalize(self, id):
74 def internalize(self, id):
69 '''return a list of (or set if given a set) of node ixs'''
75 '''return a list of (or set if given a set) of node ixs'''
70 return self._internalize(id)
76 return self._internalize(id)
71
77
72 def internalizeall(self, ids, filterunknown=False):
78 def internalizeall(self, ids, filterunknown=False):
73 '''return a list of (or set if given a set) of node ids'''
79 '''return a list of (or set if given a set) of node ids'''
74 ixs = self._internalizeall(ids, filterunknown)
80 ixs = self._internalizeall(ids, filterunknown)
75 if isinstance(ids, set):
81 if isinstance(ids, set):
76 return set(ixs)
82 return set(ixs)
77 return list(ixs)
83 return list(ixs)
78
84
79
85
80 class genericdag(basedag):
86 class genericdag(basedag):
81 '''generic implementations for DAGs'''
87 '''generic implementations for DAGs'''
82
88
83 def ancestorset(self, starts, stops=None):
89 def ancestorset(self, starts, stops=None):
84 stops = stops and set(stops) or set()
90 stops = stops and set(stops) or set()
85 seen = set()
91 seen = set()
86 pending = list(starts)
92 pending = list(starts)
87 while pending:
93 while pending:
88 n = pending.pop()
94 n = pending.pop()
89 if n not in seen and n not in stops:
95 if n not in seen and n not in stops:
90 seen.add(n)
96 seen.add(n)
91 pending.extend(self.parents(n))
97 pending.extend(self.parents(n))
92 return seen
98 return seen
93
99
94 def headsetofconnecteds(self, ixs):
100 def headsetofconnecteds(self, ixs):
95 hds = set(ixs)
101 hds = set(ixs)
96 if not hds:
102 if not hds:
97 return hds
103 return hds
98 for n in ixs:
104 for n in ixs:
99 for p in self.parents(n):
105 for p in self.parents(n):
100 hds.discard(p)
106 hds.discard(p)
101 assert hds
107 assert hds
102 return hds
108 return hds
103
109
104
110
105 class revlogbaseddag(basedag):
111 class revlogbaseddag(basedag):
106 '''generic dag interface to a revlog'''
112 '''generic dag interface to a revlog'''
107
113
108 def __init__(self, revlog, nodeset):
114 def __init__(self, revlog, nodeset):
109 basedag.__init__(self)
115 basedag.__init__(self)
110 self._revlog = revlog
116 self._revlog = revlog
111 self._heads = None
117 self._heads = None
112 self._nodeset = nodeset
118 self._nodeset = nodeset
113
119
114 def nodeset(self):
120 def nodeset(self):
115 return self._nodeset
121 return self._nodeset
116
122
117 def heads(self):
123 def heads(self):
118 if self._heads is None:
124 if self._heads is None:
119 self._heads = self._getheads()
125 self._heads = self._getheads()
120 return self._heads
126 return self._heads
121
127
122 def _externalize(self, ix):
128 def _externalize(self, ix):
123 return self._revlog.index[ix][7]
129 return self._revlog.index[ix][7]
124 def _externalizeall(self, ixs):
130 def _externalizeall(self, ixs):
125 idx = self._revlog.index
131 idx = self._revlog.index
126 return [idx[i][7] for i in ixs]
132 return [idx[i][7] for i in ixs]
127
133
128 def _internalize(self, id):
134 def _internalize(self, id):
129 ix = self._revlog.rev(id)
135 ix = self._revlog.rev(id)
130 if ix == nullrev:
136 if ix == nullrev:
131 raise LookupError(id, self._revlog.indexfile, _('nullid'))
137 raise LookupError(id, self._revlog.indexfile, _('nullid'))
132 return ix
138 return ix
133 def _internalizeall(self, ids, filterunknown):
139 def _internalizeall(self, ids, filterunknown):
134 rl = self._revlog
140 rl = self._revlog
135 if filterunknown:
141 if filterunknown:
136 return [r for r in map(rl.nodemap.get, ids)
142 return [r for r in map(rl.nodemap.get, ids)
137 if r is not None and r != nullrev]
143 if r is not None and r != nullrev]
138 return map(self._internalize, ids)
144 return map(self._internalize, ids)
139
145
140
146
141 class revlogdag(revlogbaseddag):
147 class revlogdag(revlogbaseddag):
142 '''dag interface to a revlog'''
148 '''dag interface to a revlog'''
143
149
144 def __init__(self, revlog):
150 def __init__(self, revlog):
145 revlogbaseddag.__init__(self, revlog, set(xrange(len(revlog))))
151 revlogbaseddag.__init__(self, revlog, set(xrange(len(revlog))))
146
152
147 def _getheads(self):
153 def _getheads(self):
148 return [r for r in self._revlog.headrevs() if r != nullrev]
154 return [r for r in self._revlog.headrevs() if r != nullrev]
149
155
150 def parents(self, ix):
156 def parents(self, ix):
151 rlog = self._revlog
157 rlog = self._revlog
152 idx = rlog.index
158 idx = rlog.index
153 revdata = idx[ix]
159 revdata = idx[ix]
154 prev = revdata[5]
160 prev = revdata[5]
155 if prev != nullrev:
161 if prev != nullrev:
156 prev2 = revdata[6]
162 prev2 = revdata[6]
157 if prev2 == nullrev:
163 if prev2 == nullrev:
158 return [prev]
164 return [prev]
159 return [prev, prev2]
165 return [prev, prev2]
160 prev2 = revdata[6]
166 prev2 = revdata[6]
161 if prev2 != nullrev:
167 if prev2 != nullrev:
162 return [prev2]
168 return [prev2]
163 return []
169 return []
164
170
165 def inverse(self):
171 def inverse(self):
166 if self._inverse is None:
172 if self._inverse is None:
167 self._inverse = inverserevlogdag(self)
173 self._inverse = inverserevlogdag(self)
168 return self._inverse
174 return self._inverse
169
175
170 def ancestorset(self, starts, stops=None):
176 def ancestorset(self, starts, stops=None):
171 rlog = self._revlog
177 rlog = self._revlog
172 idx = rlog.index
178 idx = rlog.index
173 stops = stops and set(stops) or set()
179 stops = stops and set(stops) or set()
174 seen = set()
180 seen = set()
175 pending = list(starts)
181 pending = list(starts)
176 while pending:
182 while pending:
177 rev = pending.pop()
183 rev = pending.pop()
178 if rev not in seen and rev not in stops:
184 if rev not in seen and rev not in stops:
179 seen.add(rev)
185 seen.add(rev)
180 revdata = idx[rev]
186 revdata = idx[rev]
181 for i in [5, 6]:
187 for i in [5, 6]:
182 prev = revdata[i]
188 prev = revdata[i]
183 if prev != nullrev:
189 if prev != nullrev:
184 pending.append(prev)
190 pending.append(prev)
185 return seen
191 return seen
186
192
187 def headsetofconnecteds(self, ixs):
193 def headsetofconnecteds(self, ixs):
188 if not ixs:
194 if not ixs:
189 return set()
195 return set()
190 rlog = self._revlog
196 rlog = self._revlog
191 idx = rlog.index
197 idx = rlog.index
192 headrevs = set(ixs)
198 headrevs = set(ixs)
193 for rev in ixs:
199 for rev in ixs:
194 revdata = idx[rev]
200 revdata = idx[rev]
195 for i in [5, 6]:
201 for i in [5, 6]:
196 prev = revdata[i]
202 prev = revdata[i]
197 if prev != nullrev:
203 if prev != nullrev:
198 headrevs.discard(prev)
204 headrevs.discard(prev)
199 assert headrevs
205 assert headrevs
200 return headrevs
206 return headrevs
201
207
202
208
203 class inverserevlogdag(revlogbaseddag, genericdag):
209 class inverserevlogdag(revlogbaseddag, genericdag):
204 '''inverse of an existing revlog dag; see revlogdag.inverse()'''
210 '''inverse of an existing revlog dag; see revlogdag.inverse()'''
205
211
206 def __init__(self, orig):
212 def __init__(self, orig):
207 revlogbaseddag.__init__(self, orig._revlog, orig._nodeset)
213 revlogbaseddag.__init__(self, orig._revlog, orig._nodeset)
208 self._orig = orig
214 self._orig = orig
209 self._children = {}
215 self._children = {}
210 self._roots = []
216 self._roots = []
211 self._walkfrom = len(self._revlog) - 1
217 self._walkfrom = len(self._revlog) - 1
212
218
213 def _walkto(self, walkto):
219 def _walkto(self, walkto):
214 rev = self._walkfrom
220 rev = self._walkfrom
215 cs = self._children
221 cs = self._children
216 roots = self._roots
222 roots = self._roots
217 idx = self._revlog.index
223 idx = self._revlog.index
218 while rev >= walkto:
224 while rev >= walkto:
219 data = idx[rev]
225 data = idx[rev]
220 isroot = True
226 isroot = True
221 for prev in [data[5], data[6]]: # parent revs
227 for prev in [data[5], data[6]]: # parent revs
222 if prev != nullrev:
228 if prev != nullrev:
223 cs.setdefault(prev, []).append(rev)
229 cs.setdefault(prev, []).append(rev)
224 isroot = False
230 isroot = False
225 if isroot:
231 if isroot:
226 roots.append(rev)
232 roots.append(rev)
227 rev -= 1
233 rev -= 1
228 self._walkfrom = rev - 1
234 self._walkfrom = rev - 1
229
235
230 def _getheads(self):
236 def _getheads(self):
231 self._walkto(nullrev)
237 self._walkto(nullrev)
232 return self._roots
238 return self._roots
233
239
234 def parents(self, ix):
240 def parents(self, ix):
235 if ix is None:
241 if ix is None:
236 return []
242 return []
237 if ix <= self._walkfrom:
243 if ix <= self._walkfrom:
238 self._walkto(ix)
244 self._walkto(ix)
239 return self._children.get(ix, [])
245 return self._children.get(ix, [])
240
246
241 def inverse(self):
247 def inverse(self):
242 return self._orig
248 return self._orig
@@ -1,178 +1,178 b''
1 # setdiscovery.py - improved discovery of common nodeset for mercurial
1 # setdiscovery.py - improved discovery of common nodeset for mercurial
2 #
2 #
3 # Copyright 2010 Benoit Boissinot <bboissin@gmail.com>
3 # Copyright 2010 Benoit Boissinot <bboissin@gmail.com>
4 # and Peter Arrenbrecht <peter@arrenbrecht.ch>
4 # and Peter Arrenbrecht <peter@arrenbrecht.ch>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from node import nullid
9 from node import nullid
10 from i18n import _
10 from i18n import _
11 import random, collections, util, dagutil
11 import random, collections, util, dagutil
12
12
13 def _updatesample(dag, nodes, sample, always, quicksamplesize=0):
13 def _updatesample(dag, nodes, sample, always, quicksamplesize=0):
14 # if nodes is empty we scan the entire graph
14 # if nodes is empty we scan the entire graph
15 if nodes:
15 if nodes:
16 heads = dag.headsetofconnecteds(nodes)
16 heads = dag.headsetofconnecteds(nodes)
17 else:
17 else:
18 heads = dag.heads()
18 heads = dag.heads()
19 dist = {}
19 dist = {}
20 visit = collections.deque(heads)
20 visit = collections.deque(heads)
21 seen = set()
21 seen = set()
22 factor = 1
22 factor = 1
23 while visit:
23 while visit:
24 curr = visit.popleft()
24 curr = visit.popleft()
25 if curr in seen:
25 if curr in seen:
26 continue
26 continue
27 d = dist.setdefault(curr, 1)
27 d = dist.setdefault(curr, 1)
28 if d > factor:
28 if d > factor:
29 factor *= 2
29 factor *= 2
30 if d == factor:
30 if d == factor:
31 if curr not in always: # need this check for the early exit below
31 if curr not in always: # need this check for the early exit below
32 sample.add(curr)
32 sample.add(curr)
33 if quicksamplesize and (len(sample) >= quicksamplesize):
33 if quicksamplesize and (len(sample) >= quicksamplesize):
34 return
34 return
35 seen.add(curr)
35 seen.add(curr)
36 for p in dag.parents(curr):
36 for p in dag.parents(curr):
37 if not nodes or p in nodes:
37 if not nodes or p in nodes:
38 dist.setdefault(p, d + 1)
38 dist.setdefault(p, d + 1)
39 visit.append(p)
39 visit.append(p)
40
40
41 def _setupsample(dag, nodes, size):
41 def _setupsample(dag, nodes, size):
42 if len(nodes) <= size:
42 if len(nodes) <= size:
43 return set(nodes), None, 0
43 return set(nodes), None, 0
44 always = set(dag.heads())
44 always = set(dag.heads())
45 desiredlen = size - len(always)
45 desiredlen = size - len(always)
46 if desiredlen <= 0:
46 if desiredlen <= 0:
47 # This could be bad if there are very many heads, all unknown to the
47 # This could be bad if there are very many heads, all unknown to the
48 # server. We're counting on long request support here.
48 # server. We're counting on long request support here.
49 return always, None, desiredlen
49 return always, None, desiredlen
50 return always, set(), desiredlen
50 return always, set(), desiredlen
51
51
52 def _takequicksample(dag, nodes, size, initial):
52 def _takequicksample(dag, nodes, size, initial):
53 always, sample, desiredlen = _setupsample(dag, nodes, size)
53 always, sample, desiredlen = _setupsample(dag, nodes, size)
54 if sample is None:
54 if sample is None:
55 return always
55 return always
56 if initial:
56 if initial:
57 fromset = None
57 fromset = None
58 else:
58 else:
59 fromset = nodes
59 fromset = nodes
60 _updatesample(dag, fromset, sample, always, quicksamplesize=desiredlen)
60 _updatesample(dag, fromset, sample, always, quicksamplesize=desiredlen)
61 sample.update(always)
61 sample.update(always)
62 return sample
62 return sample
63
63
64 def _takefullsample(dag, nodes, size):
64 def _takefullsample(dag, nodes, size):
65 always, sample, desiredlen = _setupsample(dag, nodes, size)
65 always, sample, desiredlen = _setupsample(dag, nodes, size)
66 if sample is None:
66 if sample is None:
67 return always
67 return always
68 # update from heads
68 # update from heads
69 _updatesample(dag, nodes, sample, always)
69 _updatesample(dag, nodes, sample, always)
70 # update from roots
70 # update from roots
71 _updatesample(dag.inverse(), nodes, sample, always)
71 _updatesample(dag.inverse(), nodes, sample, always)
72 assert sample
72 assert sample
73 if len(sample) > desiredlen:
73 if len(sample) > desiredlen:
74 sample = set(random.sample(sample, desiredlen))
74 sample = set(random.sample(sample, desiredlen))
75 elif len(sample) < desiredlen:
75 elif len(sample) < desiredlen:
76 more = desiredlen - len(sample)
76 more = desiredlen - len(sample)
77 sample.update(random.sample(list(nodes - sample - always), more))
77 sample.update(random.sample(list(nodes - sample - always), more))
78 sample.update(always)
78 sample.update(always)
79 return sample
79 return sample
80
80
81 def findcommonheads(ui, local, remote,
81 def findcommonheads(ui, local, remote,
82 initialsamplesize=100,
82 initialsamplesize=100,
83 fullsamplesize=200,
83 fullsamplesize=200,
84 abortwhenunrelated=True):
84 abortwhenunrelated=True):
85 '''Return a tuple (common, anyincoming, remoteheads) used to identify missing
85 '''Return a tuple (common, anyincoming, remoteheads) used to identify
86 nodes from or in remote.
86 missing nodes from or in remote.
87
87
88 shortcutlocal determines whether we try use direct access to localrepo if
88 shortcutlocal determines whether we try use direct access to localrepo if
89 remote is actually local.
89 remote is actually local.
90 '''
90 '''
91 roundtrips = 0
91 roundtrips = 0
92 cl = local.changelog
92 cl = local.changelog
93 dag = dagutil.revlogdag(cl)
93 dag = dagutil.revlogdag(cl)
94 nodes = dag.nodeset()
94 nodes = dag.nodeset()
95
95
96 # early exit if we know all the specified server heads already
96 # early exit if we know all the specified server heads already
97 ui.debug("query 1; heads\n")
97 ui.debug("query 1; heads\n")
98 roundtrips += 1
98 roundtrips += 1
99 srvheadhashes = remote.heads()
99 srvheadhashes = remote.heads()
100
100
101 ## TODO We might want to request an additional random sample of the server's
101 ## TODO We might want to request an additional random sample of the server's
102 ## nodes batched with the heads query here.
102 ## nodes batched with the heads query here.
103
103
104 if cl.tip() == nullid:
104 if cl.tip() == nullid:
105 if srvheadhashes != [nullid]:
105 if srvheadhashes != [nullid]:
106 return [nullid], True, srvheadhashes
106 return [nullid], True, srvheadhashes
107 return [nullid], False, []
107 return [nullid], False, []
108
108
109 # start actual discovery (we note this before the next "if" for compatibility
109 # start actual discovery (we note this before the next "if" for
110 # reasons)
110 # compatibility reasons)
111 ui.status(_("searching for changes\n"))
111 ui.status(_("searching for changes\n"))
112
112
113 srvheads = dag.internalizeall(srvheadhashes, filterunknown=True)
113 srvheads = dag.internalizeall(srvheadhashes, filterunknown=True)
114 if len(srvheads) == len(srvheadhashes):
114 if len(srvheads) == len(srvheadhashes):
115 ui.note("all remote heads known locally\n")
115 ui.note("all remote heads known locally\n")
116 return (srvheadhashes, False, srvheadhashes,)
116 return (srvheadhashes, False, srvheadhashes,)
117
117
118 # full blown discovery
118 # full blown discovery
119 undecided = nodes # own nodes where I don't know if the server knows them
119 undecided = nodes # own nodes where I don't know if the server knows them
120 common = set() # own nodes I know we both know
120 common = set() # own nodes I know we both know
121 missing = set() # own nodes I know the server lacks
121 missing = set() # own nodes I know the server lacks
122
122
123 # treat remote heads as a first implicit sample response
123 # treat remote heads as a first implicit sample response
124 common.update(dag.ancestorset(srvheads))
124 common.update(dag.ancestorset(srvheads))
125 undecided.difference_update(common)
125 undecided.difference_update(common)
126 # use cheapish initial sample
126 # use cheapish initial sample
127 if common:
127 if common:
128 ui.debug("taking initial sample\n")
128 ui.debug("taking initial sample\n")
129 sample = _takefullsample(dag, undecided, size=fullsamplesize)
129 sample = _takefullsample(dag, undecided, size=fullsamplesize)
130 else:
130 else:
131 ui.debug("taking quick initial sample\n")
131 ui.debug("taking quick initial sample\n")
132 sample = _takequicksample(dag, nodes, size=initialsamplesize,
132 sample = _takequicksample(dag, nodes, size=initialsamplesize,
133 initial=True)
133 initial=True)
134
134
135 roundtrips += 1
135 roundtrips += 1
136 ui.progress(_('searching'), roundtrips, unit=_('queries'))
136 ui.progress(_('searching'), roundtrips, unit=_('queries'))
137 ui.debug("query %i; still undecided: %i, sample size is: %i\n"
137 ui.debug("query %i; still undecided: %i, sample size is: %i\n"
138 % (roundtrips, len(undecided), len(sample)))
138 % (roundtrips, len(undecided), len(sample)))
139 # indices between sample and externalized version must match
139 # indices between sample and externalized version must match
140 sample = list(sample)
140 sample = list(sample)
141 yesno = remote.known(dag.externalizeall(sample))
141 yesno = remote.known(dag.externalizeall(sample))
142
142
143 while undecided:
143 while undecided:
144 commoninsample = set(n for i, n in enumerate(sample) if yesno[i])
144 commoninsample = set(n for i, n in enumerate(sample) if yesno[i])
145 common.update(dag.ancestorset(commoninsample, common))
145 common.update(dag.ancestorset(commoninsample, common))
146
146
147 missinginsample = [n for i, n in enumerate(sample) if not yesno[i]]
147 missinginsample = [n for i, n in enumerate(sample) if not yesno[i]]
148 missing.update(dag.descendantset(missinginsample, missing))
148 missing.update(dag.descendantset(missinginsample, missing))
149
149
150 undecided.difference_update(missing)
150 undecided.difference_update(missing)
151 undecided.difference_update(common)
151 undecided.difference_update(common)
152
152
153 if not undecided:
153 if not undecided:
154 break
154 break
155
155
156 ui.note("sampling from both directions\n")
156 ui.note("sampling from both directions\n")
157 sample = _takefullsample(dag, undecided, size=fullsamplesize)
157 sample = _takefullsample(dag, undecided, size=fullsamplesize)
158
158
159 roundtrips += 1
159 roundtrips += 1
160 ui.progress(_('searching'), roundtrips, unit=_('queries'))
160 ui.progress(_('searching'), roundtrips, unit=_('queries'))
161 ui.debug("query %i; still undecided: %i, sample size is: %i\n"
161 ui.debug("query %i; still undecided: %i, sample size is: %i\n"
162 % (roundtrips, len(undecided), len(sample)))
162 % (roundtrips, len(undecided), len(sample)))
163 # indices between sample and externalized version must match
163 # indices between sample and externalized version must match
164 sample = list(sample)
164 sample = list(sample)
165 yesno = remote.known(dag.externalizeall(sample))
165 yesno = remote.known(dag.externalizeall(sample))
166
166
167 result = dag.headsetofconnecteds(common)
167 result = dag.headsetofconnecteds(common)
168 ui.progress(_('searching'), None)
168 ui.progress(_('searching'), None)
169 ui.debug("%d total queries\n" % roundtrips)
169 ui.debug("%d total queries\n" % roundtrips)
170
170
171 if not result and srvheadhashes != [nullid]:
171 if not result and srvheadhashes != [nullid]:
172 if abortwhenunrelated:
172 if abortwhenunrelated:
173 raise util.Abort(_("repository is unrelated"))
173 raise util.Abort(_("repository is unrelated"))
174 else:
174 else:
175 ui.warn(_("warning: repository is unrelated\n"))
175 ui.warn(_("warning: repository is unrelated\n"))
176 return (set([nullid]), True, srvheadhashes,)
176 return (set([nullid]), True, srvheadhashes,)
177
177
178 return (dag.externalizeall(result), True, srvheadhashes,)
178 return (dag.externalizeall(result), True, srvheadhashes,)
General Comments 0
You need to be logged in to leave comments. Login now