comparison mercurial/copies.py @ 43199:069cbbb53cdf

copies: drop the findlimit logic We don't use the limit anymore so we should stop computing that limit. I did not bother measuring the potential performance gain. I am assuming that not running any code will be faster that doing some computation and not using the result.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Thu, 10 Oct 2019 17:18:46 +0200
parents c16fe77e340a
children 30570a056fa8
comparison
equal deleted inserted replaced
43198:c16fe77e340a 43199:069cbbb53cdf
26 ) 26 )
27 27
28 from .revlogutils import sidedata as sidedatamod 28 from .revlogutils import sidedata as sidedatamod
29 29
30 from .utils import stringutil 30 from .utils import stringutil
31
32
33 def _findlimit(repo, ctxa, ctxb):
34 """
35 Find the last revision that needs to be checked to ensure that a full
36 transitive closure for file copies can be properly calculated.
37 Generally, this means finding the earliest revision number that's an
38 ancestor of a or b but not both, except when a or b is a direct descendent
39 of the other, in which case we can return the minimum revnum of a and b.
40 """
41
42 # basic idea:
43 # - mark a and b with different sides
44 # - if a parent's children are all on the same side, the parent is
45 # on that side, otherwise it is on no side
46 # - walk the graph in topological order with the help of a heap;
47 # - add unseen parents to side map
48 # - clear side of any parent that has children on different sides
49 # - track number of interesting revs that might still be on a side
50 # - track the lowest interesting rev seen
51 # - quit when interesting revs is zero
52
53 cl = repo.changelog
54 wdirparents = None
55 a = ctxa.rev()
56 b = ctxb.rev()
57 if a is None:
58 wdirparents = (ctxa.p1(), ctxa.p2())
59 a = node.wdirrev
60 if b is None:
61 assert not wdirparents
62 wdirparents = (ctxb.p1(), ctxb.p2())
63 b = node.wdirrev
64
65 side = {a: -1, b: 1}
66 visit = [-a, -b]
67 heapq.heapify(visit)
68 interesting = len(visit)
69 limit = node.wdirrev
70
71 while interesting:
72 r = -(heapq.heappop(visit))
73 if r == node.wdirrev:
74 parents = [pctx.rev() for pctx in wdirparents]
75 else:
76 parents = cl.parentrevs(r)
77 if parents[1] == node.nullrev:
78 parents = parents[:1]
79 for p in parents:
80 if p not in side:
81 # first time we see p; add it to visit
82 side[p] = side[r]
83 if side[p]:
84 interesting += 1
85 heapq.heappush(visit, -p)
86 elif side[p] and side[p] != side[r]:
87 # p was interesting but now we know better
88 side[p] = 0
89 interesting -= 1
90 if side[r]:
91 limit = r # lowest rev visited
92 interesting -= 1
93
94 # Consider the following flow (see test-commit-amend.t under issue4405):
95 # 1/ File 'a0' committed
96 # 2/ File renamed from 'a0' to 'a1' in a new commit (call it 'a1')
97 # 3/ Move back to first commit
98 # 4/ Create a new commit via revert to contents of 'a1' (call it 'a1-amend')
99 # 5/ Rename file from 'a1' to 'a2' and commit --amend 'a1-msg'
100 #
101 # During the amend in step five, we will be in this state:
102 #
103 # @ 3 temporary amend commit for a1-amend
104 # |
105 # o 2 a1-amend
106 # |
107 # | o 1 a1
108 # |/
109 # o 0 a0
110 #
111 # When _findlimit is called, a and b are revs 3 and 0, so limit will be 2,
112 # yet the filelog has the copy information in rev 1 and we will not look
113 # back far enough unless we also look at the a and b as candidates.
114 # This only occurs when a is a descendent of b or visa-versa.
115 return min(limit, a, b)
116 31
117 32
118 def _filter(src, dst, t): 33 def _filter(src, dst, t):
119 """filters out invalid copies after chaining""" 34 """filters out invalid copies after chaining"""
120 35
158 else: 73 else:
159 t[k] = v 74 t[k] = v
160 return t 75 return t
161 76
162 77
163 def _tracefile(fctx, am, basemf, limit): 78 def _tracefile(fctx, am, basemf):
164 """return file context that is the ancestor of fctx present in ancestor 79 """return file context that is the ancestor of fctx present in ancestor
165 manifest am 80 manifest am
166 81
167 Note: we used to try and stop after a given limit, however checking if that 82 Note: we used to try and stop after a given limit, however checking if that
168 limit is reached turned out to be very expensive. we are better off 83 limit is reached turned out to be very expensive. we are better off
215 130
216 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies') 131 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies')
217 dbg = repo.ui.debug 132 dbg = repo.ui.debug
218 if debug: 133 if debug:
219 dbg(b'debug.copies: looking into rename from %s to %s\n' % (a, b)) 134 dbg(b'debug.copies: looking into rename from %s to %s\n' % (a, b))
220 limit = _findlimit(repo, a, b)
221 if debug:
222 dbg(b'debug.copies: search limit: %d\n' % limit)
223 am = a.manifest() 135 am = a.manifest()
224 basemf = None if base is None else base.manifest() 136 basemf = None if base is None else base.manifest()
225 137
226 # find where new files came from 138 # find where new files came from
227 # we currently don't try to find where old files went, too expensive 139 # we currently don't try to find where old files went, too expensive
251 fctx = b[f] 163 fctx = b[f]
252 fctx._ancestrycontext = ancestrycontext 164 fctx._ancestrycontext = ancestrycontext
253 165
254 if debug: 166 if debug:
255 start = util.timer() 167 start = util.timer()
256 opath = _tracefile(fctx, am, basemf, limit) 168 opath = _tracefile(fctx, am, basemf)
257 if opath: 169 if opath:
258 if debug: 170 if debug:
259 dbg(b'debug.copies: rename of: %s\n' % opath) 171 dbg(b'debug.copies: rename of: %s\n' % opath)
260 cm[f] = opath 172 cm[f] = opath
261 if debug: 173 if debug: