@@ -75,7 +75,7 @@
(r'cext', r'diffhelpers'): 1,
(r'cext', r'mpatch'): 1,
(r'cext', r'osutil'): 1,
- (r'cext', r'parsers'): 3,
+ (r'cext', r'parsers'): 4,
}
# map import request to other package or module
@@ -115,6 +115,7 @@
)
from . import (
error,
+ pycompat,
smartset,
txnutil,
util,
@@ -202,46 +203,54 @@
if _load:
# Cheap trick to allow shallow-copy without copy module
self.phaseroots, self.dirty = _readroots(repo, phasedefaults)
- self._phaserevs = None
+ self._phasemaxrev = nullrev
self._phasesets = None
self.filterunknown(repo)
self.opener = repo.svfs
def getrevset(self, repo, phases):
"""return a smartset for the given phases"""
self.loadphaserevs(repo) # ensure phase's sets are loaded
-
- if self._phasesets and all(self._phasesets[p] is not None
- for p in phases):
- # fast path - use _phasesets
- revs = self._phasesets[phases[0]]
- if len(phases) > 1:
- revs = revs.copy() # only copy when needed
- for p in phases[1:]:
- revs.update(self._phasesets[p])
+ phases = set(phases)
+ if public not in phases:
+ # fast path: _phasesets contains the interesting sets,
+ # might only need a union and post-filtering.
+ if len(phases) == 1:
+ [p] = phases
+ revs = self._phasesets[p]
+ else:
+ revs = set.union(*[self._phasesets[p] for p in phases])
if repo.changelog.filteredrevs:
revs = revs - repo.changelog.filteredrevs
return smartset.baseset(revs)
else:
- # slow path - enumerate all revisions
- phase = self.phase
- revs = (r for r in repo if phase(repo, r) in phases)
- return smartset.generatorset(revs, iterasc=True)
+ phases = set(allphases).difference(phases)
+ if not phases:
+ return smartset.fullreposet(repo)
+ if len(phases) == 1:
+ [p] = phases
+ revs = self._phasesets[p]
+ else:
+ revs = set.union(*[self._phasesets[p] for p in phases])
+ if not revs:
+ return smartset.fullreposet(repo)
+ return smartset.fullreposet(repo).filter(lambda r: r not in revs)
def copy(self):
# Shallow copy meant to ensure isolation in
# advance/retractboundary(), nothing more.
ph = self.__class__(None, None, _load=False)
ph.phaseroots = self.phaseroots[:]
ph.dirty = self.dirty
ph.opener = self.opener
- ph._phaserevs = self._phaserevs
+ ph._phasemaxrev = self._phasemaxrev
ph._phasesets = self._phasesets
return ph
def replace(self, phcache):
"""replace all values in 'self' with content of phcache"""
- for a in ('phaseroots', 'dirty', 'opener', '_phaserevs', '_phasesets'):
+ for a in ('phaseroots', 'dirty', 'opener', '_phasemaxrev',
+ '_phasesets'):
setattr(self, a, getattr(phcache, a))
def _getphaserevsnative(self, repo):
@@ -253,54 +262,53 @@
def _computephaserevspure(self, repo):
repo = repo.unfiltered()
- revs = [public] * len(repo.changelog)
- self._phaserevs = revs
- self._populatephaseroots(repo)
- for phase in trackedphases:
- roots = list(map(repo.changelog.rev, self.phaseroots[phase]))
- if roots:
- for rev in roots:
- revs[rev] = phase
- for rev in repo.changelog.descendants(roots):
- revs[rev] = phase
+ cl = repo.changelog
+ self._phasesets = [set() for phase in allphases]
+ roots = pycompat.maplist(cl.rev, self.phaseroots[secret])
+ if roots:
+ ps = set(cl.descendants(roots))
+ for root in roots:
+ ps.add(root)
+ self._phasesets[secret] = ps
+ roots = pycompat.maplist(cl.rev, self.phaseroots[draft])
+ if roots:
+ ps = set(cl.descendants(roots))
+ for root in roots:
+ ps.add(root)
+ ps.difference_update(self._phasesets[secret])
+ self._phasesets[draft] = ps
+ self._phasemaxrev = len(cl)
def loadphaserevs(self, repo):
"""ensure phase information is loaded in the object"""
- if self._phaserevs is None:
+ if self._phasesets is None:
try:
res = self._getphaserevsnative(repo)
- self._phaserevs, self._phasesets = res
+ self._phasemaxrev, self._phasesets = res
except AttributeError:
self._computephaserevspure(repo)
def invalidate(self):
- self._phaserevs = None
+ self._phasemaxrev = nullrev
self._phasesets = None
- def _populatephaseroots(self, repo):
- """Fills the _phaserevs cache with phases for the roots.
- """
- cl = repo.changelog
- phaserevs = self._phaserevs
- for phase in trackedphases:
- roots = map(cl.rev, self.phaseroots[phase])
- for root in roots:
- phaserevs[root] = phase
-
def phase(self, repo, rev):
- # We need a repo argument here to be able to build _phaserevs
+ # We need a repo argument here to be able to build _phasesets
# if necessary. The repository instance is not stored in
# phasecache to avoid reference cycles. The changelog instance
# is not stored because it is a filecache() property and can
# be replaced without us being notified.
if rev == nullrev:
return public
if rev < nullrev:
raise ValueError(_('cannot lookup negative revision'))
- if self._phaserevs is None or rev >= len(self._phaserevs):
+ if rev >= self._phasemaxrev:
self.invalidate()
self.loadphaserevs(repo)
- return self._phaserevs[rev]
+ for phase in trackedphases:
+ if rev in self._phasesets[phase]:
+ return phase
+ return public
def write(self):
if not self.dirty:
@@ -455,10 +463,10 @@
if filtered:
self.dirty = True
# filterunknown is called by repo.destroyed, we may have no changes in
- # root but phaserevs contents is certainly invalid (or at least we
+ # root but _phasesets contents is certainly invalid (or at least we
# have not proper way to check that). related to issue 3858.
#
- # The other caller is __init__ that have no _phaserevs initialized
+ # The other caller is __init__ that have no _phasesets initialized
# anyway. If this change we should consider adding a dedicated
# "destroyed" function to phasecache or a proper cache key mechanism
# (see branchmap one)
@@ -688,8 +688,8 @@
def _activebookmark(self):
return self._bookmarks.active
- # _phaserevs and _phasesets depend on changelog. what we need is to
- # call _phasecache.invalidate() if '00changelog.i' was changed, but it
+ # _phasesets depend on changelog. what we need is to call
+ # _phasecache.invalidate() if '00changelog.i' was changed, but it
# can't be easily expressed in filecache mechanism.
@storecache('phaseroots', '00changelog.i')
def _phasecache(self):
@@ -628,7 +628,7 @@
{
PyObject *roots = Py_None;
PyObject *ret = NULL;
- PyObject *phaseslist = NULL;
+ PyObject *phasessize = NULL;
PyObject *phaseroots = NULL;
PyObject *phaseset = NULL;
PyObject *phasessetlist = NULL;
@@ -685,12 +685,10 @@
}
}
/* Transform phase list to a python list */
- phaseslist = PyList_New(len);
- if (phaseslist == NULL)
+ phasessize = PyInt_FromLong(len);
+ if (phasessize == NULL)
goto release;
for (i = 0; i < len; i++) {
- PyObject *phaseval;
-
phase = phases[i];
/* We only store the sets of phase for non public phase, the public phase
* is computed as a difference */
@@ -702,15 +700,11 @@
PySet_Add(phaseset, rev);
Py_XDECREF(rev);
}
- phaseval = PyInt_FromLong(phase);
- if (phaseval == NULL)
- goto release;
- PyList_SET_ITEM(phaseslist, i, phaseval);
}
- ret = PyTuple_Pack(2, phaseslist, phasessetlist);
+ ret = PyTuple_Pack(2, phasessize, phasessetlist);
release:
- Py_XDECREF(phaseslist);
+ Py_XDECREF(phasessize);
Py_XDECREF(phasessetlist);
done:
free(phases);
@@ -710,7 +710,7 @@
void manifest_module_init(PyObject *mod);
void revlog_module_init(PyObject *mod);
-static const int version = 3;
+static const int version = 4;
static void module_init(PyObject *mod)
{