##// END OF EJS Templates
branchmap: make update a method
Pierre-Yves David -
r18131:f0eeb9b3 default
parent child Browse files
Show More
@@ -42,87 +42,6 b' def read(repo):'
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):
@@ -142,7 +61,7 b' def updatecache(repo):'
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
@@ -150,7 +69,7 b' def updatecache(repo):'
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):
@@ -171,3 +90,84 b' class branchcache(dict):'
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
@@ -196,7 +196,7 b' def _headssummary(repo, remote, outgoing'
196 newmap = branchmap.branchcache((branch, heads[1])
196 newmap = branchmap.branchcache((branch, heads[1])
197 for branch, heads in headssum.iteritems()
197 for branch, heads in headssum.iteritems()
198 if heads[0] is not None)
198 if heads[0] is not None)
199 branchmap.update(repo, newmap, missingctx)
199 newmap.update(repo, missingctx)
200 for branch, newheads in newmap.iteritems():
200 for branch, newheads in newmap.iteritems():
201 headssum[branch][1][:] = newheads
201 headssum[branch][1][:] = newheads
202 return headssum
202 return headssum
@@ -666,7 +666,7 b' class localrepository(object):'
666 if self.changelog.filteredrevs:
666 if self.changelog.filteredrevs:
667 # some changeset are excluded we can't use the cache
667 # some changeset are excluded we can't use the cache
668 bmap = branchmap.branchcache()
668 bmap = branchmap.branchcache()
669 branchmap.update(self, bmap, (self[r] for r in self))
669 bmap.update(self, (self[r] for r in self))
670 return bmap
670 return bmap
671 else:
671 else:
672 branchmap.updatecache(self)
672 branchmap.updatecache(self)
@@ -1437,7 +1437,7 b' class localrepository(object):'
1437 ctxgen = (self[node] for node in newheadnodes
1437 ctxgen = (self[node] for node in newheadnodes
1438 if self.changelog.hasnode(node))
1438 if self.changelog.hasnode(node))
1439 cache = self._branchcache
1439 cache = self._branchcache
1440 branchmap.update(self, cache, ctxgen)
1440 cache.update(self, ctxgen)
1441 cache.write(self)
1441 cache.write(self)
1442
1442
1443 # Ensure the persistent tag cache is updated. Doing it now
1443 # Ensure the persistent tag cache is updated. Doing it now
General Comments 0
You need to be logged in to leave comments. Login now