##// END OF EJS Templates
phases: sparsify phaseroots and phasesets...
Joerg Sonnenberger -
r45691:61e74644 default
parent child Browse files
Show More
@@ -667,7 +667,7 b' void dirs_module_init(PyObject *mod);'
667 void manifest_module_init(PyObject *mod);
667 void manifest_module_init(PyObject *mod);
668 void revlog_module_init(PyObject *mod);
668 void revlog_module_init(PyObject *mod);
669
669
670 static const int version = 16;
670 static const int version = 17;
671
671
672 static void module_init(PyObject *mod)
672 static void module_init(PyObject *mod)
673 {
673 {
@@ -109,6 +109,9 b' static const Py_ssize_t nullrev = -1;'
109
109
110 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
110 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
111
111
112 static int index_find_node(indexObject *self, const char *node,
113 Py_ssize_t nodelen);
114
112 #if LONG_MAX == 0x7fffffffL
115 #if LONG_MAX == 0x7fffffffL
113 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
116 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
114 #else
117 #else
@@ -577,34 +580,6 b' static int check_filter(PyObject *filter'
577 }
580 }
578 }
581 }
579
582
580 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
581 Py_ssize_t marker, char *phases)
582 {
583 PyObject *iter = NULL;
584 PyObject *iter_item = NULL;
585 Py_ssize_t min_idx = index_length(self) + 2;
586 long iter_item_long;
587
588 if (PyList_GET_SIZE(list) != 0) {
589 iter = PyObject_GetIter(list);
590 if (iter == NULL)
591 return -2;
592 while ((iter_item = PyIter_Next(iter))) {
593 if (!pylong_to_long(iter_item, &iter_item_long)) {
594 Py_DECREF(iter_item);
595 return -2;
596 }
597 Py_DECREF(iter_item);
598 if (iter_item_long < min_idx)
599 min_idx = iter_item_long;
600 phases[iter_item_long] = (char)marker;
601 }
602 Py_DECREF(iter);
603 }
604
605 return min_idx;
606 }
607
608 static inline void set_phase_from_parents(char *phases, int parent_1,
583 static inline void set_phase_from_parents(char *phases, int parent_1,
609 int parent_2, Py_ssize_t i)
584 int parent_2, Py_ssize_t i)
610 {
585 {
@@ -773,99 +748,165 b' bail:'
773 return NULL;
748 return NULL;
774 }
749 }
775
750
751 static int add_roots_get_min(indexObject *self, PyObject *roots, char *phases,
752 char phase)
753 {
754 Py_ssize_t len = index_length(self);
755 PyObject *iter;
756 PyObject *item;
757 PyObject *iterator;
758 int rev, minrev = -1;
759 char *node;
760
761 if (!PySet_Check(roots))
762 return -2;
763 iterator = PyObject_GetIter(roots);
764 if (iterator == NULL)
765 return -2;
766 while ((item = PyIter_Next(iterator))) {
767 if (node_check(item, &node) == -1)
768 goto failed;
769 rev = index_find_node(self, node, 20);
770 /* null is implicitly public, so negative is invalid */
771 if (rev < 0 || rev >= len)
772 goto failed;
773 phases[rev] = phase;
774 if (minrev == -1 || minrev > rev)
775 minrev = rev;
776 Py_DECREF(item);
777 }
778 Py_DECREF(iterator);
779 return minrev;
780 failed:
781 Py_DECREF(iterator);
782 Py_DECREF(item);
783 return -2;
784 }
785
776 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
786 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
777 {
787 {
778 PyObject *roots = Py_None;
788 /* 0: public (untracked), 1: draft, 2: secret, 32: archive,
789 96: internal */
790 static const char trackedphases[] = {1, 2, 32, 96};
779 PyObject *ret = NULL;
791 PyObject *ret = NULL;
780 PyObject *phasessize = NULL;
792 PyObject *roots = Py_None;
793 PyObject *idx = NULL;
794 PyObject *pyphase = NULL;
795 PyObject *pyrev = NULL;
781 PyObject *phaseroots = NULL;
796 PyObject *phaseroots = NULL;
782 PyObject *phaseset = NULL;
797 PyObject *phasessize = NULL;
783 PyObject *phasessetlist = NULL;
798 PyObject *phasesets[4] = {NULL, NULL, NULL, NULL};
784 PyObject *rev = NULL;
785 Py_ssize_t len = index_length(self);
799 Py_ssize_t len = index_length(self);
786 Py_ssize_t numphase = 0;
800 const char *currentphase;
787 Py_ssize_t minrevallphases = 0;
788 Py_ssize_t minrevphase = 0;
789 Py_ssize_t i = 0;
790 char *phases = NULL;
801 char *phases = NULL;
791 long phase;
802 int minphaserev = -1, rev, i;
803 const int numphases = (int)(sizeof(phasesets) / sizeof(phasesets[0]));
792
804
793 if (!PyArg_ParseTuple(args, "O", &roots))
805 if (!PyArg_ParseTuple(args, "O", &roots))
794 goto done;
806 return NULL;
795 if (roots == NULL || !PyList_Check(roots)) {
807 if (roots == NULL || !PyDict_Check(roots)) {
796 PyErr_SetString(PyExc_TypeError, "roots must be a list");
808 PyErr_SetString(PyExc_TypeError, "roots must be a dictionary");
797 goto done;
809 return NULL;
798 }
810 }
799
811
800 phases = calloc(
812 phases = calloc(len, 1);
801 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
802 if (phases == NULL) {
813 if (phases == NULL) {
803 PyErr_NoMemory();
814 PyErr_NoMemory();
804 goto done;
815 return NULL;
805 }
816 }
806 /* Put the phase information of all the roots in phases */
817
807 numphase = PyList_GET_SIZE(roots) + 1;
818 for (i = 0; i < numphases; ++i) {
808 minrevallphases = len + 1;
819 pyphase = PyInt_FromLong(trackedphases[i]);
809 phasessetlist = PyList_New(numphase);
820 if (pyphase == NULL)
810 if (phasessetlist == NULL)
821 goto release;
811 goto done;
822 phaseroots = PyDict_GetItem(roots, pyphase);
823 Py_DECREF(pyphase);
824 if (phaseroots == NULL)
825 continue;
826 rev = add_roots_get_min(self, phaseroots, phases, trackedphases[i]);
827 phaseroots = NULL;
828 if (rev == -2)
829 goto release;
830 if (rev != -1 && (minphaserev == -1 || rev < minphaserev))
831 minphaserev = rev;
832 }
833
834 for (i = 0; i < numphases; ++i) {
835 phasesets[i] = PySet_New(NULL);
836 if (phasesets[i] == NULL)
837 goto release;
838 }
812
839
813 PyList_SET_ITEM(phasessetlist, 0, Py_None);
840 if (minphaserev == -1)
814 Py_INCREF(Py_None);
841 minphaserev = len;
815
842 for (rev = minphaserev; rev < len; ++rev) {
816 for (i = 0; i < numphase - 1; i++) {
843 int parents[2];
817 phaseroots = PyList_GET_ITEM(roots, i);
844 /*
818 phaseset = PySet_New(NULL);
845 * The parent lookup could be skipped for phaseroots, but
819 if (phaseset == NULL)
846 * phase --force would historically not recompute them
847 * correctly, leaving descendents with a lower phase around.
848 * As such, unconditionally recompute the phase.
849 */
850 if (index_get_parents(self, rev, parents, (int)len - 1) < 0)
820 goto release;
851 goto release;
821 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
852 set_phase_from_parents(phases, parents[0], parents[1], rev);
822 if (!PyList_Check(phaseroots)) {
853 switch (phases[rev]) {
823 PyErr_SetString(PyExc_TypeError,
854 case 0:
824 "roots item must be a list");
855 continue;
856 case 1:
857 pyphase = phasesets[0];
858 break;
859 case 2:
860 pyphase = phasesets[1];
861 break;
862 case 32:
863 pyphase = phasesets[2];
864 break;
865 case 96:
866 pyphase = phasesets[3];
867 break;
868 default:
825 goto release;
869 goto release;
826 }
870 }
827 minrevphase =
871 pyrev = PyInt_FromLong(rev);
828 add_roots_get_min(self, phaseroots, i + 1, phases);
872 if (pyrev == NULL)
829 if (minrevphase == -2) /* Error from add_roots_get_min */
830 goto release;
873 goto release;
831 minrevallphases = MIN(minrevallphases, minrevphase);
874 if (PySet_Add(pyphase, pyrev) == -1) {
875 Py_DECREF(pyrev);
876 goto release;
877 }
878 Py_DECREF(pyrev);
832 }
879 }
833 /* Propagate the phase information from the roots to the revs */
880 phaseroots = _dict_new_presized(numphases);
834 if (minrevallphases != -1) {
881 if (phaseroots == NULL)
835 int parents[2];
882 goto release;
836 for (i = minrevallphases; i < len; i++) {
883 for (int i = 0; i < numphases; ++i) {
837 if (index_get_parents(self, i, parents, (int)len - 1) <
884 pyphase = PyInt_FromLong(trackedphases[i]);
838 0)
885 if (pyphase == NULL)
839 goto release;
886 goto release;
840 set_phase_from_parents(phases, parents[0], parents[1],
887 if (PyDict_SetItem(phaseroots, pyphase, phasesets[i]) == -1) {
841 i);
888 Py_DECREF(pyphase);
889 goto release;
842 }
890 }
891 Py_DECREF(phasesets[i]);
892 phasesets[i] = NULL;
843 }
893 }
844 /* Transform phase list to a python list */
845 phasessize = PyInt_FromSsize_t(len);
894 phasessize = PyInt_FromSsize_t(len);
846 if (phasessize == NULL)
895 if (phasessize == NULL)
847 goto release;
896 goto release;
848 for (i = 0; i < len; i++) {
897
849 phase = phases[i];
898 ret = PyTuple_Pack(2, phasessize, phaseroots);
850 /* We only store the sets of phase for non public phase, the
899 Py_DECREF(phasessize);
851 * public phase is computed as a difference */
900 Py_DECREF(phaseroots);
852 if (phase != 0) {
901 return ret;
853 phaseset = PyList_GET_ITEM(phasessetlist, phase);
854 rev = PyInt_FromSsize_t(i);
855 if (rev == NULL)
856 goto release;
857 PySet_Add(phaseset, rev);
858 Py_XDECREF(rev);
859 }
860 }
861 ret = PyTuple_Pack(2, phasessize, phasessetlist);
862
902
863 release:
903 release:
864 Py_XDECREF(phasessize);
904 for (i = 0; i < numphases; ++i)
865 Py_XDECREF(phasessetlist);
905 Py_XDECREF(phasesets[i]);
866 done:
906 Py_XDECREF(phaseroots);
907
867 free(phases);
908 free(phases);
868 return ret;
909 return NULL;
869 }
910 }
870
911
871 static PyObject *index_headrevs(indexObject *self, PyObject *args)
912 static PyObject *index_headrevs(indexObject *self, PyObject *args)
@@ -170,7 +170,7 b' def _readroots(repo, phasedefaults=None)'
170 """
170 """
171 repo = repo.unfiltered()
171 repo = repo.unfiltered()
172 dirty = False
172 dirty = False
173 roots = [set() for i in range(max(allphases) + 1)]
173 roots = {i: set() for i in allphases}
174 try:
174 try:
175 f, pending = txnutil.trypending(repo.root, repo.svfs, b'phaseroots')
175 f, pending = txnutil.trypending(repo.root, repo.svfs, b'phaseroots')
176 try:
176 try:
@@ -333,7 +333,11 b' class phasecache(object):'
333 if len(cl) >= self._loadedrevslen:
333 if len(cl) >= self._loadedrevslen:
334 self.invalidate()
334 self.invalidate()
335 self.loadphaserevs(repo)
335 self.loadphaserevs(repo)
336 return any(self.phaseroots[1:])
336 return any(
337 revs
338 for phase, revs in pycompat.iteritems(self.phaseroots)
339 if phase != public
340 )
337
341
338 def nonpublicphaseroots(self, repo):
342 def nonpublicphaseroots(self, repo):
339 """returns the roots of all non-public phases
343 """returns the roots of all non-public phases
@@ -346,7 +350,13 b' class phasecache(object):'
346 if len(cl) >= self._loadedrevslen:
350 if len(cl) >= self._loadedrevslen:
347 self.invalidate()
351 self.invalidate()
348 self.loadphaserevs(repo)
352 self.loadphaserevs(repo)
349 return set().union(*[roots for roots in self.phaseroots[1:] if roots])
353 return set().union(
354 *[
355 revs
356 for phase, revs in pycompat.iteritems(self.phaseroots)
357 if phase != public
358 ]
359 )
350
360
351 def getrevset(self, repo, phases, subset=None):
361 def getrevset(self, repo, phases, subset=None):
352 """return a smartset for the given phases"""
362 """return a smartset for the given phases"""
@@ -405,7 +415,7 b' class phasecache(object):'
405 # Shallow copy meant to ensure isolation in
415 # Shallow copy meant to ensure isolation in
406 # advance/retractboundary(), nothing more.
416 # advance/retractboundary(), nothing more.
407 ph = self.__class__(None, None, _load=False)
417 ph = self.__class__(None, None, _load=False)
408 ph.phaseroots = self.phaseroots[:]
418 ph.phaseroots = self.phaseroots.copy()
409 ph.dirty = self.dirty
419 ph.dirty = self.dirty
410 ph.opener = self.opener
420 ph.opener = self.opener
411 ph._loadedrevslen = self._loadedrevslen
421 ph._loadedrevslen = self._loadedrevslen
@@ -425,21 +435,12 b' class phasecache(object):'
425
435
426 def _getphaserevsnative(self, repo):
436 def _getphaserevsnative(self, repo):
427 repo = repo.unfiltered()
437 repo = repo.unfiltered()
428 nativeroots = []
438 return repo.changelog.computephases(self.phaseroots)
429 for phase in trackedphases:
430 nativeroots.append(
431 pycompat.maplist(repo.changelog.rev, self.phaseroots[phase])
432 )
433 revslen, phasesets = repo.changelog.computephases(nativeroots)
434 phasesets2 = [set() for phase in range(max(allphases) + 1)]
435 for phase, phaseset in zip(allphases, phasesets):
436 phasesets2[phase] = phaseset
437 return revslen, phasesets2
438
439
439 def _computephaserevspure(self, repo):
440 def _computephaserevspure(self, repo):
440 repo = repo.unfiltered()
441 repo = repo.unfiltered()
441 cl = repo.changelog
442 cl = repo.changelog
442 self._phasesets = [set() for phase in range(max(allphases) + 1)]
443 self._phasesets = {phase: set() for phase in allphases}
443 lowerroots = set()
444 lowerroots = set()
444 for phase in reversed(trackedphases):
445 for phase in reversed(trackedphases):
445 roots = pycompat.maplist(cl.rev, self.phaseroots[phase])
446 roots = pycompat.maplist(cl.rev, self.phaseroots[phase])
@@ -493,7 +494,7 b' class phasecache(object):'
493 f.close()
494 f.close()
494
495
495 def _write(self, fp):
496 def _write(self, fp):
496 for phase, roots in enumerate(self.phaseroots):
497 for phase, roots in pycompat.iteritems(self.phaseroots):
497 for h in sorted(roots):
498 for h in sorted(roots):
498 fp.write(b'%i %s\n' % (phase, hex(h)))
499 fp.write(b'%i %s\n' % (phase, hex(h)))
499 self.dirty = False
500 self.dirty = False
@@ -575,7 +576,11 b' class phasecache(object):'
575 return changes
576 return changes
576
577
577 def retractboundary(self, repo, tr, targetphase, nodes):
578 def retractboundary(self, repo, tr, targetphase, nodes):
578 oldroots = self.phaseroots[: targetphase + 1]
579 oldroots = {
580 phase: revs
581 for phase, revs in pycompat.iteritems(self.phaseroots)
582 if phase <= targetphase
583 }
579 if tr is None:
584 if tr is None:
580 phasetracking = None
585 phasetracking = None
581 else:
586 else:
@@ -594,7 +599,7 b' class phasecache(object):'
594 # find the phase of the affected revision
599 # find the phase of the affected revision
595 for phase in pycompat.xrange(targetphase, -1, -1):
600 for phase in pycompat.xrange(targetphase, -1, -1):
596 if phase:
601 if phase:
597 roots = oldroots[phase]
602 roots = oldroots.get(phase, [])
598 revs = set(repo.revs(b'%ln::%ld', roots, affected))
603 revs = set(repo.revs(b'%ln::%ld', roots, affected))
599 affected -= revs
604 affected -= revs
600 else: # public phase
605 else: # public phase
@@ -648,7 +653,7 b' class phasecache(object):'
648 """
653 """
649 filtered = False
654 filtered = False
650 has_node = repo.changelog.index.has_node # to filter unknown nodes
655 has_node = repo.changelog.index.has_node # to filter unknown nodes
651 for phase, nodes in enumerate(self.phaseroots):
656 for phase, nodes in pycompat.iteritems(self.phaseroots):
652 missing = sorted(node for node in nodes if not has_node(node))
657 missing = sorted(node for node in nodes if not has_node(node))
653 if missing:
658 if missing:
654 for mnode in missing:
659 for mnode in missing:
@@ -80,7 +80,7 b' def _importfrom(pkgname, modname):'
80 ('cext', 'bdiff'): 3,
80 ('cext', 'bdiff'): 3,
81 ('cext', 'mpatch'): 1,
81 ('cext', 'mpatch'): 1,
82 ('cext', 'osutil'): 4,
82 ('cext', 'osutil'): 4,
83 ('cext', 'parsers'): 16,
83 ('cext', 'parsers'): 17,
84 }
84 }
85
85
86 # map import request to other package or module
86 # map import request to other package or module
@@ -185,7 +185,7 b' Test corrupted p1/p2 fields that could c'
185 > ops = [
185 > ops = [
186 > ('reachableroots',
186 > ('reachableroots',
187 > lambda: cl.index.reachableroots2(0, [1], [0], False)),
187 > lambda: cl.index.reachableroots2(0, [1], [0], False)),
188 > ('compute_phases_map_sets', lambda: cl.computephases([[0], []])),
188 > ('compute_phases_map_sets', lambda: cl.computephases({1: {cl.node(0)}})),
189 > ('index_headrevs', lambda: cl.headrevs()),
189 > ('index_headrevs', lambda: cl.headrevs()),
190 > ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
190 > ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
191 > ('find_deepest', lambda: cl.ancestor(n0, n1)),
191 > ('find_deepest', lambda: cl.ancestor(n0, n1)),
General Comments 0
You need to be logged in to leave comments. Login now