Mercurial > public > mercurial-scm > hg
comparison mercurial/branchmap.py @ 18131:f0eeb9b3444a
branchmap: make update a method
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Sat, 22 Dec 2012 17:08:15 +0100 |
parents | 1b05ffce47bd |
children | db25bf1dc828 |
comparison
equal
deleted
inserted
replaced
18130:1b05ffce47bd | 18131:f0eeb9b3444a |
---|---|
40 if repo.ui.debugflag: | 40 if repo.ui.debugflag: |
41 repo.ui.warn(str(inst), '\n') | 41 repo.ui.warn(str(inst), '\n') |
42 partial = branchcache() | 42 partial = branchcache() |
43 return partial | 43 return partial |
44 | 44 |
45 def update(repo, partial, ctxgen): | |
46 """Given a branchhead cache, partial, that may have extra nodes or be | |
47 missing heads, and a generator of nodes that are at least a superset of | |
48 heads missing, this function updates partial to be correct. | |
49 """ | |
50 cl = repo.changelog | |
51 # collect new branch entries | |
52 newbranches = {} | |
53 for c in ctxgen: | |
54 newbranches.setdefault(c.branch(), []).append(c.node()) | |
55 # if older branchheads are reachable from new ones, they aren't | |
56 # really branchheads. Note checking parents is insufficient: | |
57 # 1 (branch a) -> 2 (branch b) -> 3 (branch a) | |
58 for branch, newnodes in newbranches.iteritems(): | |
59 bheads = partial.setdefault(branch, []) | |
60 # Remove candidate heads that no longer are in the repo (e.g., as | |
61 # the result of a strip that just happened). Avoid using 'node in | |
62 # self' here because that dives down into branchcache code somewhat | |
63 # recursively. | |
64 bheadrevs = [cl.rev(node) for node in bheads | |
65 if cl.hasnode(node)] | |
66 newheadrevs = [cl.rev(node) for node in newnodes | |
67 if cl.hasnode(node)] | |
68 ctxisnew = bheadrevs and min(newheadrevs) > max(bheadrevs) | |
69 # Remove duplicates - nodes that are in newheadrevs and are already | |
70 # in bheadrevs. This can happen if you strip a node whose parent | |
71 # was already a head (because they're on different branches). | |
72 bheadrevs = sorted(set(bheadrevs).union(newheadrevs)) | |
73 | |
74 # Starting from tip means fewer passes over reachable. If we know | |
75 # the new candidates are not ancestors of existing heads, we don't | |
76 # have to examine ancestors of existing heads | |
77 if ctxisnew: | |
78 iterrevs = sorted(newheadrevs) | |
79 else: | |
80 iterrevs = list(bheadrevs) | |
81 | |
82 # This loop prunes out two kinds of heads - heads that are | |
83 # superseded by a head in newheadrevs, and newheadrevs that are not | |
84 # heads because an existing head is their descendant. | |
85 while iterrevs: | |
86 latest = iterrevs.pop() | |
87 if latest not in bheadrevs: | |
88 continue | |
89 ancestors = set(cl.ancestors([latest], | |
90 bheadrevs[0])) | |
91 if ancestors: | |
92 bheadrevs = [b for b in bheadrevs if b not in ancestors] | |
93 partial[branch] = [cl.node(rev) for rev in bheadrevs] | |
94 tiprev = max(bheadrevs) | |
95 if tiprev > partial.tiprev: | |
96 partial.tipnode = cl.node(tiprev) | |
97 partial.tiprev = tiprev | |
98 | |
99 | |
100 # There may be branches that cease to exist when the last commit in the | |
101 # branch was stripped. This code filters them out. Note that the | |
102 # branch that ceased to exist may not be in newbranches because | |
103 # newbranches is the set of candidate heads, which when you strip the | |
104 # last commit in a branch will be the parent branch. | |
105 droppednodes = [] | |
106 for branch in partial.keys(): | |
107 nodes = [head for head in partial[branch] | |
108 if cl.hasnode(head)] | |
109 if not nodes: | |
110 droppednodes.extend(nodes) | |
111 del partial[branch] | |
112 try: | |
113 node = cl.node(partial.tiprev) | |
114 except IndexError: | |
115 node = None | |
116 if ((partial.tipnode != node) | |
117 or (partial.tipnode in droppednodes)): | |
118 # cache key are not valid anymore | |
119 partial.tipnode = nullid | |
120 partial.tiprev = nullrev | |
121 for heads in partial.values(): | |
122 tiprev = max(cl.rev(node) for node in heads) | |
123 if tiprev > partial.tiprev: | |
124 partial.tipnode = cl.node(tiprev) | |
125 partial.tiprev = tiprev | |
126 | 45 |
127 | 46 |
128 def updatecache(repo): | 47 def updatecache(repo): |
129 repo = repo.unfiltered() # Until we get a smarter cache management | 48 repo = repo.unfiltered() # Until we get a smarter cache management |
130 cl = repo.changelog | 49 cl = repo.changelog |
140 # if partial.tiprev == catip: cache is already up to date | 59 # if partial.tiprev == catip: cache is already up to date |
141 # if partial.tiprev > catip: we have uncachable element in `partial` can't | 60 # if partial.tiprev > catip: we have uncachable element in `partial` can't |
142 # write on disk | 61 # write on disk |
143 if partial.tiprev < catip: | 62 if partial.tiprev < catip: |
144 ctxgen = (repo[r] for r in cl.revs(partial.tiprev + 1, catip)) | 63 ctxgen = (repo[r] for r in cl.revs(partial.tiprev + 1, catip)) |
145 update(repo, partial, ctxgen) | 64 partial.update(repo, ctxgen) |
146 partial.write(repo) | 65 partial.write(repo) |
147 # If cacheable tip were lower than actual tip, we need to update the | 66 # If cacheable tip were lower than actual tip, we need to update the |
148 # cache up to tip. This update (from cacheable to actual tip) is not | 67 # cache up to tip. This update (from cacheable to actual tip) is not |
149 # written to disk since it's not cacheable. | 68 # written to disk since it's not cacheable. |
150 tiprev = len(repo) - 1 | 69 tiprev = len(repo) - 1 |
151 if partial.tiprev < tiprev: | 70 if partial.tiprev < tiprev: |
152 ctxgen = (repo[r] for r in cl.revs(partial.tiprev + 1, tiprev)) | 71 ctxgen = (repo[r] for r in cl.revs(partial.tiprev + 1, tiprev)) |
153 update(repo, partial, ctxgen) | 72 partial.update(repo, ctxgen) |
154 repo._branchcache = partial | 73 repo._branchcache = partial |
155 | 74 |
156 class branchcache(dict): | 75 class branchcache(dict): |
157 """A dict like object that hold branches heads cache""" | 76 """A dict like object that hold branches heads cache""" |
158 | 77 |
169 for node in nodes: | 88 for node in nodes: |
170 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label))) | 89 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label))) |
171 f.close() | 90 f.close() |
172 except (IOError, OSError): | 91 except (IOError, OSError): |
173 pass | 92 pass |
93 | |
94 def update(self, repo, ctxgen): | |
95 """Given a branchhead cache, self, that may have extra nodes or be | |
96 missing heads, and a generator of nodes that are at least a superset of | |
97 heads missing, this function updates self to be correct. | |
98 """ | |
99 cl = repo.changelog | |
100 # collect new branch entries | |
101 newbranches = {} | |
102 for c in ctxgen: | |
103 newbranches.setdefault(c.branch(), []).append(c.node()) | |
104 # if older branchheads are reachable from new ones, they aren't | |
105 # really branchheads. Note checking parents is insufficient: | |
106 # 1 (branch a) -> 2 (branch b) -> 3 (branch a) | |
107 for branch, newnodes in newbranches.iteritems(): | |
108 bheads = self.setdefault(branch, []) | |
109 # Remove candidate heads that no longer are in the repo (e.g., as | |
110 # the result of a strip that just happened). Avoid using 'node in | |
111 # self' here because that dives down into branchcache code somewhat | |
112 # recursively. | |
113 bheadrevs = [cl.rev(node) for node in bheads | |
114 if cl.hasnode(node)] | |
115 newheadrevs = [cl.rev(node) for node in newnodes | |
116 if cl.hasnode(node)] | |
117 ctxisnew = bheadrevs and min(newheadrevs) > max(bheadrevs) | |
118 # Remove duplicates - nodes that are in newheadrevs and are already | |
119 # in bheadrevs. This can happen if you strip a node whose parent | |
120 # was already a head (because they're on different branches). | |
121 bheadrevs = sorted(set(bheadrevs).union(newheadrevs)) | |
122 | |
123 # Starting from tip means fewer passes over reachable. If we know | |
124 # the new candidates are not ancestors of existing heads, we don't | |
125 # have to examine ancestors of existing heads | |
126 if ctxisnew: | |
127 iterrevs = sorted(newheadrevs) | |
128 else: | |
129 iterrevs = list(bheadrevs) | |
130 | |
131 # This loop prunes out two kinds of heads - heads that are | |
132 # superseded by a head in newheadrevs, and newheadrevs that are not | |
133 # heads because an existing head is their descendant. | |
134 while iterrevs: | |
135 latest = iterrevs.pop() | |
136 if latest not in bheadrevs: | |
137 continue | |
138 ancestors = set(cl.ancestors([latest], | |
139 bheadrevs[0])) | |
140 if ancestors: | |
141 bheadrevs = [b for b in bheadrevs if b not in ancestors] | |
142 self[branch] = [cl.node(rev) for rev in bheadrevs] | |
143 tiprev = max(bheadrevs) | |
144 if tiprev > self.tiprev: | |
145 self.tipnode = cl.node(tiprev) | |
146 self.tiprev = tiprev | |
147 | |
148 # There may be branches that cease to exist when the last commit in the | |
149 # branch was stripped. This code filters them out. Note that the | |
150 # branch that ceased to exist may not be in newbranches because | |
151 # newbranches is the set of candidate heads, which when you strip the | |
152 # last commit in a branch will be the parent branch. | |
153 droppednodes = [] | |
154 for branch in self.keys(): | |
155 nodes = [head for head in self[branch] | |
156 if cl.hasnode(head)] | |
157 if not nodes: | |
158 droppednodes.extend(nodes) | |
159 del self[branch] | |
160 try: | |
161 node = cl.node(self.tiprev) | |
162 except IndexError: | |
163 node = None | |
164 if ((self.tipnode != node) | |
165 or (self.tipnode in droppednodes)): | |
166 # cache key are not valid anymore | |
167 self.tipnode = nullid | |
168 self.tiprev = nullrev | |
169 for heads in self.values(): | |
170 tiprev = max(cl.rev(node) for node in heads) | |
171 if tiprev > self.tiprev: | |
172 self.tipnode = cl.node(tiprev) | |
173 self.tiprev = tiprev |