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 = 1 |
|
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 * |
|
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 *phasese |
|
797 | PyObject *phasessize = NULL; | |
783 |
PyObject *phases |
|
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 || !Py |
|
807 | if (roots == NULL || !PyDict_Check(roots)) { | |
796 |
PyErr_SetString(PyExc_TypeError, "roots must be a |
|
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 |
|
|
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(phases |
|
905 | Py_XDECREF(phasesets[i]); | |
866 | done: |
|
906 | Py_XDECREF(phaseroots); | |
|
907 | ||||
867 | free(phases); |
|
908 | free(phases); | |
868 |
return |
|
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 = |
|
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( |
|
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 = |
|
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 |
|
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[ |
|
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 |
|
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'): 1 |
|
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( |
|
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