##// END OF EJS Templates
phases: introduce phasecache...
Patrick Mezard -
r16657:b6081c2c default
parent child Browse files
Show More
@@ -883,7 +883,7 b' class queue(object):'
883 883 def finish(self, repo, revs):
884 884 # Manually trigger phase computation to ensure phasedefaults is
885 885 # executed before we remove the patches.
886 repo._phaserev
886 repo._phasecache
887 887 patches = self._revpatches(repo, sorted(revs))
888 888 qfinished = self._cleanup(patches, len(patches))
889 889 if qfinished and repo.ui.configbool('mq', 'secret', False):
@@ -4378,7 +4378,7 b' def phase(ui, repo, *revs, **opts):'
4378 4378 nodes = [ctx.node() for ctx in repo.set('%ld', revs)]
4379 4379 if not nodes:
4380 4380 raise util.Abort(_('empty revision set'))
4381 olddata = repo._phaserev[:]
4381 olddata = repo._phasecache.getphaserevs(repo)[:]
4382 4382 phases.advanceboundary(repo, targetphase, nodes)
4383 4383 if opts['force']:
4384 4384 phases.retractboundary(repo, targetphase, nodes)
@@ -4386,7 +4386,7 b' def phase(ui, repo, *revs, **opts):'
4386 4386 lock.release()
4387 4387 if olddata is not None:
4388 4388 changes = 0
4389 newdata = repo._phaserev
4389 newdata = repo._phasecache.getphaserevs(repo)
4390 4390 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4391 4391 rejected = [n for n in nodes
4392 4392 if newdata[repo[n].rev()] < targetphase]
@@ -191,12 +191,7 b' class changectx(object):'
191 191 def bookmarks(self):
192 192 return self._repo.nodebookmarks(self._node)
193 193 def phase(self):
194 if self._rev == -1:
195 return phases.public
196 if self._rev >= len(self._repo._phaserev):
197 # outdated cache
198 del self._repo._phaserev
199 return self._repo._phaserev[self._rev]
194 return self._repo._phasecache.phase(self._repo, self._rev)
200 195 def phasestr(self):
201 196 return phases.phasenames[self.phase()]
202 197 def mutable(self):
@@ -105,7 +105,7 b' def findcommonoutgoing(repo, other, only'
105 105 og.commonheads, _any, _hds = commoninc
106 106
107 107 # compute outgoing
108 if not repo._phaseroots[phases.secret]:
108 if not repo._phasecache.phaseroots[phases.secret]:
109 109 og.missingheads = onlyheads or repo.heads()
110 110 elif onlyheads is None:
111 111 # use visible heads as it should be cached
@@ -41,7 +41,6 b' class localrepository(repo.repository):'
41 41 self.wopener = scmutil.opener(self.root)
42 42 self.baseui = baseui
43 43 self.ui = baseui.copy()
44 self._dirtyphases = False
45 44 # A list of callback to shape the phase if no data were found.
46 45 # Callback are in the form: func(repo, roots) --> processed root.
47 46 # This list it to be filled by extension during repo setup
@@ -182,22 +181,8 b' class localrepository(repo.repository):'
182 181 bookmarks.write(self)
183 182
184 183 @storecache('phaseroots')
185 def _phaseroots(self):
186 phaseroots, self._dirtyphases = phases.readroots(
187 self, self._phasedefaults)
188 return phaseroots
189
190 @propertycache
191 def _phaserev(self):
192 cache = [phases.public] * len(self)
193 for phase in phases.trackedphases:
194 roots = map(self.changelog.rev, self._phaseroots[phase])
195 if roots:
196 for rev in roots:
197 cache[rev] = phase
198 for rev in self.changelog.descendants(*roots):
199 cache[rev] = phase
200 return cache
184 def _phasecache(self):
185 return phases.phasecache(self, self._phasedefaults)
201 186
202 187 @storecache('00changelog.i')
203 188 def changelog(self):
@@ -604,10 +589,11 b' class localrepository(repo.repository):'
604 589
605 590 def known(self, nodes):
606 591 nm = self.changelog.nodemap
592 pc = self._phasecache
607 593 result = []
608 594 for n in nodes:
609 595 r = nm.get(n)
610 resp = not (r is None or self._phaserev[r] >= phases.secret)
596 resp = not (r is None or pc.phase(self, r) >= phases.secret)
611 597 result.append(resp)
612 598 return result
613 599
@@ -863,7 +849,6 b' class localrepository(repo.repository):'
863 849 pass
864 850
865 851 delcache('_tagscache')
866 delcache('_phaserev')
867 852
868 853 self._branchcache = None # in UTF-8
869 854 self._branchcachetip = None
@@ -931,9 +916,8 b' class localrepository(repo.repository):'
931 916
932 917 def unlock():
933 918 self.store.write()
934 if self._dirtyphases:
935 phases.writeroots(self, self._phaseroots)
936 self._dirtyphases = False
919 if '_phasecache' in vars(self):
920 self._phasecache.write()
937 921 for k, ce in self._filecache.items():
938 922 if k == 'dirstate':
939 923 continue
@@ -99,7 +99,7 b' Note: old client behave as publish serve'
99 99 """
100 100
101 101 import errno
102 from node import nullid, bin, hex, short
102 from node import nullid, nullrev, bin, hex, short
103 103 from i18n import _
104 104
105 105 allphases = public, draft, secret = range(3)
@@ -124,7 +124,7 b' def _filterunknown(ui, changelog, phaser'
124 124 updated = True
125 125 return updated
126 126
127 def readroots(repo, phasedefaults=None):
127 def _readroots(repo, phasedefaults=None):
128 128 """Read phase roots from disk
129 129
130 130 phasedefaults is a list of fn(repo, roots) callable, which are
@@ -156,15 +156,51 b' def readroots(repo, phasedefaults=None):'
156 156 dirty = True
157 157 return roots, dirty
158 158
159 def writeroots(repo, phaseroots):
160 """Write phase roots from disk"""
161 f = repo.sopener('phaseroots', 'w', atomictemp=True)
162 try:
163 for phase, roots in enumerate(phaseroots):
164 for h in roots:
165 f.write('%i %s\n' % (phase, hex(h)))
166 finally:
167 f.close()
159 class phasecache(object):
160 def __init__(self, repo, phasedefaults):
161 self.phaseroots, self.dirty = _readroots(repo, phasedefaults)
162 self.opener = repo.sopener
163 self._phaserevs = None
164
165 def getphaserevs(self, repo, rebuild=False):
166 if rebuild or self._phaserevs is None:
167 revs = [public] * len(repo.changelog)
168 for phase in trackedphases:
169 roots = map(repo.changelog.rev, self.phaseroots[phase])
170 if roots:
171 for rev in roots:
172 revs[rev] = phase
173 for rev in repo.changelog.descendants(*roots):
174 revs[rev] = phase
175 self._phaserevs = revs
176 return self._phaserevs
177
178 def invalidatephaserevs(self):
179 self._phaserevs = None
180
181 def phase(self, repo, rev):
182 # We need a repo argument here to be able to build _phaserev
183 # if necessary. The repository instance is not stored in
184 # phasecache to avoid reference cycles. The changelog instance
185 # is not stored because it is a filecache() property and can
186 # be replaced without us being notified.
187 if rev == nullrev:
188 return public
189 if self._phaserevs is None or rev >= len(self._phaserevs):
190 self._phaserevs = self.getphaserevs(repo, rebuild=True)
191 return self._phaserevs[rev]
192
193 def write(self):
194 if not self.dirty:
195 return
196 f = self.opener('phaseroots', 'w', atomictemp=True)
197 try:
198 for phase, roots in enumerate(self.phaseroots):
199 for h in roots:
200 f.write('%i %s\n' % (phase, hex(h)))
201 finally:
202 f.close()
203 self.dirty = False
168 204
169 205 def advanceboundary(repo, targetphase, nodes):
170 206 """Add nodes to a phase changing other nodes phases if necessary.
@@ -173,6 +209,8 b' def advanceboundary(repo, targetphase, n'
173 209 in the target phase or kept in a *lower* phase.
174 210
175 211 Simplify boundary to contains phase roots only."""
212 phcache = repo._phasecache
213
176 214 delroots = [] # set of root deleted by this path
177 215 for phase in xrange(targetphase + 1, len(allphases)):
178 216 # filter nodes that are not in a compatible phase already
@@ -181,16 +219,15 b' def advanceboundary(repo, targetphase, n'
181 219 nodes = [n for n in nodes if repo[n].phase() >= phase]
182 220 if not nodes:
183 221 break # no roots to move anymore
184 roots = repo._phaseroots[phase]
222 roots = phcache.phaseroots[phase]
185 223 olds = roots.copy()
186 224 ctxs = list(repo.set('roots((%ln::) - (%ln::%ln))', olds, olds, nodes))
187 225 roots.clear()
188 226 roots.update(ctx.node() for ctx in ctxs)
189 227 if olds != roots:
190 228 # invalidate cache (we probably could be smarter here
191 if '_phaserev' in vars(repo):
192 del repo._phaserev
193 repo._dirtyphases = True
229 phcache.invalidatephaserevs()
230 phcache.dirty = True
194 231 # some roots may need to be declared for lower phases
195 232 delroots.extend(olds - roots)
196 233 # declare deleted root in the target phase
@@ -205,22 +242,23 b' def retractboundary(repo, targetphase, n'
205 242 in the target phase or kept in a *higher* phase.
206 243
207 244 Simplify boundary to contains phase roots only."""
208 currentroots = repo._phaseroots[targetphase]
245 phcache = repo._phasecache
246
247 currentroots = phcache.phaseroots[targetphase]
209 248 newroots = [n for n in nodes if repo[n].phase() < targetphase]
210 249 if newroots:
211 250 currentroots.update(newroots)
212 251 ctxs = repo.set('roots(%ln::)', currentroots)
213 252 currentroots.intersection_update(ctx.node() for ctx in ctxs)
214 if '_phaserev' in vars(repo):
215 del repo._phaserev
216 repo._dirtyphases = True
253 phcache.invalidatephaserevs()
254 phcache.dirty = True
217 255
218 256
219 257 def listphases(repo):
220 258 """List phases root for serialisation over pushkey"""
221 259 keys = {}
222 260 value = '%i' % draft
223 for root in repo._phaseroots[draft]:
261 for root in repo._phasecache.phaseroots[draft]:
224 262 keys[hex(root)] = value
225 263
226 264 if repo.ui.configbool('phases', 'publish', True):
@@ -263,7 +301,7 b' def pushphase(repo, nhex, oldphasestr, n'
263 301 def visibleheads(repo):
264 302 """return the set of visible head of this repo"""
265 303 # XXX we want a cache on this
266 sroots = repo._phaseroots[secret]
304 sroots = repo._phasecache.phaseroots[secret]
267 305 if sroots:
268 306 # XXX very slow revset. storing heads or secret "boundary" would help.
269 307 revset = repo.set('heads(not (%ln::))', sroots)
@@ -279,7 +317,7 b' def visiblebranchmap(repo):'
279 317 """return a branchmap for the visible set"""
280 318 # XXX Recomputing this data on the fly is very slow. We should build a
281 319 # XXX cached version while computin the standard branchmap version.
282 sroots = repo._phaseroots[secret]
320 sroots = repo._phasecache.phaseroots[secret]
283 321 if sroots:
284 322 vbranchmap = {}
285 323 for branch, nodes in repo.branchmap().iteritems():
@@ -463,7 +463,8 b' def draft(repo, subset, x):'
463 463 """``draft()``
464 464 Changeset in draft phase."""
465 465 getargs(x, 0, 0, _("draft takes no arguments"))
466 return [r for r in subset if repo._phaserev[r] == phases.draft]
466 pc = repo._phasecache
467 return [r for r in subset if pc.phase(repo, r) == phases.draft]
467 468
468 469 def filelog(repo, subset, x):
469 470 """``filelog(pattern)``
@@ -852,7 +853,8 b' def public(repo, subset, x):'
852 853 """``public()``
853 854 Changeset in public phase."""
854 855 getargs(x, 0, 0, _("public takes no arguments"))
855 return [r for r in subset if repo._phaserev[r] == phases.public]
856 pc = repo._phasecache
857 return [r for r in subset if pc.phase(repo, r) == phases.public]
856 858
857 859 def remote(repo, subset, x):
858 860 """``remote([id [,path]])``
@@ -1031,7 +1033,8 b' def secret(repo, subset, x):'
1031 1033 """``secret()``
1032 1034 Changeset in secret phase."""
1033 1035 getargs(x, 0, 0, _("secret takes no arguments"))
1034 return [r for r in subset if repo._phaserev[r] == phases.secret]
1036 pc = repo._phasecache
1037 return [r for r in subset if pc.phase(repo, r) == phases.secret]
1035 1038
1036 1039 def sort(repo, subset, x):
1037 1040 """``sort(set[, [-]key...])``
General Comments 0
You need to be logged in to leave comments. Login now