bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
1  | 
# Copyright (C) 2009 Canonical Ltd
 | 
2  | 
#
 | 
|
3  | 
# This program is free software; you can redistribute it and/or modify
 | 
|
4  | 
# it under the terms of the GNU General Public License as published by
 | 
|
5  | 
# the Free Software Foundation; either version 2 of the License, or
 | 
|
6  | 
# (at your option) any later version.
 | 
|
7  | 
#
 | 
|
8  | 
# This program is distributed in the hope that it will be useful,
 | 
|
9  | 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|
10  | 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|
11  | 
# GNU General Public License for more details.
 | 
|
12  | 
#
 | 
|
13  | 
# You should have received a copy of the GNU General Public License
 | 
|
14  | 
# along with this program; if not, write to the Free Software
 | 
|
15  | 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
|
16  | 
||
17  | 
"""Implementation of Graph algorithms when we have already loaded everything.
 | 
|
18  | 
"""
 | 
|
19  | 
||
20  | 
cdef extern from "python-compat.h":  | 
|
21  | 
    pass
 | 
|
22  | 
||
23  | 
cdef extern from "Python.h":  | 
|
24  | 
ctypedef int Py_ssize_t  | 
|
25  | 
ctypedef struct PyObject:  | 
|
26  | 
        pass
 | 
|
27  | 
||
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
28  | 
object PyTuple_New(Py_ssize_t n)  | 
| 
4371.4.23
by John Arbash Meinel
 Clean up the imports at the top.  | 
29  | 
Py_ssize_t PyTuple_GET_SIZE(object t)  | 
30  | 
PyObject * PyTuple_GET_ITEM(object t, Py_ssize_t o)  | 
|
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
31  | 
void PyTuple_SET_ITEM(object t, Py_ssize_t o, object v)  | 
| 
4371.4.23
by John Arbash Meinel
 Clean up the imports at the top.  | 
32  | 
|
33  | 
Py_ssize_t PyList_GET_SIZE(object l)  | 
|
34  | 
PyObject * PyList_GET_ITEM(object l, Py_ssize_t o)  | 
|
35  | 
int PyList_SetItem(object l, Py_ssize_t o, object l) except -1  | 
|
36  | 
int PyList_Append(object l, object v) except -1  | 
|
37  | 
||
38  | 
int PyDict_CheckExact(object d)  | 
|
39  | 
Py_ssize_t PyDict_Size(object d) except -1  | 
|
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
40  | 
PyObject * PyDict_GetItem(object d, object k)  | 
| 
4371.4.23
by John Arbash Meinel
 Clean up the imports at the top.  | 
41  | 
int PyDict_SetItem(object d, object k, object v) except -1  | 
| 
4371.4.18
by John Arbash Meinel
 Big performance win, back to 650ms.  | 
42  | 
int PyDict_DelItem(object d, object k) except -1  | 
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
43  | 
int PyDict_Next(object d, Py_ssize_t *pos, PyObject **k, PyObject **v)  | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
44  | 
|
| 
4371.3.20
by John Arbash Meinel
 A few tweaks to the pyrex version.  | 
45  | 
void Py_INCREF(object)  | 
46  | 
||
| 
4371.3.21
by John Arbash Meinel
 Attempt to make things better by splitting out left_parent and right_parent into  | 
47  | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
48  | 
from bzrlib import revision  | 
49  | 
||
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
50  | 
cdef object NULL_REVISION  | 
51  | 
NULL_REVISION = revision.NULL_REVISION  | 
|
52  | 
||
53  | 
||
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
54  | 
cdef class _KnownGraphNode:  | 
55  | 
"""Represents a single object in the known graph."""  | 
|
56  | 
||
| 
4371.3.35
by John Arbash Meinel
 Changing the heapq algorithm actually ends up with better overall performance.  | 
57  | 
cdef object key  | 
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
58  | 
cdef object parents  | 
59  | 
cdef object children  | 
|
| 
4371.4.13
by Vincent Ladeuil
 Fixed as per John's review.  | 
60  | 
cdef public long gdfo  | 
| 
4371.4.22
by John Arbash Meinel
 Changing from a set of seen to a list to cleanup and a seen attribute.  | 
61  | 
cdef int seen  | 
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
62  | 
|
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
63  | 
def __init__(self, key):  | 
| 
4371.3.21
by John Arbash Meinel
 Attempt to make things better by splitting out left_parent and right_parent into  | 
64  | 
cdef int i  | 
65  | 
||
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
66  | 
self.key = key  | 
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
67  | 
self.parents = None  | 
| 
4371.3.21
by John Arbash Meinel
 Attempt to make things better by splitting out left_parent and right_parent into  | 
68  | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
69  | 
self.children = []  | 
70  | 
        # Greatest distance from origin
 | 
|
71  | 
self.gdfo = -1  | 
|
| 
4371.4.22
by John Arbash Meinel
 Changing from a set of seen to a list to cleanup and a seen attribute.  | 
72  | 
self.seen = 0  | 
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
73  | 
|
74  | 
property child_keys:  | 
|
75  | 
def __get__(self):  | 
|
76  | 
cdef _KnownGraphNode child  | 
|
77  | 
||
78  | 
keys = []  | 
|
79  | 
for child in self.children:  | 
|
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
80  | 
PyList_Append(keys, child.key)  | 
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
81  | 
return keys  | 
82  | 
||
83  | 
cdef clear_references(self):  | 
|
84  | 
self.parents = None  | 
|
85  | 
self.children = None  | 
|
86  | 
||
87  | 
def __repr__(self):  | 
|
| 
4371.3.35
by John Arbash Meinel
 Changing the heapq algorithm actually ends up with better overall performance.  | 
88  | 
cdef _KnownGraphNode node  | 
89  | 
||
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
90  | 
parent_keys = []  | 
| 
4371.3.35
by John Arbash Meinel
 Changing the heapq algorithm actually ends up with better overall performance.  | 
91  | 
if self.parents is not None:  | 
92  | 
for node in self.parents:  | 
|
93  | 
parent_keys.append(node.key)  | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
94  | 
child_keys = []  | 
| 
4371.3.35
by John Arbash Meinel
 Changing the heapq algorithm actually ends up with better overall performance.  | 
95  | 
if self.children is not None:  | 
96  | 
for node in self.children:  | 
|
97  | 
child_keys.append(node.key)  | 
|
| 
4371.4.10
by Vincent Ladeuil
 Cleanup.  | 
98  | 
return '%s(%s gdfo:%s par:%s child:%s)' % (  | 
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
99  | 
self.__class__.__name__, self.key, self.gdfo,  | 
| 
4371.4.12
by Vincent Ladeuil
 Fix typos.  | 
100  | 
parent_keys, child_keys)  | 
| 
4371.4.10
by Vincent Ladeuil
 Cleanup.  | 
101  | 
|
| 
4371.3.37
by John Arbash Meinel
 cleanup passes.  | 
102  | 
|
| 
4371.4.14
by John Arbash Meinel
 Optimize _find_gdfo and make known_parent_gdfos a member of KnownGraphNode  | 
103  | 
cdef _KnownGraphNode _get_list_node(lst, Py_ssize_t pos):  | 
104  | 
cdef PyObject *temp_node  | 
|
105  | 
||
106  | 
temp_node = PyList_GET_ITEM(lst, pos)  | 
|
107  | 
return <_KnownGraphNode>temp_node  | 
|
108  | 
||
109  | 
||
110  | 
cdef _KnownGraphNode _get_parent(parents, Py_ssize_t pos):  | 
|
111  | 
cdef PyObject *temp_node  | 
|
112  | 
cdef _KnownGraphNode node  | 
|
113  | 
||
114  | 
temp_node = PyTuple_GET_ITEM(parents, pos)  | 
|
115  | 
return <_KnownGraphNode>temp_node  | 
|
116  | 
||
117  | 
||
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
118  | 
# TODO: slab allocate all _KnownGraphNode objects.
 | 
| 
4371.3.26
by John Arbash Meinel
 A few more cleanups. Start moving away from pyrex 0.9.8isms  | 
119  | 
#       We already know how many we are going to need, except for a couple of
 | 
120  | 
#       ghosts that could be allocated on demand.
 | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
121  | 
|
122  | 
cdef class KnownGraph:  | 
|
123  | 
"""This is a class which assumes we already know the full graph."""  | 
|
124  | 
||
125  | 
cdef public object _nodes  | 
|
| 
4371.3.26
by John Arbash Meinel
 A few more cleanups. Start moving away from pyrex 0.9.8isms  | 
126  | 
cdef object _known_heads  | 
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
127  | 
cdef public int do_cache  | 
128  | 
||
129  | 
def __init__(self, parent_map, do_cache=True):  | 
|
130  | 
"""Create a new KnownGraph instance.  | 
|
131  | 
||
132  | 
        :param parent_map: A dictionary mapping key => parent_keys
 | 
|
133  | 
        """
 | 
|
| 
4371.4.29
by John Arbash Meinel
 Pre-allocating self._nodes turned out to be slower.  | 
134  | 
        # tests at pre-allocating the node dict actually slowed things down
 | 
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
135  | 
self._nodes = {}  | 
136  | 
        # Maps {sorted(revision_id, revision_id): heads}
 | 
|
137  | 
self._known_heads = {}  | 
|
138  | 
self.do_cache = int(do_cache)  | 
|
139  | 
self._initialize_nodes(parent_map)  | 
|
140  | 
self._find_gdfo()  | 
|
141  | 
||
142  | 
def __dealloc__(self):  | 
|
143  | 
cdef _KnownGraphNode child  | 
|
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
144  | 
cdef Py_ssize_t pos  | 
145  | 
cdef PyObject *temp_node  | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
146  | 
|
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
147  | 
while PyDict_Next(self._nodes, &pos, NULL, &temp_node):  | 
148  | 
child = <_KnownGraphNode>temp_node  | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
149  | 
child.clear_references()  | 
150  | 
||
| 
4371.4.28
by John Arbash Meinel
 We spent a lot of time adding and removing keys from tails.  | 
151  | 
cdef _KnownGraphNode _get_or_create_node(self, key):  | 
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
152  | 
cdef PyObject *temp_node  | 
153  | 
cdef _KnownGraphNode node  | 
|
154  | 
||
155  | 
temp_node = PyDict_GetItem(self._nodes, key)  | 
|
156  | 
if temp_node == NULL:  | 
|
157  | 
node = _KnownGraphNode(key)  | 
|
158  | 
PyDict_SetItem(self._nodes, key, node)  | 
|
159  | 
else:  | 
|
160  | 
node = <_KnownGraphNode>temp_node  | 
|
161  | 
return node  | 
|
162  | 
||
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
163  | 
def _initialize_nodes(self, parent_map):  | 
164  | 
"""Populate self._nodes.  | 
|
165  | 
||
| 
4371.4.9
by Vincent Ladeuil
 Simplify gdfo computing by finding tails when at graph build time.  | 
166  | 
        After this has finished:
 | 
167  | 
        - self._nodes will have an entry for every entry in parent_map.
 | 
|
168  | 
        - ghosts will have a parent_keys = None,
 | 
|
| 
4371.4.12
by Vincent Ladeuil
 Fix typos.  | 
169  | 
        - all nodes found will also have child_keys populated with all known
 | 
170  | 
          child keys,
 | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
171  | 
        """
 | 
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
172  | 
cdef PyObject *temp_key, *temp_parent_keys, *temp_node  | 
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
173  | 
cdef Py_ssize_t pos, pos2, num_parent_keys  | 
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
174  | 
cdef _KnownGraphNode node  | 
175  | 
cdef _KnownGraphNode parent_node  | 
|
176  | 
||
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
177  | 
if not PyDict_CheckExact(parent_map):  | 
178  | 
raise TypeError('parent_map should be a dict of {key:parent_keys}')  | 
|
179  | 
        # for key, parent_keys in parent_map.iteritems():
 | 
|
180  | 
pos = 0  | 
|
181  | 
while PyDict_Next(parent_map, &pos, &temp_key, &temp_parent_keys):  | 
|
182  | 
key = <object>temp_key  | 
|
183  | 
parent_keys = <object>temp_parent_keys  | 
|
| 
4371.4.9
by Vincent Ladeuil
 Simplify gdfo computing by finding tails when at graph build time.  | 
184  | 
num_parent_keys = len(parent_keys)  | 
| 
4371.4.28
by John Arbash Meinel
 We spent a lot of time adding and removing keys from tails.  | 
185  | 
node = self._get_or_create_node(key)  | 
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
186  | 
            # We know how many parents, so we could pre allocate an exact sized
 | 
187  | 
            # tuple here
 | 
|
188  | 
parent_nodes = PyTuple_New(num_parent_keys)  | 
|
189  | 
            # We use iter here, because parent_keys maybe be a list or tuple
 | 
|
190  | 
for pos2 from 0 <= pos2 < num_parent_keys:  | 
|
| 
4371.4.28
by John Arbash Meinel
 We spent a lot of time adding and removing keys from tails.  | 
191  | 
parent_node = self._get_or_create_node(parent_keys[pos2])  | 
| 
4371.3.31
by John Arbash Meinel
 Change _KnownGraph.parents to be a tuple rather than a list.  | 
192  | 
                # PyTuple_SET_ITEM will steal a reference, so INCREF first
 | 
193  | 
Py_INCREF(parent_node)  | 
|
194  | 
PyTuple_SET_ITEM(parent_nodes, pos2, parent_node)  | 
|
| 
4371.3.28
by John Arbash Meinel
 Finish converting away from 'cdef list' syntax.  | 
195  | 
PyList_Append(parent_node.children, node)  | 
196  | 
node.parents = parent_nodes  | 
|
| 
4371.4.30
by John Arbash Meinel
 We don't need self._tails anymore, nor does it need to be a set.  | 
197  | 
|
198  | 
def _find_tails(self):  | 
|
199  | 
cdef PyObject *temp_node  | 
|
200  | 
cdef _KnownGraphNode node  | 
|
201  | 
cdef Py_ssize_t pos  | 
|
202  | 
||
203  | 
tails = []  | 
|
| 
4371.4.28
by John Arbash Meinel
 We spent a lot of time adding and removing keys from tails.  | 
204  | 
pos = 0  | 
205  | 
while PyDict_Next(self._nodes, &pos, NULL, &temp_node):  | 
|
206  | 
node = <_KnownGraphNode>temp_node  | 
|
207  | 
if node.parents is None or PyTuple_GET_SIZE(node.parents) == 0:  | 
|
| 
4371.4.30
by John Arbash Meinel
 We don't need self._tails anymore, nor does it need to be a set.  | 
208  | 
node.gdfo = 1  | 
209  | 
PyList_Append(tails, node)  | 
|
210  | 
return tails  | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
211  | 
|
212  | 
def _find_gdfo(self):  | 
|
| 
4371.4.8
by Vincent Ladeuil
 Replace the existing KnownGraph._find_gdfo.  | 
213  | 
cdef _KnownGraphNode node  | 
214  | 
cdef _KnownGraphNode child  | 
|
| 
4371.4.14
by John Arbash Meinel
 Optimize _find_gdfo and make known_parent_gdfos a member of KnownGraphNode  | 
215  | 
cdef PyObject *temp  | 
| 
4371.4.30
by John Arbash Meinel
 We don't need self._tails anymore, nor does it need to be a set.  | 
216  | 
cdef Py_ssize_t pos  | 
| 
4371.4.14
by John Arbash Meinel
 Optimize _find_gdfo and make known_parent_gdfos a member of KnownGraphNode  | 
217  | 
cdef int replace  | 
| 
4371.4.26
by John Arbash Meinel
 Don't shrink the pending list.  | 
218  | 
cdef Py_ssize_t last_item  | 
| 
4371.4.25
by John Arbash Meinel
 We had an 'child_node.gdfo is None' check in the inner loop.  | 
219  | 
cdef long next_gdfo  | 
| 
4371.4.8
by Vincent Ladeuil
 Replace the existing KnownGraph._find_gdfo.  | 
220  | 
|
| 
4371.4.30
by John Arbash Meinel
 We don't need self._tails anymore, nor does it need to be a set.  | 
221  | 
pending = self._find_tails()  | 
| 
4371.4.8
by Vincent Ladeuil
 Replace the existing KnownGraph._find_gdfo.  | 
222  | 
|
| 
4371.4.26
by John Arbash Meinel
 Don't shrink the pending list.  | 
223  | 
last_item = PyList_GET_SIZE(pending) - 1  | 
224  | 
while last_item >= 0:  | 
|
| 
4371.4.14
by John Arbash Meinel
 Optimize _find_gdfo and make known_parent_gdfos a member of KnownGraphNode  | 
225  | 
            # Avoid pop followed by push, instead, peek, and replace
 | 
| 
4371.4.16
by John Arbash Meinel
 Document some perf issues with using known_parent_gdfos, but leave it as a dict.  | 
226  | 
            # timing shows this is 930ms => 770ms for OOo
 | 
| 
4371.4.26
by John Arbash Meinel
 Don't shrink the pending list.  | 
227  | 
node = _get_list_node(pending, last_item)  | 
228  | 
last_item = last_item - 1  | 
|
| 
4371.4.25
by John Arbash Meinel
 We had an 'child_node.gdfo is None' check in the inner loop.  | 
229  | 
next_gdfo = node.gdfo + 1  | 
| 
4371.4.30
by John Arbash Meinel
 We don't need self._tails anymore, nor does it need to be a set.  | 
230  | 
for pos from 0 <= pos < PyList_GET_SIZE(node.children):  | 
231  | 
child = _get_list_node(node.children, pos)  | 
|
| 
4371.4.25
by John Arbash Meinel
 We had an 'child_node.gdfo is None' check in the inner loop.  | 
232  | 
if next_gdfo > child.gdfo:  | 
233  | 
child.gdfo = next_gdfo  | 
|
| 
4371.4.27
by John Arbash Meinel
 Re-use the child.seen attribute for tracking num parents.  | 
234  | 
child.seen = child.seen + 1  | 
235  | 
if child.seen == PyTuple_GET_SIZE(child.parents):  | 
|
| 
4371.4.17
by John Arbash Meinel
 tried a different tack, to use a new list and append.  | 
236  | 
                    # This child is populated, queue it to be walked
 | 
| 
4371.4.26
by John Arbash Meinel
 Don't shrink the pending list.  | 
237  | 
last_item = last_item + 1  | 
238  | 
if last_item < PyList_GET_SIZE(pending):  | 
|
| 
4371.4.14
by John Arbash Meinel
 Optimize _find_gdfo and make known_parent_gdfos a member of KnownGraphNode  | 
239  | 
Py_INCREF(child) # SetItem steals a ref  | 
| 
4371.4.26
by John Arbash Meinel
 Don't shrink the pending list.  | 
240  | 
PyList_SetItem(pending, last_item, child)  | 
| 
4371.4.14
by John Arbash Meinel
 Optimize _find_gdfo and make known_parent_gdfos a member of KnownGraphNode  | 
241  | 
else:  | 
242  | 
PyList_Append(pending, child)  | 
|
| 
4371.4.27
by John Arbash Meinel
 Re-use the child.seen attribute for tracking num parents.  | 
243  | 
                    # We have queued this node, we don't need to track it
 | 
244  | 
                    # anymore
 | 
|
245  | 
child.seen = 0  | 
|
| 
4371.4.8
by Vincent Ladeuil
 Replace the existing KnownGraph._find_gdfo.  | 
246  | 
|
| 
4371.3.19
by John Arbash Meinel
 Get an initial pyrex implementation.  | 
247  | 
def heads(self, keys):  | 
248  | 
"""Return the heads from amongst keys.  | 
|
249  | 
||
250  | 
        This is done by searching the ancestries of each key.  Any key that is
 | 
|
251  | 
        reachable from another key is not returned; all the others are.
 | 
|
252  | 
||
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
253  | 
        This operation scales with the relative depth between any two keys. It
 | 
254  | 
        uses gdfo to avoid walking all ancestry.
 | 
|
255  | 
||
256  | 
        :param keys: An iterable of keys.
 | 
|
257  | 
        :return: A set of the heads. Note that as a set there is no ordering
 | 
|
258  | 
            information. Callers will need to filter their input to create
 | 
|
259  | 
            order if they need it.
 | 
|
260  | 
        """
 | 
|
261  | 
cdef PyObject *maybe_node  | 
|
262  | 
cdef PyObject *maybe_heads  | 
|
263  | 
cdef PyObject *temp_node  | 
|
264  | 
cdef _KnownGraphNode node  | 
|
| 
4371.4.31
by John Arbash Meinel
 Apply the same 'never pop' logic to the heads() code.  | 
265  | 
cdef Py_ssize_t pos, last_item  | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
266  | 
cdef long min_gdfo  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
267  | 
|
| 
4526.10.1
by John Arbash Meinel
 Avoid using PyFrozenSet_New  | 
268  | 
heads_key = frozenset(keys)  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
269  | 
maybe_heads = PyDict_GetItem(self._known_heads, heads_key)  | 
270  | 
if maybe_heads != NULL:  | 
|
271  | 
return <object>maybe_heads  | 
|
272  | 
        # Not cached, compute it ourselves
 | 
|
273  | 
candidate_nodes = {}  | 
|
274  | 
for key in keys:  | 
|
| 
4371.4.28
by John Arbash Meinel
 We spent a lot of time adding and removing keys from tails.  | 
275  | 
maybe_node = PyDict_GetItem(self._nodes, key)  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
276  | 
if maybe_node == NULL:  | 
277  | 
raise KeyError('key %s not in nodes' % (key,))  | 
|
278  | 
PyDict_SetItem(candidate_nodes, key, <object>maybe_node)  | 
|
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
279  | 
maybe_node = PyDict_GetItem(candidate_nodes, NULL_REVISION)  | 
280  | 
if maybe_node != NULL:  | 
|
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
281  | 
            # NULL_REVISION is only a head if it is the only entry
 | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
282  | 
candidate_nodes.pop(NULL_REVISION)  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
283  | 
if not candidate_nodes:  | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
284  | 
return frozenset([NULL_REVISION])  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
285  | 
            # The keys changed, so recalculate heads_key
 | 
| 
4526.10.1
by John Arbash Meinel
 Avoid using PyFrozenSet_New  | 
286  | 
heads_key = frozenset(candidate_nodes)  | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
287  | 
if PyDict_Size(candidate_nodes) < 2:  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
288  | 
return heads_key  | 
289  | 
||
| 
4371.4.22
by John Arbash Meinel
 Changing from a set of seen to a list to cleanup and a seen attribute.  | 
290  | 
cleanup = []  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
291  | 
pending = []  | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
292  | 
        # we know a gdfo cannot be longer than a linear chain of all nodes
 | 
293  | 
min_gdfo = PyDict_Size(self._nodes) + 1  | 
|
294  | 
        # Build up nodes that need to be walked, note that starting nodes are
 | 
|
295  | 
        # not added to seen()
 | 
|
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
296  | 
pos = 0  | 
297  | 
while PyDict_Next(candidate_nodes, &pos, NULL, &temp_node):  | 
|
298  | 
node = <_KnownGraphNode>temp_node  | 
|
299  | 
if node.parents is not None:  | 
|
300  | 
pending.extend(node.parents)  | 
|
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
301  | 
if node.gdfo < min_gdfo:  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
302  | 
min_gdfo = node.gdfo  | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
303  | 
|
304  | 
        # Now do all the real work
 | 
|
| 
4371.4.31
by John Arbash Meinel
 Apply the same 'never pop' logic to the heads() code.  | 
305  | 
last_item = PyList_GET_SIZE(pending) - 1  | 
306  | 
while last_item >= 0:  | 
|
307  | 
node = _get_list_node(pending, last_item)  | 
|
308  | 
last_item = last_item - 1  | 
|
| 
4371.4.22
by John Arbash Meinel
 Changing from a set of seen to a list to cleanup and a seen attribute.  | 
309  | 
if node.seen:  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
310  | 
                # node already appears in some ancestry
 | 
311  | 
                continue
 | 
|
| 
4371.4.22
by John Arbash Meinel
 Changing from a set of seen to a list to cleanup and a seen attribute.  | 
312  | 
PyList_Append(cleanup, node)  | 
313  | 
node.seen = 1  | 
|
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
314  | 
if node.gdfo <= min_gdfo:  | 
315  | 
                continue
 | 
|
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
316  | 
if node.parents is not None and PyTuple_GET_SIZE(node.parents) > 0:  | 
317  | 
for pos from 0 <= pos < PyTuple_GET_SIZE(node.parents):  | 
|
318  | 
parent_node = _get_parent(node.parents, pos)  | 
|
| 
4371.4.31
by John Arbash Meinel
 Apply the same 'never pop' logic to the heads() code.  | 
319  | 
last_item = last_item + 1  | 
320  | 
if last_item < PyList_GET_SIZE(pending):  | 
|
321  | 
Py_INCREF(parent_node) # SetItem steals a ref  | 
|
322  | 
PyList_SetItem(pending, last_item, parent_node)  | 
|
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
323  | 
else:  | 
324  | 
PyList_Append(pending, parent_node)  | 
|
| 
4371.4.22
by John Arbash Meinel
 Changing from a set of seen to a list to cleanup and a seen attribute.  | 
325  | 
heads = []  | 
326  | 
pos = 0  | 
|
327  | 
while PyDict_Next(candidate_nodes, &pos, NULL, &temp_node):  | 
|
328  | 
node = <_KnownGraphNode>temp_node  | 
|
329  | 
if not node.seen:  | 
|
330  | 
PyList_Append(heads, node.key)  | 
|
| 
4526.10.1
by John Arbash Meinel
 Avoid using PyFrozenSet_New  | 
331  | 
heads = frozenset(heads)  | 
| 
4371.4.22
by John Arbash Meinel
 Changing from a set of seen to a list to cleanup and a seen attribute.  | 
332  | 
for pos from 0 <= pos < PyList_GET_SIZE(cleanup):  | 
333  | 
node = _get_list_node(cleanup, pos)  | 
|
334  | 
node.seen = 0  | 
|
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
335  | 
if self.do_cache:  | 
| 
4371.4.21
by John Arbash Meinel
 Spend some time optimizing the inner heads() loop, approx 2x faster.  | 
336  | 
PyDict_SetItem(self._known_heads, heads_key, heads)  | 
| 
4371.4.7
by Vincent Ladeuil
 Simple Pyrex version for the new heads() method.  | 
337  | 
return heads  |