##// END OF EJS Templates
phases: drop the list with phase of each rev, always comput phase sets...
Joerg Sonnenberger -
r35310:d1352633 default
parent child Browse files
Show More
@@ -710,7 +710,7 b' void dirs_module_init(PyObject *mod);'
710 void manifest_module_init(PyObject *mod);
710 void manifest_module_init(PyObject *mod);
711 void revlog_module_init(PyObject *mod);
711 void revlog_module_init(PyObject *mod);
712
712
713 static const int version = 3;
713 static const int version = 4;
714
714
715 static void module_init(PyObject *mod)
715 static void module_init(PyObject *mod)
716 {
716 {
@@ -628,7 +628,7 b' static PyObject *compute_phases_map_sets'
628 {
628 {
629 PyObject *roots = Py_None;
629 PyObject *roots = Py_None;
630 PyObject *ret = NULL;
630 PyObject *ret = NULL;
631 PyObject *phaseslist = NULL;
631 PyObject *phasessize = NULL;
632 PyObject *phaseroots = NULL;
632 PyObject *phaseroots = NULL;
633 PyObject *phaseset = NULL;
633 PyObject *phaseset = NULL;
634 PyObject *phasessetlist = NULL;
634 PyObject *phasessetlist = NULL;
@@ -685,12 +685,10 b' static PyObject *compute_phases_map_sets'
685 }
685 }
686 }
686 }
687 /* Transform phase list to a python list */
687 /* Transform phase list to a python list */
688 phaseslist = PyList_New(len);
688 phasessize = PyInt_FromLong(len);
689 if (phaseslist == NULL)
689 if (phasessize == NULL)
690 goto release;
690 goto release;
691 for (i = 0; i < len; i++) {
691 for (i = 0; i < len; i++) {
692 PyObject *phaseval;
693
694 phase = phases[i];
692 phase = phases[i];
695 /* We only store the sets of phase for non public phase, the public phase
693 /* We only store the sets of phase for non public phase, the public phase
696 * is computed as a difference */
694 * is computed as a difference */
@@ -702,15 +700,11 b' static PyObject *compute_phases_map_sets'
702 PySet_Add(phaseset, rev);
700 PySet_Add(phaseset, rev);
703 Py_XDECREF(rev);
701 Py_XDECREF(rev);
704 }
702 }
705 phaseval = PyInt_FromLong(phase);
706 if (phaseval == NULL)
707 goto release;
708 PyList_SET_ITEM(phaseslist, i, phaseval);
709 }
703 }
710 ret = PyTuple_Pack(2, phaseslist, phasessetlist);
704 ret = PyTuple_Pack(2, phasessize, phasessetlist);
711
705
712 release:
706 release:
713 Py_XDECREF(phaseslist);
707 Py_XDECREF(phasessize);
714 Py_XDECREF(phasessetlist);
708 Py_XDECREF(phasessetlist);
715 done:
709 done:
716 free(phases);
710 free(phases);
@@ -688,8 +688,8 b' class localrepository(object):'
688 def _activebookmark(self):
688 def _activebookmark(self):
689 return self._bookmarks.active
689 return self._bookmarks.active
690
690
691 # _phaserevs and _phasesets depend on changelog. what we need is to
691 # _phasesets depend on changelog. what we need is to call
692 # call _phasecache.invalidate() if '00changelog.i' was changed, but it
692 # _phasecache.invalidate() if '00changelog.i' was changed, but it
693 # can't be easily expressed in filecache mechanism.
693 # can't be easily expressed in filecache mechanism.
694 @storecache('phaseroots', '00changelog.i')
694 @storecache('phaseroots', '00changelog.i')
695 def _phasecache(self):
695 def _phasecache(self):
@@ -115,6 +115,7 b' from .node import ('
115 )
115 )
116 from . import (
116 from . import (
117 error,
117 error,
118 pycompat,
118 smartset,
119 smartset,
119 txnutil,
120 txnutil,
120 util,
121 util,
@@ -202,7 +203,7 b' class phasecache(object):'
202 if _load:
203 if _load:
203 # Cheap trick to allow shallow-copy without copy module
204 # Cheap trick to allow shallow-copy without copy module
204 self.phaseroots, self.dirty = _readroots(repo, phasedefaults)
205 self.phaseroots, self.dirty = _readroots(repo, phasedefaults)
205 self._phaserevs = None
206 self._phasemaxrev = nullrev
206 self._phasesets = None
207 self._phasesets = None
207 self.filterunknown(repo)
208 self.filterunknown(repo)
208 self.opener = repo.svfs
209 self.opener = repo.svfs
@@ -210,23 +211,30 b' class phasecache(object):'
210 def getrevset(self, repo, phases):
211 def getrevset(self, repo, phases):
211 """return a smartset for the given phases"""
212 """return a smartset for the given phases"""
212 self.loadphaserevs(repo) # ensure phase's sets are loaded
213 self.loadphaserevs(repo) # ensure phase's sets are loaded
213
214 phases = set(phases)
214 if self._phasesets and all(self._phasesets[p] is not None
215 if public not in phases:
215 for p in phases):
216 # fast path: _phasesets contains the interesting sets,
216 # fast path - use _phasesets
217 # might only need a union and post-filtering.
217 revs = self._phasesets[phases[0]]
218 if len(phases) == 1:
218 if len(phases) > 1:
219 [p] = phases
219 revs = revs.copy() # only copy when needed
220 revs = self._phasesets[p]
220 for p in phases[1:]:
221 else:
221 revs.update(self._phasesets[p])
222 revs = set.union(*[self._phasesets[p] for p in phases])
222 if repo.changelog.filteredrevs:
223 if repo.changelog.filteredrevs:
223 revs = revs - repo.changelog.filteredrevs
224 revs = revs - repo.changelog.filteredrevs
224 return smartset.baseset(revs)
225 return smartset.baseset(revs)
225 else:
226 else:
226 # slow path - enumerate all revisions
227 phases = set(allphases).difference(phases)
227 phase = self.phase
228 if not phases:
228 revs = (r for r in repo if phase(repo, r) in phases)
229 return smartset.fullreposet(repo)
229 return smartset.generatorset(revs, iterasc=True)
230 if len(phases) == 1:
231 [p] = phases
232 revs = self._phasesets[p]
233 else:
234 revs = set.union(*[self._phasesets[p] for p in phases])
235 if not revs:
236 return smartset.fullreposet(repo)
237 return smartset.fullreposet(repo).filter(lambda r: r not in revs)
230
238
231 def copy(self):
239 def copy(self):
232 # Shallow copy meant to ensure isolation in
240 # Shallow copy meant to ensure isolation in
@@ -235,13 +243,14 b' class phasecache(object):'
235 ph.phaseroots = self.phaseroots[:]
243 ph.phaseroots = self.phaseroots[:]
236 ph.dirty = self.dirty
244 ph.dirty = self.dirty
237 ph.opener = self.opener
245 ph.opener = self.opener
238 ph._phaserevs = self._phaserevs
246 ph._phasemaxrev = self._phasemaxrev
239 ph._phasesets = self._phasesets
247 ph._phasesets = self._phasesets
240 return ph
248 return ph
241
249
242 def replace(self, phcache):
250 def replace(self, phcache):
243 """replace all values in 'self' with content of phcache"""
251 """replace all values in 'self' with content of phcache"""
244 for a in ('phaseroots', 'dirty', 'opener', '_phaserevs', '_phasesets'):
252 for a in ('phaseroots', 'dirty', 'opener', '_phasemaxrev',
253 '_phasesets'):
245 setattr(self, a, getattr(phcache, a))
254 setattr(self, a, getattr(phcache, a))
246
255
247 def _getphaserevsnative(self, repo):
256 def _getphaserevsnative(self, repo):
@@ -253,42 +262,38 b' class phasecache(object):'
253
262
254 def _computephaserevspure(self, repo):
263 def _computephaserevspure(self, repo):
255 repo = repo.unfiltered()
264 repo = repo.unfiltered()
256 revs = [public] * len(repo.changelog)
265 cl = repo.changelog
257 self._phaserevs = revs
266 self._phasesets = [set() for phase in allphases]
258 self._populatephaseroots(repo)
267 roots = pycompat.maplist(cl.rev, self.phaseroots[secret])
259 for phase in trackedphases:
268 if roots:
260 roots = list(map(repo.changelog.rev, self.phaseroots[phase]))
269 ps = set(cl.descendants(roots))
261 if roots:
270 for root in roots:
262 for rev in roots:
271 ps.add(root)
263 revs[rev] = phase
272 self._phasesets[secret] = ps
264 for rev in repo.changelog.descendants(roots):
273 roots = pycompat.maplist(cl.rev, self.phaseroots[draft])
265 revs[rev] = phase
274 if roots:
275 ps = set(cl.descendants(roots))
276 for root in roots:
277 ps.add(root)
278 ps.difference_update(self._phasesets[secret])
279 self._phasesets[draft] = ps
280 self._phasemaxrev = len(cl)
266
281
267 def loadphaserevs(self, repo):
282 def loadphaserevs(self, repo):
268 """ensure phase information is loaded in the object"""
283 """ensure phase information is loaded in the object"""
269 if self._phaserevs is None:
284 if self._phasesets is None:
270 try:
285 try:
271 res = self._getphaserevsnative(repo)
286 res = self._getphaserevsnative(repo)
272 self._phaserevs, self._phasesets = res
287 self._phasemaxrev, self._phasesets = res
273 except AttributeError:
288 except AttributeError:
274 self._computephaserevspure(repo)
289 self._computephaserevspure(repo)
275
290
276 def invalidate(self):
291 def invalidate(self):
277 self._phaserevs = None
292 self._phasemaxrev = nullrev
278 self._phasesets = None
293 self._phasesets = None
279
294
280 def _populatephaseroots(self, repo):
281 """Fills the _phaserevs cache with phases for the roots.
282 """
283 cl = repo.changelog
284 phaserevs = self._phaserevs
285 for phase in trackedphases:
286 roots = map(cl.rev, self.phaseroots[phase])
287 for root in roots:
288 phaserevs[root] = phase
289
290 def phase(self, repo, rev):
295 def phase(self, repo, rev):
291 # We need a repo argument here to be able to build _phaserevs
296 # We need a repo argument here to be able to build _phasesets
292 # if necessary. The repository instance is not stored in
297 # if necessary. The repository instance is not stored in
293 # phasecache to avoid reference cycles. The changelog instance
298 # phasecache to avoid reference cycles. The changelog instance
294 # is not stored because it is a filecache() property and can
299 # is not stored because it is a filecache() property and can
@@ -297,10 +302,13 b' class phasecache(object):'
297 return public
302 return public
298 if rev < nullrev:
303 if rev < nullrev:
299 raise ValueError(_('cannot lookup negative revision'))
304 raise ValueError(_('cannot lookup negative revision'))
300 if self._phaserevs is None or rev >= len(self._phaserevs):
305 if rev >= self._phasemaxrev:
301 self.invalidate()
306 self.invalidate()
302 self.loadphaserevs(repo)
307 self.loadphaserevs(repo)
303 return self._phaserevs[rev]
308 for phase in trackedphases:
309 if rev in self._phasesets[phase]:
310 return phase
311 return public
304
312
305 def write(self):
313 def write(self):
306 if not self.dirty:
314 if not self.dirty:
@@ -455,10 +463,10 b' class phasecache(object):'
455 if filtered:
463 if filtered:
456 self.dirty = True
464 self.dirty = True
457 # filterunknown is called by repo.destroyed, we may have no changes in
465 # filterunknown is called by repo.destroyed, we may have no changes in
458 # root but phaserevs contents is certainly invalid (or at least we
466 # root but _phasesets contents is certainly invalid (or at least we
459 # have not proper way to check that). related to issue 3858.
467 # have not proper way to check that). related to issue 3858.
460 #
468 #
461 # The other caller is __init__ that have no _phaserevs initialized
469 # The other caller is __init__ that have no _phasesets initialized
462 # anyway. If this change we should consider adding a dedicated
470 # anyway. If this change we should consider adding a dedicated
463 # "destroyed" function to phasecache or a proper cache key mechanism
471 # "destroyed" function to phasecache or a proper cache key mechanism
464 # (see branchmap one)
472 # (see branchmap one)
@@ -75,7 +75,7 b' def _importfrom(pkgname, modname):'
75 (r'cext', r'diffhelpers'): 1,
75 (r'cext', r'diffhelpers'): 1,
76 (r'cext', r'mpatch'): 1,
76 (r'cext', r'mpatch'): 1,
77 (r'cext', r'osutil'): 1,
77 (r'cext', r'osutil'): 1,
78 (r'cext', r'parsers'): 3,
78 (r'cext', r'parsers'): 4,
79 }
79 }
80
80
81 # map import request to other package or module
81 # map import request to other package or module
General Comments 0
You need to be logged in to leave comments. Login now