##// END OF EJS Templates
tree-discovery: fix the request debug output and progress location...
marmoute -
r50300:f64f6616 stable
parent child Browse files
Show More
@@ -1,205 +1,206 b''
1 # discovery.py - protocol changeset discovery functions
1 # discovery.py - protocol changeset discovery functions
2 #
2 #
3 # Copyright 2010 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2010 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 import collections
9 import collections
10
10
11 from .i18n import _
11 from .i18n import _
12 from .node import short
12 from .node import short
13 from . import (
13 from . import (
14 error,
14 error,
15 )
15 )
16
16
17
17
18 def findcommonincoming(repo, remote, heads=None, force=False, audit=None):
18 def findcommonincoming(repo, remote, heads=None, force=False, audit=None):
19 """Return a tuple (common, fetch, heads) used to identify the common
19 """Return a tuple (common, fetch, heads) used to identify the common
20 subset of nodes between repo and remote.
20 subset of nodes between repo and remote.
21
21
22 "common" is a list of (at least) the heads of the common subset.
22 "common" is a list of (at least) the heads of the common subset.
23 "fetch" is a list of roots of the nodes that would be incoming, to be
23 "fetch" is a list of roots of the nodes that would be incoming, to be
24 supplied to changegroupsubset.
24 supplied to changegroupsubset.
25 "heads" is either the supplied heads, or else the remote's heads.
25 "heads" is either the supplied heads, or else the remote's heads.
26 """
26 """
27
27
28 knownnode = repo.changelog.hasnode
28 knownnode = repo.changelog.hasnode
29 search = []
29 search = []
30 fetch = set()
30 fetch = set()
31 seen = set()
31 seen = set()
32 seenbranch = set()
32 seenbranch = set()
33 base = set()
33 base = set()
34
34
35 if not heads:
35 if not heads:
36 with remote.commandexecutor() as e:
36 with remote.commandexecutor() as e:
37 heads = e.callcommand(b'heads', {}).result()
37 heads = e.callcommand(b'heads', {}).result()
38
38
39 if audit is not None:
39 if audit is not None:
40 audit[b'total-roundtrips'] = 1
40 audit[b'total-roundtrips'] = 1
41 audit[b'total-roundtrips-heads'] = 1
41 audit[b'total-roundtrips-heads'] = 1
42 audit[b'total-roundtrips-branches'] = 0
42 audit[b'total-roundtrips-branches'] = 0
43 audit[b'total-roundtrips-between'] = 0
43 audit[b'total-roundtrips-between'] = 0
44 audit[b'total-queries'] = 0
44 audit[b'total-queries'] = 0
45 audit[b'total-queries-branches'] = 0
45 audit[b'total-queries-branches'] = 0
46 audit[b'total-queries-between'] = 0
46 audit[b'total-queries-between'] = 0
47
47
48 if repo.changelog.tip() == repo.nullid:
48 if repo.changelog.tip() == repo.nullid:
49 base.add(repo.nullid)
49 base.add(repo.nullid)
50 if heads != [repo.nullid]:
50 if heads != [repo.nullid]:
51 return [repo.nullid], [repo.nullid], list(heads)
51 return [repo.nullid], [repo.nullid], list(heads)
52 return [repo.nullid], [], heads
52 return [repo.nullid], [], heads
53
53
54 # assume we're closer to the tip than the root
54 # assume we're closer to the tip than the root
55 # and start by examining the heads
55 # and start by examining the heads
56 repo.ui.status(_(b"searching for changes\n"))
56 repo.ui.status(_(b"searching for changes\n"))
57
57
58 unknown = []
58 unknown = []
59 for h in heads:
59 for h in heads:
60 if not knownnode(h):
60 if not knownnode(h):
61 unknown.append(h)
61 unknown.append(h)
62 else:
62 else:
63 base.add(h)
63 base.add(h)
64
64
65 if not unknown:
65 if not unknown:
66 return list(base), [], list(heads)
66 return list(base), [], list(heads)
67
67
68 req = set(unknown)
68 req = set(unknown)
69 reqcnt = 0
69 reqcnt = 0
70 progress = repo.ui.makeprogress(_(b'searching'), unit=_(b'queries'))
70 progress = repo.ui.makeprogress(_(b'searching'), unit=_(b'queries'))
71
71
72 # search through remote branches
72 # search through remote branches
73 # a 'branch' here is a linear segment of history, with four parts:
73 # a 'branch' here is a linear segment of history, with four parts:
74 # head, root, first parent, second parent
74 # head, root, first parent, second parent
75 # (a branch always has two parents (or none) by definition)
75 # (a branch always has two parents (or none) by definition)
76 with remote.commandexecutor() as e:
76 with remote.commandexecutor() as e:
77 if audit is not None:
77 if audit is not None:
78 audit[b'total-queries'] += len(unknown)
78 audit[b'total-queries'] += len(unknown)
79 audit[b'total-queries-branches'] += len(unknown)
79 audit[b'total-queries-branches'] += len(unknown)
80 audit[b'total-roundtrips'] += 1
80 audit[b'total-roundtrips'] += 1
81 audit[b'total-roundtrips-branches'] += 1
81 audit[b'total-roundtrips-branches'] += 1
82 branches = e.callcommand(b'branches', {b'nodes': unknown}).result()
82 branches = e.callcommand(b'branches', {b'nodes': unknown}).result()
83
83
84 unknown = collections.deque(branches)
84 unknown = collections.deque(branches)
85 while unknown:
85 while unknown:
86 r = []
86 r = []
87 while unknown:
87 while unknown:
88 n = unknown.popleft()
88 n = unknown.popleft()
89 if n[0] in seen:
89 if n[0] in seen:
90 continue
90 continue
91
91
92 repo.ui.debug(b"examining %s:%s\n" % (short(n[0]), short(n[1])))
92 repo.ui.debug(b"examining %s:%s\n" % (short(n[0]), short(n[1])))
93 if n[0] == repo.nullid: # found the end of the branch
93 if n[0] == repo.nullid: # found the end of the branch
94 pass
94 pass
95 elif n in seenbranch:
95 elif n in seenbranch:
96 repo.ui.debug(b"branch already found\n")
96 repo.ui.debug(b"branch already found\n")
97 continue
97 continue
98 elif n[1] and knownnode(n[1]): # do we know the base?
98 elif n[1] and knownnode(n[1]): # do we know the base?
99 repo.ui.debug(
99 repo.ui.debug(
100 b"found incomplete branch %s:%s\n"
100 b"found incomplete branch %s:%s\n"
101 % (short(n[0]), short(n[1]))
101 % (short(n[0]), short(n[1]))
102 )
102 )
103 search.append(n[0:2]) # schedule branch range for scanning
103 search.append(n[0:2]) # schedule branch range for scanning
104 seenbranch.add(n)
104 seenbranch.add(n)
105 else:
105 else:
106 if n[1] not in seen and n[1] not in fetch:
106 if n[1] not in seen and n[1] not in fetch:
107 if knownnode(n[2]) and knownnode(n[3]):
107 if knownnode(n[2]) and knownnode(n[3]):
108 repo.ui.debug(b"found new changeset %s\n" % short(n[1]))
108 repo.ui.debug(b"found new changeset %s\n" % short(n[1]))
109 fetch.add(n[1]) # earliest unknown
109 fetch.add(n[1]) # earliest unknown
110 for p in n[2:4]:
110 for p in n[2:4]:
111 if knownnode(p):
111 if knownnode(p):
112 base.add(p) # latest known
112 base.add(p) # latest known
113
113
114 for p in n[2:4]:
114 for p in n[2:4]:
115 if p not in req and not knownnode(p):
115 if p not in req and not knownnode(p):
116 r.append(p)
116 r.append(p)
117 req.add(p)
117 req.add(p)
118 seen.add(n[0])
118 seen.add(n[0])
119
119
120 if r:
120 if r:
121 reqcnt += 1
122 progress.increment()
123 repo.ui.debug(
124 b"request %d: %s\n" % (reqcnt, b" ".join(map(short, r)))
125 )
126 for p in range(0, len(r), 10):
121 for p in range(0, len(r), 10):
122 reqcnt += 1
123 progress.increment()
124 if repo.ui.debugflag:
125 msg = b"request %d: %s\n"
126 msg %= (reqcnt, b" ".join(map(short, r)))
127 repo.ui.debug(msg)
127 with remote.commandexecutor() as e:
128 with remote.commandexecutor() as e:
128 subset = r[p : p + 10]
129 subset = r[p : p + 10]
129 if audit is not None:
130 if audit is not None:
130 audit[b'total-queries'] += len(subset)
131 audit[b'total-queries'] += len(subset)
131 audit[b'total-queries-branches'] += len(subset)
132 audit[b'total-queries-branches'] += len(subset)
132 audit[b'total-roundtrips'] += 1
133 audit[b'total-roundtrips'] += 1
133 audit[b'total-roundtrips-branches'] += 1
134 audit[b'total-roundtrips-branches'] += 1
134 branches = e.callcommand(
135 branches = e.callcommand(
135 b'branches',
136 b'branches',
136 {
137 {
137 b'nodes': subset,
138 b'nodes': subset,
138 },
139 },
139 ).result()
140 ).result()
140
141
141 for b in branches:
142 for b in branches:
142 repo.ui.debug(
143 repo.ui.debug(
143 b"received %s:%s\n" % (short(b[0]), short(b[1]))
144 b"received %s:%s\n" % (short(b[0]), short(b[1]))
144 )
145 )
145 unknown.append(b)
146 unknown.append(b)
146
147
147 # do binary search on the branches we found
148 # do binary search on the branches we found
148 while search:
149 while search:
149 newsearch = []
150 newsearch = []
150 reqcnt += 1
151 reqcnt += 1
151 progress.increment()
152 progress.increment()
152
153
153 with remote.commandexecutor() as e:
154 with remote.commandexecutor() as e:
154 if audit is not None:
155 if audit is not None:
155 audit[b'total-queries'] += len(search)
156 audit[b'total-queries'] += len(search)
156 audit[b'total-queries-between'] += len(search)
157 audit[b'total-queries-between'] += len(search)
157 audit[b'total-roundtrips'] += 1
158 audit[b'total-roundtrips'] += 1
158 audit[b'total-roundtrips-between'] += 1
159 audit[b'total-roundtrips-between'] += 1
159 between = e.callcommand(b'between', {b'pairs': search}).result()
160 between = e.callcommand(b'between', {b'pairs': search}).result()
160
161
161 for n, l in zip(search, between):
162 for n, l in zip(search, between):
162 l.append(n[1])
163 l.append(n[1])
163 p = n[0]
164 p = n[0]
164 f = 1
165 f = 1
165 for i in l:
166 for i in l:
166 repo.ui.debug(b"narrowing %d:%d %s\n" % (f, len(l), short(i)))
167 repo.ui.debug(b"narrowing %d:%d %s\n" % (f, len(l), short(i)))
167 if knownnode(i):
168 if knownnode(i):
168 if f <= 2:
169 if f <= 2:
169 repo.ui.debug(
170 repo.ui.debug(
170 b"found new branch changeset %s\n" % short(p)
171 b"found new branch changeset %s\n" % short(p)
171 )
172 )
172 fetch.add(p)
173 fetch.add(p)
173 base.add(i)
174 base.add(i)
174 else:
175 else:
175 repo.ui.debug(
176 repo.ui.debug(
176 b"narrowed branch search to %s:%s\n"
177 b"narrowed branch search to %s:%s\n"
177 % (short(p), short(i))
178 % (short(p), short(i))
178 )
179 )
179 newsearch.append((p, i))
180 newsearch.append((p, i))
180 break
181 break
181 p, f = i, f * 2
182 p, f = i, f * 2
182 search = newsearch
183 search = newsearch
183
184
184 # sanity check our fetch list
185 # sanity check our fetch list
185 for f in fetch:
186 for f in fetch:
186 if knownnode(f):
187 if knownnode(f):
187 raise error.RepoError(_(b"already have changeset ") + short(f[:4]))
188 raise error.RepoError(_(b"already have changeset ") + short(f[:4]))
188
189
189 base = list(base)
190 base = list(base)
190 if base == [repo.nullid]:
191 if base == [repo.nullid]:
191 if force:
192 if force:
192 repo.ui.warn(_(b"warning: repository is unrelated\n"))
193 repo.ui.warn(_(b"warning: repository is unrelated\n"))
193 else:
194 else:
194 raise error.Abort(_(b"repository is unrelated"))
195 raise error.Abort(_(b"repository is unrelated"))
195
196
196 repo.ui.debug(
197 repo.ui.debug(
197 b"found new changesets starting at "
198 b"found new changesets starting at "
198 + b" ".join([short(f) for f in fetch])
199 + b" ".join([short(f) for f in fetch])
199 + b"\n"
200 + b"\n"
200 )
201 )
201
202
202 progress.complete()
203 progress.complete()
203 repo.ui.debug(b"%d total queries\n" % reqcnt)
204 repo.ui.debug(b"%d total queries\n" % reqcnt)
204
205
205 return base, list(fetch), heads
206 return base, list(fetch), heads
General Comments 0
You need to be logged in to leave comments. Login now