##// 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 667 void manifest_module_init(PyObject *mod);
668 668 void revlog_module_init(PyObject *mod);
669 669
670 static const int version = 16;
670 static const int version = 17;
671 671
672 672 static void module_init(PyObject *mod)
673 673 {
@@ -109,6 +109,9 b' static const Py_ssize_t nullrev = -1;'
109 109
110 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 115 #if LONG_MAX == 0x7fffffffL
113 116 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
114 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 583 static inline void set_phase_from_parents(char *phases, int parent_1,
609 584 int parent_2, Py_ssize_t i)
610 585 {
@@ -773,99 +748,165 b' bail:'
773 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 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 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 796 PyObject *phaseroots = NULL;
782 PyObject *phaseset = NULL;
783 PyObject *phasessetlist = NULL;
784 PyObject *rev = NULL;
797 PyObject *phasessize = NULL;
798 PyObject *phasesets[4] = {NULL, NULL, NULL, NULL};
785 799 Py_ssize_t len = index_length(self);
786 Py_ssize_t numphase = 0;
787 Py_ssize_t minrevallphases = 0;
788 Py_ssize_t minrevphase = 0;
789 Py_ssize_t i = 0;
800 const char *currentphase;
790 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 805 if (!PyArg_ParseTuple(args, "O", &roots))
794 goto done;
795 if (roots == NULL || !PyList_Check(roots)) {
796 PyErr_SetString(PyExc_TypeError, "roots must be a list");
797 goto done;
806 return NULL;
807 if (roots == NULL || !PyDict_Check(roots)) {
808 PyErr_SetString(PyExc_TypeError, "roots must be a dictionary");
809 return NULL;
798 810 }
799 811
800 phases = calloc(
801 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
812 phases = calloc(len, 1);
802 813 if (phases == NULL) {
803 814 PyErr_NoMemory();
804 goto done;
815 return NULL;
805 816 }
806 /* Put the phase information of all the roots in phases */
807 numphase = PyList_GET_SIZE(roots) + 1;
808 minrevallphases = len + 1;
809 phasessetlist = PyList_New(numphase);
810 if (phasessetlist == NULL)
811 goto done;
812 817
813 PyList_SET_ITEM(phasessetlist, 0, Py_None);
814 Py_INCREF(Py_None);
818 for (i = 0; i < numphases; ++i) {
819 pyphase = PyInt_FromLong(trackedphases[i]);
820 if (pyphase == NULL)
821 goto release;
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 }
815 833
816 for (i = 0; i < numphase - 1; i++) {
817 phaseroots = PyList_GET_ITEM(roots, i);
818 phaseset = PySet_New(NULL);
819 if (phaseset == NULL)
820 goto release;
821 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
822 if (!PyList_Check(phaseroots)) {
823 PyErr_SetString(PyExc_TypeError,
824 "roots item must be a list");
834 for (i = 0; i < numphases; ++i) {
835 phasesets[i] = PySet_New(NULL);
836 if (phasesets[i] == NULL)
825 837 goto release;
826 838 }
827 minrevphase =
828 add_roots_get_min(self, phaseroots, i + 1, phases);
829 if (minrevphase == -2) /* Error from add_roots_get_min */
830 goto release;
831 minrevallphases = MIN(minrevallphases, minrevphase);
832 }
833 /* Propagate the phase information from the roots to the revs */
834 if (minrevallphases != -1) {
839
840 if (minphaserev == -1)
841 minphaserev = len;
842 for (rev = minphaserev; rev < len; ++rev) {
835 843 int parents[2];
836 for (i = minrevallphases; i < len; i++) {
837 if (index_get_parents(self, i, parents, (int)len - 1) <
838 0)
844 /*
845 * The parent lookup could be skipped for phaseroots, but
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)
839 851 goto release;
840 set_phase_from_parents(phases, parents[0], parents[1],
841 i);
852 set_phase_from_parents(phases, parents[0], parents[1], rev);
853 switch (phases[rev]) {
854 case 0:
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:
869 goto release;
842 870 }
871 pyrev = PyInt_FromLong(rev);
872 if (pyrev == NULL)
873 goto release;
874 if (PySet_Add(pyphase, pyrev) == -1) {
875 Py_DECREF(pyrev);
876 goto release;
843 877 }
844 /* Transform phase list to a python list */
878 Py_DECREF(pyrev);
879 }
880 phaseroots = _dict_new_presized(numphases);
881 if (phaseroots == NULL)
882 goto release;
883 for (int i = 0; i < numphases; ++i) {
884 pyphase = PyInt_FromLong(trackedphases[i]);
885 if (pyphase == NULL)
886 goto release;
887 if (PyDict_SetItem(phaseroots, pyphase, phasesets[i]) == -1) {
888 Py_DECREF(pyphase);
889 goto release;
890 }
891 Py_DECREF(phasesets[i]);
892 phasesets[i] = NULL;
893 }
845 894 phasessize = PyInt_FromSsize_t(len);
846 895 if (phasessize == NULL)
847 896 goto release;
848 for (i = 0; i < len; i++) {
849 phase = phases[i];
850 /* We only store the sets of phase for non public phase, the
851 * public phase is computed as a difference */
852 if (phase != 0) {
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);
897
898 ret = PyTuple_Pack(2, phasessize, phaseroots);
899 Py_DECREF(phasessize);
900 Py_DECREF(phaseroots);
901 return ret;
862 902
863 903 release:
864 Py_XDECREF(phasessize);
865 Py_XDECREF(phasessetlist);
866 done:
904 for (i = 0; i < numphases; ++i)
905 Py_XDECREF(phasesets[i]);
906 Py_XDECREF(phaseroots);
907
867 908 free(phases);
868 return ret;
909 return NULL;
869 910 }
870 911
871 912 static PyObject *index_headrevs(indexObject *self, PyObject *args)
@@ -170,7 +170,7 b' def _readroots(repo, phasedefaults=None)'
170 170 """
171 171 repo = repo.unfiltered()
172 172 dirty = False
173 roots = [set() for i in range(max(allphases) + 1)]
173 roots = {i: set() for i in allphases}
174 174 try:
175 175 f, pending = txnutil.trypending(repo.root, repo.svfs, b'phaseroots')
176 176 try:
@@ -333,7 +333,11 b' class phasecache(object):'
333 333 if len(cl) >= self._loadedrevslen:
334 334 self.invalidate()
335 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 342 def nonpublicphaseroots(self, repo):
339 343 """returns the roots of all non-public phases
@@ -346,7 +350,13 b' class phasecache(object):'
346 350 if len(cl) >= self._loadedrevslen:
347 351 self.invalidate()
348 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 361 def getrevset(self, repo, phases, subset=None):
352 362 """return a smartset for the given phases"""
@@ -405,7 +415,7 b' class phasecache(object):'
405 415 # Shallow copy meant to ensure isolation in
406 416 # advance/retractboundary(), nothing more.
407 417 ph = self.__class__(None, None, _load=False)
408 ph.phaseroots = self.phaseroots[:]
418 ph.phaseroots = self.phaseroots.copy()
409 419 ph.dirty = self.dirty
410 420 ph.opener = self.opener
411 421 ph._loadedrevslen = self._loadedrevslen
@@ -425,21 +435,12 b' class phasecache(object):'
425 435
426 436 def _getphaserevsnative(self, repo):
427 437 repo = repo.unfiltered()
428 nativeroots = []
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 return repo.changelog.computephases(self.phaseroots)
438 439
439 440 def _computephaserevspure(self, repo):
440 441 repo = repo.unfiltered()
441 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 444 lowerroots = set()
444 445 for phase in reversed(trackedphases):
445 446 roots = pycompat.maplist(cl.rev, self.phaseroots[phase])
@@ -493,7 +494,7 b' class phasecache(object):'
493 494 f.close()
494 495
495 496 def _write(self, fp):
496 for phase, roots in enumerate(self.phaseroots):
497 for phase, roots in pycompat.iteritems(self.phaseroots):
497 498 for h in sorted(roots):
498 499 fp.write(b'%i %s\n' % (phase, hex(h)))
499 500 self.dirty = False
@@ -575,7 +576,11 b' class phasecache(object):'
575 576 return changes
576 577
577 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 584 if tr is None:
580 585 phasetracking = None
581 586 else:
@@ -594,7 +599,7 b' class phasecache(object):'
594 599 # find the phase of the affected revision
595 600 for phase in pycompat.xrange(targetphase, -1, -1):
596 601 if phase:
597 roots = oldroots[phase]
602 roots = oldroots.get(phase, [])
598 603 revs = set(repo.revs(b'%ln::%ld', roots, affected))
599 604 affected -= revs
600 605 else: # public phase
@@ -648,7 +653,7 b' class phasecache(object):'
648 653 """
649 654 filtered = False
650 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 657 missing = sorted(node for node in nodes if not has_node(node))
653 658 if missing:
654 659 for mnode in missing:
@@ -80,7 +80,7 b' def _importfrom(pkgname, modname):'
80 80 ('cext', 'bdiff'): 3,
81 81 ('cext', 'mpatch'): 1,
82 82 ('cext', 'osutil'): 4,
83 ('cext', 'parsers'): 16,
83 ('cext', 'parsers'): 17,
84 84 }
85 85
86 86 # map import request to other package or module
@@ -185,7 +185,7 b' Test corrupted p1/p2 fields that could c'
185 185 > ops = [
186 186 > ('reachableroots',
187 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 189 > ('index_headrevs', lambda: cl.headrevs()),
190 190 > ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
191 191 > ('find_deepest', lambda: cl.ancestor(n0, n1)),
General Comments 0
You need to be logged in to leave comments. Login now