Show More
@@ -11,6 +11,7 b' import ancestor, mdiff, error, util, scm' | |||
|
11 | 11 | import copies |
|
12 | 12 | import match as matchmod |
|
13 | 13 | import os, errno, stat |
|
14 | import obsolete as obsmod | |
|
14 | 15 | |
|
15 | 16 | propertycache = util.propertycache |
|
16 | 17 | |
@@ -232,38 +233,15 b' class changectx(object):' | |||
|
232 | 233 | |
|
233 | 234 | def obsolete(self): |
|
234 | 235 | """True if the changeset is obsolete""" |
|
235 |
return |
|
|
236 | and self.phase() > phases.public) | |
|
236 | return self.rev() in obsmod.getobscache(self._repo, 'obsolete') | |
|
237 | 237 | |
|
238 | 238 | def extinct(self): |
|
239 | 239 | """True if the changeset is extinct""" |
|
240 | # We should just compute a cache and check against it. | |
|
241 | # See revset implementation for details. | |
|
242 | # | |
|
243 | # But this naive implementation does not require cache | |
|
244 | if self.phase() <= phases.public: | |
|
245 | return False | |
|
246 | if not self.obsolete(): | |
|
247 | return False | |
|
248 | for desc in self.descendants(): | |
|
249 | if not desc.obsolete(): | |
|
250 | return False | |
|
251 | return True | |
|
240 | return self.rev() in obsmod.getobscache(self._repo, 'extinct') | |
|
252 | 241 | |
|
253 | 242 | def unstable(self): |
|
254 | 243 | """True if the changeset is not obsolete but it's ancestor are""" |
|
255 | # We should just compute /(obsolete()::) - obsolete()/ | |
|
256 | # and keep it in a cache. | |
|
257 | # | |
|
258 | # But this naive implementation does not require cache | |
|
259 | if self.phase() <= phases.public: | |
|
260 | return False | |
|
261 | if self.obsolete(): | |
|
262 | return False | |
|
263 | for anc in self.ancestors(): | |
|
264 | if anc.obsolete(): | |
|
265 | return True | |
|
266 | return False | |
|
244 | return self.rev() in obsmod.getobscache(self._repo, 'unstable') | |
|
267 | 245 | |
|
268 | 246 | def _fileinfo(self, path): |
|
269 | 247 | if '_manifest' in self.__dict__: |
@@ -1042,6 +1042,7 b' class localrepository(object):' | |||
|
1042 | 1042 | |
|
1043 | 1043 | self._branchcache = None # in UTF-8 |
|
1044 | 1044 | self._branchcachetip = None |
|
1045 | obsolete.clearobscaches(self) | |
|
1045 | 1046 | |
|
1046 | 1047 | def invalidatedirstate(self): |
|
1047 | 1048 | '''Invalidates the dirstate, causing the next call to dirstate |
@@ -2404,6 +2405,7 b' class localrepository(object):' | |||
|
2404 | 2405 | self.ui.status(_("added %d changesets" |
|
2405 | 2406 | " with %d changes to %d files%s\n") |
|
2406 | 2407 | % (changesets, revisions, files, htext)) |
|
2408 | obsolete.clearobscaches(self) | |
|
2407 | 2409 | |
|
2408 | 2410 | if changesets > 0: |
|
2409 | 2411 | p = lambda: cl.writepending() and self.root or "" |
@@ -161,6 +161,8 b' class obsstore(object):' | |||
|
161 | 161 | """ |
|
162 | 162 | |
|
163 | 163 | def __init__(self, sopener): |
|
164 | # caches for various obsolescence related cache | |
|
165 | self.caches = {} | |
|
164 | 166 | self._all = [] |
|
165 | 167 | # new markers to serialize |
|
166 | 168 | self.precursors = {} |
@@ -220,6 +222,8 b' class obsstore(object):' | |||
|
220 | 222 | # call 'filecacheentry.refresh()' here |
|
221 | 223 | f.close() |
|
222 | 224 | self._load(new) |
|
225 | # new marker *may* have changed several set. invalidate the cache. | |
|
226 | self.caches.clear() | |
|
223 | 227 | return len(new) |
|
224 | 228 | |
|
225 | 229 | def mergemarkers(self, transation, data): |
@@ -327,3 +331,67 b' def anysuccessors(obsstore, node):' | |||
|
327 | 331 | if suc not in seen: |
|
328 | 332 | seen.add(suc) |
|
329 | 333 | remaining.add(suc) |
|
334 | ||
|
335 | # mapping of 'set-name' -> <function to computer this set> | |
|
336 | cachefuncs = {} | |
|
337 | def cachefor(name): | |
|
338 | """Decorator to register a function as computing the cache for a set""" | |
|
339 | def decorator(func): | |
|
340 | assert name not in cachefuncs | |
|
341 | cachefuncs[name] = func | |
|
342 | return func | |
|
343 | return decorator | |
|
344 | ||
|
345 | def getobscache(repo, name): | |
|
346 | """Return the set of revision that belong to the <name> set | |
|
347 | ||
|
348 | Such access may compute the set and cache it for future use""" | |
|
349 | if not repo.obsstore: | |
|
350 | return () | |
|
351 | if name not in repo.obsstore.caches: | |
|
352 | repo.obsstore.caches[name] = cachefuncs[name](repo) | |
|
353 | return repo.obsstore.caches[name] | |
|
354 | ||
|
355 | # To be simple we need to invalidate obsolescence cache when: | |
|
356 | # | |
|
357 | # - new changeset is added: | |
|
358 | # - public phase is changed | |
|
359 | # - obsolescence marker are added | |
|
360 | # - strip is used a repo | |
|
361 | def clearobscaches(repo): | |
|
362 | """Remove all obsolescence related cache from a repo | |
|
363 | ||
|
364 | This remove all cache in obsstore is the obsstore already exist on the | |
|
365 | repo. | |
|
366 | ||
|
367 | (We could be smarter here given the exact event that trigger the cache | |
|
368 | clearing)""" | |
|
369 | # only clear cache is there is obsstore data in this repo | |
|
370 | if 'obsstore' in repo._filecache: | |
|
371 | repo.obsstore.caches.clear() | |
|
372 | ||
|
373 | @cachefor('obsolete') | |
|
374 | def _computeobsoleteset(repo): | |
|
375 | """the set of obsolete revisions""" | |
|
376 | obs = set() | |
|
377 | nm = repo.changelog.nodemap | |
|
378 | for prec in repo.obsstore.precursors: | |
|
379 | rev = nm.get(prec) | |
|
380 | if rev is not None: | |
|
381 | obs.add(rev) | |
|
382 | return set(repo.revs('%ld - public()', obs)) | |
|
383 | ||
|
384 | @cachefor('unstable') | |
|
385 | def _computeunstableset(repo): | |
|
386 | """the set of non obsolete revisions with obsolete parents""" | |
|
387 | return set(repo.revs('(obsolete()::) - obsolete()')) | |
|
388 | ||
|
389 | @cachefor('suspended') | |
|
390 | def _computesuspendedset(repo): | |
|
391 | """the set of obsolete parents with non obsolete descendants""" | |
|
392 | return set(repo.revs('obsolete() and obsolete()::unstable()')) | |
|
393 | ||
|
394 | @cachefor('extinct') | |
|
395 | def _computeextinctset(repo): | |
|
396 | """the set of obsolete parents without non obsolete descendants""" | |
|
397 | return set(repo.revs('obsolete() - obsolete()::unstable()')) |
@@ -104,6 +104,7 b' import errno' | |||
|
104 | 104 | from node import nullid, nullrev, bin, hex, short |
|
105 | 105 | from i18n import _ |
|
106 | 106 | import util |
|
107 | import obsolete | |
|
107 | 108 | |
|
108 | 109 | allphases = public, draft, secret = range(3) |
|
109 | 110 | trackedphases = allphases[1:] |
@@ -244,6 +245,7 b' class phasecache(object):' | |||
|
244 | 245 | # declare deleted root in the target phase |
|
245 | 246 | if targetphase != 0: |
|
246 | 247 | self.retractboundary(repo, targetphase, delroots) |
|
248 | obsolete.clearobscaches(repo) | |
|
247 | 249 | |
|
248 | 250 | def retractboundary(self, repo, targetphase, nodes): |
|
249 | 251 | # Be careful to preserve shallow-copied values: do not update |
@@ -260,6 +262,7 b' class phasecache(object):' | |||
|
260 | 262 | ctxs = repo.set('roots(%ln::)', currentroots) |
|
261 | 263 | currentroots.intersection_update(ctx.node() for ctx in ctxs) |
|
262 | 264 | self._updateroots(targetphase, currentroots) |
|
265 | obsolete.clearobscaches(repo) | |
|
263 | 266 | |
|
264 | 267 | def advanceboundary(repo, targetphase, nodes): |
|
265 | 268 | """Add nodes to a phase changing other nodes phases if necessary. |
@@ -12,6 +12,7 b' import bookmarks as bookmarksmod' | |||
|
12 | 12 | import match as matchmod |
|
13 | 13 | from i18n import _ |
|
14 | 14 | import encoding |
|
15 | import obsolete as obsmod | |
|
15 | 16 | |
|
16 | 17 | def _revancestors(repo, revs, followfirst): |
|
17 | 18 | """Like revlog.ancestors(), but supports followfirst.""" |
@@ -621,8 +622,8 b' def extinct(repo, subset, x):' | |||
|
621 | 622 | """ |
|
622 | 623 | # i18n: "extinct" is a keyword |
|
623 | 624 | getargs(x, 0, 0, _("extinct takes no arguments")) |
|
624 | extinctset = set(repo.revs('(obsolete()::) - (::(not obsolete()))')) | |
|
625 |
return [r for r in subset if r in extincts |
|
|
625 | extincts = obsmod.getobscache(repo, 'extinct') | |
|
626 | return [r for r in subset if r in extincts] | |
|
626 | 627 | |
|
627 | 628 | def extra(repo, subset, x): |
|
628 | 629 | """``extra(label, [value])`` |
@@ -959,7 +960,8 b' def obsolete(repo, subset, x):' | |||
|
959 | 960 | Mutable changeset with a newer version.""" |
|
960 | 961 | # i18n: "obsolete" is a keyword |
|
961 | 962 | getargs(x, 0, 0, _("obsolete takes no arguments")) |
|
962 | return [r for r in subset if repo[r].obsolete()] | |
|
963 | obsoletes = obsmod.getobscache(repo, 'obsolete') | |
|
964 | return [r for r in subset if r in obsoletes] | |
|
963 | 965 | |
|
964 | 966 | def origin(repo, subset, x): |
|
965 | 967 | """``origin([set])`` |
@@ -1437,8 +1439,8 b' def unstable(repo, subset, x):' | |||
|
1437 | 1439 | """ |
|
1438 | 1440 | # i18n: "unstable" is a keyword |
|
1439 | 1441 | getargs(x, 0, 0, _("unstable takes no arguments")) |
|
1440 | unstableset = set(repo.revs('(obsolete()::) - obsolete()')) | |
|
1441 |
return [r for r in subset if r in unstables |
|
|
1442 | unstables = obsmod.getobscache(repo, 'unstable') | |
|
1443 | return [r for r in subset if r in unstables] | |
|
1442 | 1444 | |
|
1443 | 1445 | |
|
1444 | 1446 | def user(repo, subset, x): |
General Comments 0
You need to be logged in to leave comments.
Login now