##// END OF EJS Templates
index: handle index[-1] as nullid more explicitly...
Martin von Zweigbergk -
r38883:f3d394ea default
parent child Browse files
Show More
@@ -1,2184 +1,2184
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #include <Python.h>
10 #include <Python.h>
11 #include <assert.h>
11 #include <assert.h>
12 #include <ctype.h>
12 #include <ctype.h>
13 #include <stddef.h>
13 #include <stddef.h>
14 #include <string.h>
14 #include <string.h>
15
15
16 #include "bitmanipulation.h"
16 #include "bitmanipulation.h"
17 #include "charencode.h"
17 #include "charencode.h"
18 #include "util.h"
18 #include "util.h"
19
19
20 #ifdef IS_PY3K
20 #ifdef IS_PY3K
21 /* The mapping of Python types is meant to be temporary to get Python
21 /* The mapping of Python types is meant to be temporary to get Python
22 * 3 to compile. We should remove this once Python 3 support is fully
22 * 3 to compile. We should remove this once Python 3 support is fully
23 * supported and proper types are used in the extensions themselves. */
23 * supported and proper types are used in the extensions themselves. */
24 #define PyInt_Check PyLong_Check
24 #define PyInt_Check PyLong_Check
25 #define PyInt_FromLong PyLong_FromLong
25 #define PyInt_FromLong PyLong_FromLong
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
27 #define PyInt_AS_LONG PyLong_AS_LONG
27 #define PyInt_AS_LONG PyLong_AS_LONG
28 #define PyInt_AsLong PyLong_AsLong
28 #define PyInt_AsLong PyLong_AsLong
29 #endif
29 #endif
30
30
31 /*
31 /*
32 * A base-16 trie for fast node->rev mapping.
32 * A base-16 trie for fast node->rev mapping.
33 *
33 *
34 * Positive value is index of the next node in the trie
34 * Positive value is index of the next node in the trie
35 * Negative value is a leaf: -(rev + 2)
35 * Negative value is a leaf: -(rev + 2)
36 * Zero is empty
36 * Zero is empty
37 */
37 */
38 typedef struct {
38 typedef struct {
39 int children[16];
39 int children[16];
40 } nodetree;
40 } nodetree;
41
41
42 /*
42 /*
43 * This class has two behaviors.
43 * This class has two behaviors.
44 *
44 *
45 * When used in a list-like way (with integer keys), we decode an
45 * When used in a list-like way (with integer keys), we decode an
46 * entry in a RevlogNG index file on demand. Our last entry is a
46 * entry in a RevlogNG index file on demand. Our last entry is a
47 * sentinel, always a nullid. We have limited support for
47 * sentinel, always a nullid. We have limited support for
48 * integer-keyed insert and delete, only at elements right before the
48 * integer-keyed insert and delete, only at elements right before the
49 * sentinel.
49 * sentinel.
50 *
50 *
51 * With string keys, we lazily perform a reverse mapping from node to
51 * With string keys, we lazily perform a reverse mapping from node to
52 * rev, using a base-16 trie.
52 * rev, using a base-16 trie.
53 */
53 */
54 typedef struct {
54 typedef struct {
55 PyObject_HEAD
55 PyObject_HEAD
56 /* Type-specific fields go here. */
56 /* Type-specific fields go here. */
57 PyObject *data; /* raw bytes of index */
57 PyObject *data; /* raw bytes of index */
58 Py_buffer buf; /* buffer of data */
58 Py_buffer buf; /* buffer of data */
59 PyObject **cache; /* cached tuples */
59 PyObject **cache; /* cached tuples */
60 const char **offsets; /* populated on demand */
60 const char **offsets; /* populated on demand */
61 Py_ssize_t raw_length; /* original number of elements */
61 Py_ssize_t raw_length; /* original number of elements */
62 Py_ssize_t length; /* current number of elements */
62 Py_ssize_t length; /* current number of elements */
63 PyObject *added; /* populated on demand */
63 PyObject *added; /* populated on demand */
64 PyObject *headrevs; /* cache, invalidated on changes */
64 PyObject *headrevs; /* cache, invalidated on changes */
65 PyObject *filteredrevs;/* filtered revs set */
65 PyObject *filteredrevs;/* filtered revs set */
66 nodetree *nt; /* base-16 trie */
66 nodetree *nt; /* base-16 trie */
67 unsigned ntlength; /* # nodes in use */
67 unsigned ntlength; /* # nodes in use */
68 unsigned ntcapacity; /* # nodes allocated */
68 unsigned ntcapacity; /* # nodes allocated */
69 int ntdepth; /* maximum depth of tree */
69 int ntdepth; /* maximum depth of tree */
70 int ntsplits; /* # splits performed */
70 int ntsplits; /* # splits performed */
71 int ntrev; /* last rev scanned */
71 int ntrev; /* last rev scanned */
72 int ntlookups; /* # lookups */
72 int ntlookups; /* # lookups */
73 int ntmisses; /* # lookups that miss the cache */
73 int ntmisses; /* # lookups that miss the cache */
74 int inlined;
74 int inlined;
75 } indexObject;
75 } indexObject;
76
76
77 static Py_ssize_t index_length(const indexObject *self)
77 static Py_ssize_t index_length(const indexObject *self)
78 {
78 {
79 if (self->added == NULL)
79 if (self->added == NULL)
80 return self->length;
80 return self->length;
81 return self->length + PyList_GET_SIZE(self->added);
81 return self->length + PyList_GET_SIZE(self->added);
82 }
82 }
83
83
84 static PyObject *nullentry;
84 static PyObject *nullentry;
85 static const char nullid[20];
85 static const char nullid[20];
86
86
87 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
87 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
88
88
89 #if LONG_MAX == 0x7fffffffL
89 #if LONG_MAX == 0x7fffffffL
90 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
90 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
91 #else
91 #else
92 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
92 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
93 #endif
93 #endif
94
94
95 /* A RevlogNG v1 index entry is 64 bytes long. */
95 /* A RevlogNG v1 index entry is 64 bytes long. */
96 static const long v1_hdrsize = 64;
96 static const long v1_hdrsize = 64;
97
97
98 /*
98 /*
99 * Return a pointer to the beginning of a RevlogNG record.
99 * Return a pointer to the beginning of a RevlogNG record.
100 */
100 */
101 static const char *index_deref(indexObject *self, Py_ssize_t pos)
101 static const char *index_deref(indexObject *self, Py_ssize_t pos)
102 {
102 {
103 if (self->inlined && pos > 0) {
103 if (self->inlined && pos > 0) {
104 if (self->offsets == NULL) {
104 if (self->offsets == NULL) {
105 self->offsets = PyMem_Malloc(self->raw_length *
105 self->offsets = PyMem_Malloc(self->raw_length *
106 sizeof(*self->offsets));
106 sizeof(*self->offsets));
107 if (self->offsets == NULL)
107 if (self->offsets == NULL)
108 return (const char *)PyErr_NoMemory();
108 return (const char *)PyErr_NoMemory();
109 inline_scan(self, self->offsets);
109 inline_scan(self, self->offsets);
110 }
110 }
111 return self->offsets[pos];
111 return self->offsets[pos];
112 }
112 }
113
113
114 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
114 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
115 }
115 }
116
116
117 static inline int index_get_parents(indexObject *self, Py_ssize_t rev,
117 static inline int index_get_parents(indexObject *self, Py_ssize_t rev,
118 int *ps, int maxrev)
118 int *ps, int maxrev)
119 {
119 {
120 if (rev >= self->length - 1) {
120 if (rev >= self->length - 1) {
121 PyObject *tuple = PyList_GET_ITEM(self->added,
121 PyObject *tuple = PyList_GET_ITEM(self->added,
122 rev - self->length + 1);
122 rev - self->length + 1);
123 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
123 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
124 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
124 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
125 } else {
125 } else {
126 const char *data = index_deref(self, rev);
126 const char *data = index_deref(self, rev);
127 ps[0] = getbe32(data + 24);
127 ps[0] = getbe32(data + 24);
128 ps[1] = getbe32(data + 28);
128 ps[1] = getbe32(data + 28);
129 }
129 }
130 /* If index file is corrupted, ps[] may point to invalid revisions. So
130 /* If index file is corrupted, ps[] may point to invalid revisions. So
131 * there is a risk of buffer overflow to trust them unconditionally. */
131 * there is a risk of buffer overflow to trust them unconditionally. */
132 if (ps[0] > maxrev || ps[1] > maxrev) {
132 if (ps[0] > maxrev || ps[1] > maxrev) {
133 PyErr_SetString(PyExc_ValueError, "parent out of range");
133 PyErr_SetString(PyExc_ValueError, "parent out of range");
134 return -1;
134 return -1;
135 }
135 }
136 return 0;
136 return 0;
137 }
137 }
138
138
139
139
140 /*
140 /*
141 * RevlogNG format (all in big endian, data may be inlined):
141 * RevlogNG format (all in big endian, data may be inlined):
142 * 6 bytes: offset
142 * 6 bytes: offset
143 * 2 bytes: flags
143 * 2 bytes: flags
144 * 4 bytes: compressed length
144 * 4 bytes: compressed length
145 * 4 bytes: uncompressed length
145 * 4 bytes: uncompressed length
146 * 4 bytes: base revision
146 * 4 bytes: base revision
147 * 4 bytes: link revision
147 * 4 bytes: link revision
148 * 4 bytes: parent 1 revision
148 * 4 bytes: parent 1 revision
149 * 4 bytes: parent 2 revision
149 * 4 bytes: parent 2 revision
150 * 32 bytes: nodeid (only 20 bytes used)
150 * 32 bytes: nodeid (only 20 bytes used)
151 */
151 */
152 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
152 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
153 {
153 {
154 uint64_t offset_flags;
154 uint64_t offset_flags;
155 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
155 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
156 const char *c_node_id;
156 const char *c_node_id;
157 const char *data;
157 const char *data;
158 Py_ssize_t length = index_length(self);
158 Py_ssize_t length = index_length(self);
159 PyObject *entry;
159 PyObject *entry;
160
160
161 if (pos == -1 || pos == length - 1) {
162 Py_INCREF(nullentry);
163 return nullentry;
164 }
165
161 if (pos < 0)
166 if (pos < 0)
162 pos += length;
167 pos += length;
163
168
164 if (pos < 0 || pos >= length) {
169 if (pos < 0 || pos >= length) {
165 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
170 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
166 return NULL;
171 return NULL;
167 }
172 }
168
173
169 if (pos == length - 1) {
170 Py_INCREF(nullentry);
171 return nullentry;
172 }
173
174 if (pos >= self->length - 1) {
174 if (pos >= self->length - 1) {
175 PyObject *obj;
175 PyObject *obj;
176 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
176 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
177 Py_INCREF(obj);
177 Py_INCREF(obj);
178 return obj;
178 return obj;
179 }
179 }
180
180
181 if (self->cache) {
181 if (self->cache) {
182 if (self->cache[pos]) {
182 if (self->cache[pos]) {
183 Py_INCREF(self->cache[pos]);
183 Py_INCREF(self->cache[pos]);
184 return self->cache[pos];
184 return self->cache[pos];
185 }
185 }
186 } else {
186 } else {
187 self->cache = calloc(self->raw_length, sizeof(PyObject *));
187 self->cache = calloc(self->raw_length, sizeof(PyObject *));
188 if (self->cache == NULL)
188 if (self->cache == NULL)
189 return PyErr_NoMemory();
189 return PyErr_NoMemory();
190 }
190 }
191
191
192 data = index_deref(self, pos);
192 data = index_deref(self, pos);
193 if (data == NULL)
193 if (data == NULL)
194 return NULL;
194 return NULL;
195
195
196 offset_flags = getbe32(data + 4);
196 offset_flags = getbe32(data + 4);
197 if (pos == 0) /* mask out version number for the first entry */
197 if (pos == 0) /* mask out version number for the first entry */
198 offset_flags &= 0xFFFF;
198 offset_flags &= 0xFFFF;
199 else {
199 else {
200 uint32_t offset_high = getbe32(data);
200 uint32_t offset_high = getbe32(data);
201 offset_flags |= ((uint64_t)offset_high) << 32;
201 offset_flags |= ((uint64_t)offset_high) << 32;
202 }
202 }
203
203
204 comp_len = getbe32(data + 8);
204 comp_len = getbe32(data + 8);
205 uncomp_len = getbe32(data + 12);
205 uncomp_len = getbe32(data + 12);
206 base_rev = getbe32(data + 16);
206 base_rev = getbe32(data + 16);
207 link_rev = getbe32(data + 20);
207 link_rev = getbe32(data + 20);
208 parent_1 = getbe32(data + 24);
208 parent_1 = getbe32(data + 24);
209 parent_2 = getbe32(data + 28);
209 parent_2 = getbe32(data + 28);
210 c_node_id = data + 32;
210 c_node_id = data + 32;
211
211
212 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
212 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
213 uncomp_len, base_rev, link_rev,
213 uncomp_len, base_rev, link_rev,
214 parent_1, parent_2, c_node_id, 20);
214 parent_1, parent_2, c_node_id, 20);
215
215
216 if (entry) {
216 if (entry) {
217 PyObject_GC_UnTrack(entry);
217 PyObject_GC_UnTrack(entry);
218 Py_INCREF(entry);
218 Py_INCREF(entry);
219 }
219 }
220
220
221 self->cache[pos] = entry;
221 self->cache[pos] = entry;
222
222
223 return entry;
223 return entry;
224 }
224 }
225
225
226 /*
226 /*
227 * Return the 20-byte SHA of the node corresponding to the given rev.
227 * Return the 20-byte SHA of the node corresponding to the given rev.
228 */
228 */
229 static const char *index_node(indexObject *self, Py_ssize_t pos)
229 static const char *index_node(indexObject *self, Py_ssize_t pos)
230 {
230 {
231 Py_ssize_t length = index_length(self);
231 Py_ssize_t length = index_length(self);
232 const char *data;
232 const char *data;
233
233
234 if (pos == length - 1 || pos == -1)
234 if (pos == length - 1 || pos == -1)
235 return nullid;
235 return nullid;
236
236
237 if (pos >= length)
237 if (pos >= length)
238 return NULL;
238 return NULL;
239
239
240 if (pos >= self->length - 1) {
240 if (pos >= self->length - 1) {
241 PyObject *tuple, *str;
241 PyObject *tuple, *str;
242 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
242 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
243 str = PyTuple_GetItem(tuple, 7);
243 str = PyTuple_GetItem(tuple, 7);
244 return str ? PyBytes_AS_STRING(str) : NULL;
244 return str ? PyBytes_AS_STRING(str) : NULL;
245 }
245 }
246
246
247 data = index_deref(self, pos);
247 data = index_deref(self, pos);
248 return data ? data + 32 : NULL;
248 return data ? data + 32 : NULL;
249 }
249 }
250
250
251 /*
251 /*
252 * Return the 20-byte SHA of the node corresponding to the given rev. The
252 * Return the 20-byte SHA of the node corresponding to the given rev. The
253 * rev is assumed to be existing. If not, an exception is set.
253 * rev is assumed to be existing. If not, an exception is set.
254 */
254 */
255 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
255 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
256 {
256 {
257 const char *node = index_node(self, pos);
257 const char *node = index_node(self, pos);
258 if (node == NULL) {
258 if (node == NULL) {
259 PyErr_Format(PyExc_IndexError, "could not access rev %d",
259 PyErr_Format(PyExc_IndexError, "could not access rev %d",
260 (int)pos);
260 (int)pos);
261 }
261 }
262 return node;
262 return node;
263 }
263 }
264
264
265 static int nt_insert(indexObject *self, const char *node, int rev);
265 static int nt_insert(indexObject *self, const char *node, int rev);
266
266
267 static int node_check(PyObject *obj, char **node)
267 static int node_check(PyObject *obj, char **node)
268 {
268 {
269 Py_ssize_t nodelen;
269 Py_ssize_t nodelen;
270 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
270 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
271 return -1;
271 return -1;
272 if (nodelen == 20)
272 if (nodelen == 20)
273 return 0;
273 return 0;
274 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
274 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
275 return -1;
275 return -1;
276 }
276 }
277
277
278 static PyObject *index_insert(indexObject *self, PyObject *args)
278 static PyObject *index_insert(indexObject *self, PyObject *args)
279 {
279 {
280 PyObject *obj;
280 PyObject *obj;
281 char *node;
281 char *node;
282 int index;
282 int index;
283 Py_ssize_t len;
283 Py_ssize_t len;
284
284
285 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
285 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
286 return NULL;
286 return NULL;
287
287
288 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
288 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
289 PyErr_SetString(PyExc_TypeError, "8-tuple required");
289 PyErr_SetString(PyExc_TypeError, "8-tuple required");
290 return NULL;
290 return NULL;
291 }
291 }
292
292
293 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
293 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
294 return NULL;
294 return NULL;
295
295
296 len = index_length(self);
296 len = index_length(self);
297
297
298 if (index < 0)
298 if (index < 0)
299 index += len;
299 index += len;
300
300
301 if (index != len - 1) {
301 if (index != len - 1) {
302 PyErr_SetString(PyExc_IndexError,
302 PyErr_SetString(PyExc_IndexError,
303 "insert only supported at index -1");
303 "insert only supported at index -1");
304 return NULL;
304 return NULL;
305 }
305 }
306
306
307 if (self->added == NULL) {
307 if (self->added == NULL) {
308 self->added = PyList_New(0);
308 self->added = PyList_New(0);
309 if (self->added == NULL)
309 if (self->added == NULL)
310 return NULL;
310 return NULL;
311 }
311 }
312
312
313 if (PyList_Append(self->added, obj) == -1)
313 if (PyList_Append(self->added, obj) == -1)
314 return NULL;
314 return NULL;
315
315
316 if (self->nt)
316 if (self->nt)
317 nt_insert(self, node, index);
317 nt_insert(self, node, index);
318
318
319 Py_CLEAR(self->headrevs);
319 Py_CLEAR(self->headrevs);
320 Py_RETURN_NONE;
320 Py_RETURN_NONE;
321 }
321 }
322
322
323 static void _index_clearcaches(indexObject *self)
323 static void _index_clearcaches(indexObject *self)
324 {
324 {
325 if (self->cache) {
325 if (self->cache) {
326 Py_ssize_t i;
326 Py_ssize_t i;
327
327
328 for (i = 0; i < self->raw_length; i++)
328 for (i = 0; i < self->raw_length; i++)
329 Py_CLEAR(self->cache[i]);
329 Py_CLEAR(self->cache[i]);
330 free(self->cache);
330 free(self->cache);
331 self->cache = NULL;
331 self->cache = NULL;
332 }
332 }
333 if (self->offsets) {
333 if (self->offsets) {
334 PyMem_Free(self->offsets);
334 PyMem_Free(self->offsets);
335 self->offsets = NULL;
335 self->offsets = NULL;
336 }
336 }
337 free(self->nt);
337 free(self->nt);
338 self->nt = NULL;
338 self->nt = NULL;
339 Py_CLEAR(self->headrevs);
339 Py_CLEAR(self->headrevs);
340 }
340 }
341
341
342 static PyObject *index_clearcaches(indexObject *self)
342 static PyObject *index_clearcaches(indexObject *self)
343 {
343 {
344 _index_clearcaches(self);
344 _index_clearcaches(self);
345 self->ntlength = self->ntcapacity = 0;
345 self->ntlength = self->ntcapacity = 0;
346 self->ntdepth = self->ntsplits = 0;
346 self->ntdepth = self->ntsplits = 0;
347 self->ntrev = -1;
347 self->ntrev = -1;
348 self->ntlookups = self->ntmisses = 0;
348 self->ntlookups = self->ntmisses = 0;
349 Py_RETURN_NONE;
349 Py_RETURN_NONE;
350 }
350 }
351
351
352 static PyObject *index_stats(indexObject *self)
352 static PyObject *index_stats(indexObject *self)
353 {
353 {
354 PyObject *obj = PyDict_New();
354 PyObject *obj = PyDict_New();
355 PyObject *t = NULL;
355 PyObject *t = NULL;
356
356
357 if (obj == NULL)
357 if (obj == NULL)
358 return NULL;
358 return NULL;
359
359
360 #define istat(__n, __d) \
360 #define istat(__n, __d) \
361 do { \
361 do { \
362 t = PyInt_FromSsize_t(self->__n); \
362 t = PyInt_FromSsize_t(self->__n); \
363 if (!t) \
363 if (!t) \
364 goto bail; \
364 goto bail; \
365 if (PyDict_SetItemString(obj, __d, t) == -1) \
365 if (PyDict_SetItemString(obj, __d, t) == -1) \
366 goto bail; \
366 goto bail; \
367 Py_DECREF(t); \
367 Py_DECREF(t); \
368 } while (0)
368 } while (0)
369
369
370 if (self->added) {
370 if (self->added) {
371 Py_ssize_t len = PyList_GET_SIZE(self->added);
371 Py_ssize_t len = PyList_GET_SIZE(self->added);
372 t = PyInt_FromSsize_t(len);
372 t = PyInt_FromSsize_t(len);
373 if (!t)
373 if (!t)
374 goto bail;
374 goto bail;
375 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
375 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
376 goto bail;
376 goto bail;
377 Py_DECREF(t);
377 Py_DECREF(t);
378 }
378 }
379
379
380 if (self->raw_length != self->length - 1)
380 if (self->raw_length != self->length - 1)
381 istat(raw_length, "revs on disk");
381 istat(raw_length, "revs on disk");
382 istat(length, "revs in memory");
382 istat(length, "revs in memory");
383 istat(ntcapacity, "node trie capacity");
383 istat(ntcapacity, "node trie capacity");
384 istat(ntdepth, "node trie depth");
384 istat(ntdepth, "node trie depth");
385 istat(ntlength, "node trie count");
385 istat(ntlength, "node trie count");
386 istat(ntlookups, "node trie lookups");
386 istat(ntlookups, "node trie lookups");
387 istat(ntmisses, "node trie misses");
387 istat(ntmisses, "node trie misses");
388 istat(ntrev, "node trie last rev scanned");
388 istat(ntrev, "node trie last rev scanned");
389 istat(ntsplits, "node trie splits");
389 istat(ntsplits, "node trie splits");
390
390
391 #undef istat
391 #undef istat
392
392
393 return obj;
393 return obj;
394
394
395 bail:
395 bail:
396 Py_XDECREF(obj);
396 Py_XDECREF(obj);
397 Py_XDECREF(t);
397 Py_XDECREF(t);
398 return NULL;
398 return NULL;
399 }
399 }
400
400
401 /*
401 /*
402 * When we cache a list, we want to be sure the caller can't mutate
402 * When we cache a list, we want to be sure the caller can't mutate
403 * the cached copy.
403 * the cached copy.
404 */
404 */
405 static PyObject *list_copy(PyObject *list)
405 static PyObject *list_copy(PyObject *list)
406 {
406 {
407 Py_ssize_t len = PyList_GET_SIZE(list);
407 Py_ssize_t len = PyList_GET_SIZE(list);
408 PyObject *newlist = PyList_New(len);
408 PyObject *newlist = PyList_New(len);
409 Py_ssize_t i;
409 Py_ssize_t i;
410
410
411 if (newlist == NULL)
411 if (newlist == NULL)
412 return NULL;
412 return NULL;
413
413
414 for (i = 0; i < len; i++) {
414 for (i = 0; i < len; i++) {
415 PyObject *obj = PyList_GET_ITEM(list, i);
415 PyObject *obj = PyList_GET_ITEM(list, i);
416 Py_INCREF(obj);
416 Py_INCREF(obj);
417 PyList_SET_ITEM(newlist, i, obj);
417 PyList_SET_ITEM(newlist, i, obj);
418 }
418 }
419
419
420 return newlist;
420 return newlist;
421 }
421 }
422
422
423 static int check_filter(PyObject *filter, Py_ssize_t arg)
423 static int check_filter(PyObject *filter, Py_ssize_t arg)
424 {
424 {
425 if (filter) {
425 if (filter) {
426 PyObject *arglist, *result;
426 PyObject *arglist, *result;
427 int isfiltered;
427 int isfiltered;
428
428
429 arglist = Py_BuildValue("(n)", arg);
429 arglist = Py_BuildValue("(n)", arg);
430 if (!arglist) {
430 if (!arglist) {
431 return -1;
431 return -1;
432 }
432 }
433
433
434 result = PyEval_CallObject(filter, arglist);
434 result = PyEval_CallObject(filter, arglist);
435 Py_DECREF(arglist);
435 Py_DECREF(arglist);
436 if (!result) {
436 if (!result) {
437 return -1;
437 return -1;
438 }
438 }
439
439
440 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
440 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
441 * same as this function, so we can just return it directly.*/
441 * same as this function, so we can just return it directly.*/
442 isfiltered = PyObject_IsTrue(result);
442 isfiltered = PyObject_IsTrue(result);
443 Py_DECREF(result);
443 Py_DECREF(result);
444 return isfiltered;
444 return isfiltered;
445 } else {
445 } else {
446 return 0;
446 return 0;
447 }
447 }
448 }
448 }
449
449
450 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
450 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
451 Py_ssize_t marker, char *phases)
451 Py_ssize_t marker, char *phases)
452 {
452 {
453 PyObject *iter = NULL;
453 PyObject *iter = NULL;
454 PyObject *iter_item = NULL;
454 PyObject *iter_item = NULL;
455 Py_ssize_t min_idx = index_length(self) + 1;
455 Py_ssize_t min_idx = index_length(self) + 1;
456 long iter_item_long;
456 long iter_item_long;
457
457
458 if (PyList_GET_SIZE(list) != 0) {
458 if (PyList_GET_SIZE(list) != 0) {
459 iter = PyObject_GetIter(list);
459 iter = PyObject_GetIter(list);
460 if (iter == NULL)
460 if (iter == NULL)
461 return -2;
461 return -2;
462 while ((iter_item = PyIter_Next(iter))) {
462 while ((iter_item = PyIter_Next(iter))) {
463 iter_item_long = PyInt_AS_LONG(iter_item);
463 iter_item_long = PyInt_AS_LONG(iter_item);
464 Py_DECREF(iter_item);
464 Py_DECREF(iter_item);
465 if (iter_item_long < min_idx)
465 if (iter_item_long < min_idx)
466 min_idx = iter_item_long;
466 min_idx = iter_item_long;
467 phases[iter_item_long] = marker;
467 phases[iter_item_long] = marker;
468 }
468 }
469 Py_DECREF(iter);
469 Py_DECREF(iter);
470 }
470 }
471
471
472 return min_idx;
472 return min_idx;
473 }
473 }
474
474
475 static inline void set_phase_from_parents(char *phases, int parent_1,
475 static inline void set_phase_from_parents(char *phases, int parent_1,
476 int parent_2, Py_ssize_t i)
476 int parent_2, Py_ssize_t i)
477 {
477 {
478 if (parent_1 >= 0 && phases[parent_1] > phases[i])
478 if (parent_1 >= 0 && phases[parent_1] > phases[i])
479 phases[i] = phases[parent_1];
479 phases[i] = phases[parent_1];
480 if (parent_2 >= 0 && phases[parent_2] > phases[i])
480 if (parent_2 >= 0 && phases[parent_2] > phases[i])
481 phases[i] = phases[parent_2];
481 phases[i] = phases[parent_2];
482 }
482 }
483
483
484 static PyObject *reachableroots2(indexObject *self, PyObject *args)
484 static PyObject *reachableroots2(indexObject *self, PyObject *args)
485 {
485 {
486
486
487 /* Input */
487 /* Input */
488 long minroot;
488 long minroot;
489 PyObject *includepatharg = NULL;
489 PyObject *includepatharg = NULL;
490 int includepath = 0;
490 int includepath = 0;
491 /* heads and roots are lists */
491 /* heads and roots are lists */
492 PyObject *heads = NULL;
492 PyObject *heads = NULL;
493 PyObject *roots = NULL;
493 PyObject *roots = NULL;
494 PyObject *reachable = NULL;
494 PyObject *reachable = NULL;
495
495
496 PyObject *val;
496 PyObject *val;
497 Py_ssize_t len = index_length(self) - 1;
497 Py_ssize_t len = index_length(self) - 1;
498 long revnum;
498 long revnum;
499 Py_ssize_t k;
499 Py_ssize_t k;
500 Py_ssize_t i;
500 Py_ssize_t i;
501 Py_ssize_t l;
501 Py_ssize_t l;
502 int r;
502 int r;
503 int parents[2];
503 int parents[2];
504
504
505 /* Internal data structure:
505 /* Internal data structure:
506 * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit
506 * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit
507 * revstates: array of length len+1 (all revs + nullrev) */
507 * revstates: array of length len+1 (all revs + nullrev) */
508 int *tovisit = NULL;
508 int *tovisit = NULL;
509 long lentovisit = 0;
509 long lentovisit = 0;
510 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
510 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
511 char *revstates = NULL;
511 char *revstates = NULL;
512
512
513 /* Get arguments */
513 /* Get arguments */
514 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
514 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
515 &PyList_Type, &roots,
515 &PyList_Type, &roots,
516 &PyBool_Type, &includepatharg))
516 &PyBool_Type, &includepatharg))
517 goto bail;
517 goto bail;
518
518
519 if (includepatharg == Py_True)
519 if (includepatharg == Py_True)
520 includepath = 1;
520 includepath = 1;
521
521
522 /* Initialize return set */
522 /* Initialize return set */
523 reachable = PyList_New(0);
523 reachable = PyList_New(0);
524 if (reachable == NULL)
524 if (reachable == NULL)
525 goto bail;
525 goto bail;
526
526
527 /* Initialize internal datastructures */
527 /* Initialize internal datastructures */
528 tovisit = (int *)malloc((len + 1) * sizeof(int));
528 tovisit = (int *)malloc((len + 1) * sizeof(int));
529 if (tovisit == NULL) {
529 if (tovisit == NULL) {
530 PyErr_NoMemory();
530 PyErr_NoMemory();
531 goto bail;
531 goto bail;
532 }
532 }
533
533
534 revstates = (char *)calloc(len + 1, 1);
534 revstates = (char *)calloc(len + 1, 1);
535 if (revstates == NULL) {
535 if (revstates == NULL) {
536 PyErr_NoMemory();
536 PyErr_NoMemory();
537 goto bail;
537 goto bail;
538 }
538 }
539
539
540 l = PyList_GET_SIZE(roots);
540 l = PyList_GET_SIZE(roots);
541 for (i = 0; i < l; i++) {
541 for (i = 0; i < l; i++) {
542 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
542 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
543 if (revnum == -1 && PyErr_Occurred())
543 if (revnum == -1 && PyErr_Occurred())
544 goto bail;
544 goto bail;
545 /* If root is out of range, e.g. wdir(), it must be unreachable
545 /* If root is out of range, e.g. wdir(), it must be unreachable
546 * from heads. So we can just ignore it. */
546 * from heads. So we can just ignore it. */
547 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
547 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
548 continue;
548 continue;
549 revstates[revnum + 1] |= RS_ROOT;
549 revstates[revnum + 1] |= RS_ROOT;
550 }
550 }
551
551
552 /* Populate tovisit with all the heads */
552 /* Populate tovisit with all the heads */
553 l = PyList_GET_SIZE(heads);
553 l = PyList_GET_SIZE(heads);
554 for (i = 0; i < l; i++) {
554 for (i = 0; i < l; i++) {
555 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
555 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
556 if (revnum == -1 && PyErr_Occurred())
556 if (revnum == -1 && PyErr_Occurred())
557 goto bail;
557 goto bail;
558 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
558 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
559 PyErr_SetString(PyExc_IndexError, "head out of range");
559 PyErr_SetString(PyExc_IndexError, "head out of range");
560 goto bail;
560 goto bail;
561 }
561 }
562 if (!(revstates[revnum + 1] & RS_SEEN)) {
562 if (!(revstates[revnum + 1] & RS_SEEN)) {
563 tovisit[lentovisit++] = (int)revnum;
563 tovisit[lentovisit++] = (int)revnum;
564 revstates[revnum + 1] |= RS_SEEN;
564 revstates[revnum + 1] |= RS_SEEN;
565 }
565 }
566 }
566 }
567
567
568 /* Visit the tovisit list and find the reachable roots */
568 /* Visit the tovisit list and find the reachable roots */
569 k = 0;
569 k = 0;
570 while (k < lentovisit) {
570 while (k < lentovisit) {
571 /* Add the node to reachable if it is a root*/
571 /* Add the node to reachable if it is a root*/
572 revnum = tovisit[k++];
572 revnum = tovisit[k++];
573 if (revstates[revnum + 1] & RS_ROOT) {
573 if (revstates[revnum + 1] & RS_ROOT) {
574 revstates[revnum + 1] |= RS_REACHABLE;
574 revstates[revnum + 1] |= RS_REACHABLE;
575 val = PyInt_FromLong(revnum);
575 val = PyInt_FromLong(revnum);
576 if (val == NULL)
576 if (val == NULL)
577 goto bail;
577 goto bail;
578 r = PyList_Append(reachable, val);
578 r = PyList_Append(reachable, val);
579 Py_DECREF(val);
579 Py_DECREF(val);
580 if (r < 0)
580 if (r < 0)
581 goto bail;
581 goto bail;
582 if (includepath == 0)
582 if (includepath == 0)
583 continue;
583 continue;
584 }
584 }
585
585
586 /* Add its parents to the list of nodes to visit */
586 /* Add its parents to the list of nodes to visit */
587 if (revnum == -1)
587 if (revnum == -1)
588 continue;
588 continue;
589 r = index_get_parents(self, revnum, parents, (int)len - 1);
589 r = index_get_parents(self, revnum, parents, (int)len - 1);
590 if (r < 0)
590 if (r < 0)
591 goto bail;
591 goto bail;
592 for (i = 0; i < 2; i++) {
592 for (i = 0; i < 2; i++) {
593 if (!(revstates[parents[i] + 1] & RS_SEEN)
593 if (!(revstates[parents[i] + 1] & RS_SEEN)
594 && parents[i] >= minroot) {
594 && parents[i] >= minroot) {
595 tovisit[lentovisit++] = parents[i];
595 tovisit[lentovisit++] = parents[i];
596 revstates[parents[i] + 1] |= RS_SEEN;
596 revstates[parents[i] + 1] |= RS_SEEN;
597 }
597 }
598 }
598 }
599 }
599 }
600
600
601 /* Find all the nodes in between the roots we found and the heads
601 /* Find all the nodes in between the roots we found and the heads
602 * and add them to the reachable set */
602 * and add them to the reachable set */
603 if (includepath == 1) {
603 if (includepath == 1) {
604 long minidx = minroot;
604 long minidx = minroot;
605 if (minidx < 0)
605 if (minidx < 0)
606 minidx = 0;
606 minidx = 0;
607 for (i = minidx; i < len; i++) {
607 for (i = minidx; i < len; i++) {
608 if (!(revstates[i + 1] & RS_SEEN))
608 if (!(revstates[i + 1] & RS_SEEN))
609 continue;
609 continue;
610 r = index_get_parents(self, i, parents, (int)len - 1);
610 r = index_get_parents(self, i, parents, (int)len - 1);
611 /* Corrupted index file, error is set from
611 /* Corrupted index file, error is set from
612 * index_get_parents */
612 * index_get_parents */
613 if (r < 0)
613 if (r < 0)
614 goto bail;
614 goto bail;
615 if (((revstates[parents[0] + 1] |
615 if (((revstates[parents[0] + 1] |
616 revstates[parents[1] + 1]) & RS_REACHABLE)
616 revstates[parents[1] + 1]) & RS_REACHABLE)
617 && !(revstates[i + 1] & RS_REACHABLE)) {
617 && !(revstates[i + 1] & RS_REACHABLE)) {
618 revstates[i + 1] |= RS_REACHABLE;
618 revstates[i + 1] |= RS_REACHABLE;
619 val = PyInt_FromLong(i);
619 val = PyInt_FromLong(i);
620 if (val == NULL)
620 if (val == NULL)
621 goto bail;
621 goto bail;
622 r = PyList_Append(reachable, val);
622 r = PyList_Append(reachable, val);
623 Py_DECREF(val);
623 Py_DECREF(val);
624 if (r < 0)
624 if (r < 0)
625 goto bail;
625 goto bail;
626 }
626 }
627 }
627 }
628 }
628 }
629
629
630 free(revstates);
630 free(revstates);
631 free(tovisit);
631 free(tovisit);
632 return reachable;
632 return reachable;
633 bail:
633 bail:
634 Py_XDECREF(reachable);
634 Py_XDECREF(reachable);
635 free(revstates);
635 free(revstates);
636 free(tovisit);
636 free(tovisit);
637 return NULL;
637 return NULL;
638 }
638 }
639
639
640 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
640 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
641 {
641 {
642 PyObject *roots = Py_None;
642 PyObject *roots = Py_None;
643 PyObject *ret = NULL;
643 PyObject *ret = NULL;
644 PyObject *phasessize = NULL;
644 PyObject *phasessize = NULL;
645 PyObject *phaseroots = NULL;
645 PyObject *phaseroots = NULL;
646 PyObject *phaseset = NULL;
646 PyObject *phaseset = NULL;
647 PyObject *phasessetlist = NULL;
647 PyObject *phasessetlist = NULL;
648 PyObject *rev = NULL;
648 PyObject *rev = NULL;
649 Py_ssize_t len = index_length(self) - 1;
649 Py_ssize_t len = index_length(self) - 1;
650 Py_ssize_t numphase = 0;
650 Py_ssize_t numphase = 0;
651 Py_ssize_t minrevallphases = 0;
651 Py_ssize_t minrevallphases = 0;
652 Py_ssize_t minrevphase = 0;
652 Py_ssize_t minrevphase = 0;
653 Py_ssize_t i = 0;
653 Py_ssize_t i = 0;
654 char *phases = NULL;
654 char *phases = NULL;
655 long phase;
655 long phase;
656
656
657 if (!PyArg_ParseTuple(args, "O", &roots))
657 if (!PyArg_ParseTuple(args, "O", &roots))
658 goto done;
658 goto done;
659 if (roots == NULL || !PyList_Check(roots)) {
659 if (roots == NULL || !PyList_Check(roots)) {
660 PyErr_SetString(PyExc_TypeError, "roots must be a list");
660 PyErr_SetString(PyExc_TypeError, "roots must be a list");
661 goto done;
661 goto done;
662 }
662 }
663
663
664 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
664 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
665 if (phases == NULL) {
665 if (phases == NULL) {
666 PyErr_NoMemory();
666 PyErr_NoMemory();
667 goto done;
667 goto done;
668 }
668 }
669 /* Put the phase information of all the roots in phases */
669 /* Put the phase information of all the roots in phases */
670 numphase = PyList_GET_SIZE(roots)+1;
670 numphase = PyList_GET_SIZE(roots)+1;
671 minrevallphases = len + 1;
671 minrevallphases = len + 1;
672 phasessetlist = PyList_New(numphase);
672 phasessetlist = PyList_New(numphase);
673 if (phasessetlist == NULL)
673 if (phasessetlist == NULL)
674 goto done;
674 goto done;
675
675
676 PyList_SET_ITEM(phasessetlist, 0, Py_None);
676 PyList_SET_ITEM(phasessetlist, 0, Py_None);
677 Py_INCREF(Py_None);
677 Py_INCREF(Py_None);
678
678
679 for (i = 0; i < numphase-1; i++) {
679 for (i = 0; i < numphase-1; i++) {
680 phaseroots = PyList_GET_ITEM(roots, i);
680 phaseroots = PyList_GET_ITEM(roots, i);
681 phaseset = PySet_New(NULL);
681 phaseset = PySet_New(NULL);
682 if (phaseset == NULL)
682 if (phaseset == NULL)
683 goto release;
683 goto release;
684 PyList_SET_ITEM(phasessetlist, i+1, phaseset);
684 PyList_SET_ITEM(phasessetlist, i+1, phaseset);
685 if (!PyList_Check(phaseroots)) {
685 if (!PyList_Check(phaseroots)) {
686 PyErr_SetString(PyExc_TypeError,
686 PyErr_SetString(PyExc_TypeError,
687 "roots item must be a list");
687 "roots item must be a list");
688 goto release;
688 goto release;
689 }
689 }
690 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
690 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
691 if (minrevphase == -2) /* Error from add_roots_get_min */
691 if (minrevphase == -2) /* Error from add_roots_get_min */
692 goto release;
692 goto release;
693 minrevallphases = MIN(minrevallphases, minrevphase);
693 minrevallphases = MIN(minrevallphases, minrevphase);
694 }
694 }
695 /* Propagate the phase information from the roots to the revs */
695 /* Propagate the phase information from the roots to the revs */
696 if (minrevallphases != -1) {
696 if (minrevallphases != -1) {
697 int parents[2];
697 int parents[2];
698 for (i = minrevallphases; i < len; i++) {
698 for (i = minrevallphases; i < len; i++) {
699 if (index_get_parents(self, i, parents,
699 if (index_get_parents(self, i, parents,
700 (int)len - 1) < 0)
700 (int)len - 1) < 0)
701 goto release;
701 goto release;
702 set_phase_from_parents(phases, parents[0], parents[1], i);
702 set_phase_from_parents(phases, parents[0], parents[1], i);
703 }
703 }
704 }
704 }
705 /* Transform phase list to a python list */
705 /* Transform phase list to a python list */
706 phasessize = PyInt_FromLong(len);
706 phasessize = PyInt_FromLong(len);
707 if (phasessize == NULL)
707 if (phasessize == NULL)
708 goto release;
708 goto release;
709 for (i = 0; i < len; i++) {
709 for (i = 0; i < len; i++) {
710 phase = phases[i];
710 phase = phases[i];
711 /* We only store the sets of phase for non public phase, the public phase
711 /* We only store the sets of phase for non public phase, the public phase
712 * is computed as a difference */
712 * is computed as a difference */
713 if (phase != 0) {
713 if (phase != 0) {
714 phaseset = PyList_GET_ITEM(phasessetlist, phase);
714 phaseset = PyList_GET_ITEM(phasessetlist, phase);
715 rev = PyInt_FromLong(i);
715 rev = PyInt_FromLong(i);
716 if (rev == NULL)
716 if (rev == NULL)
717 goto release;
717 goto release;
718 PySet_Add(phaseset, rev);
718 PySet_Add(phaseset, rev);
719 Py_XDECREF(rev);
719 Py_XDECREF(rev);
720 }
720 }
721 }
721 }
722 ret = PyTuple_Pack(2, phasessize, phasessetlist);
722 ret = PyTuple_Pack(2, phasessize, phasessetlist);
723
723
724 release:
724 release:
725 Py_XDECREF(phasessize);
725 Py_XDECREF(phasessize);
726 Py_XDECREF(phasessetlist);
726 Py_XDECREF(phasessetlist);
727 done:
727 done:
728 free(phases);
728 free(phases);
729 return ret;
729 return ret;
730 }
730 }
731
731
732 static PyObject *index_headrevs(indexObject *self, PyObject *args)
732 static PyObject *index_headrevs(indexObject *self, PyObject *args)
733 {
733 {
734 Py_ssize_t i, j, len;
734 Py_ssize_t i, j, len;
735 char *nothead = NULL;
735 char *nothead = NULL;
736 PyObject *heads = NULL;
736 PyObject *heads = NULL;
737 PyObject *filter = NULL;
737 PyObject *filter = NULL;
738 PyObject *filteredrevs = Py_None;
738 PyObject *filteredrevs = Py_None;
739
739
740 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
740 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
741 return NULL;
741 return NULL;
742 }
742 }
743
743
744 if (self->headrevs && filteredrevs == self->filteredrevs)
744 if (self->headrevs && filteredrevs == self->filteredrevs)
745 return list_copy(self->headrevs);
745 return list_copy(self->headrevs);
746
746
747 Py_DECREF(self->filteredrevs);
747 Py_DECREF(self->filteredrevs);
748 self->filteredrevs = filteredrevs;
748 self->filteredrevs = filteredrevs;
749 Py_INCREF(filteredrevs);
749 Py_INCREF(filteredrevs);
750
750
751 if (filteredrevs != Py_None) {
751 if (filteredrevs != Py_None) {
752 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
752 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
753 if (!filter) {
753 if (!filter) {
754 PyErr_SetString(PyExc_TypeError,
754 PyErr_SetString(PyExc_TypeError,
755 "filteredrevs has no attribute __contains__");
755 "filteredrevs has no attribute __contains__");
756 goto bail;
756 goto bail;
757 }
757 }
758 }
758 }
759
759
760 len = index_length(self) - 1;
760 len = index_length(self) - 1;
761 heads = PyList_New(0);
761 heads = PyList_New(0);
762 if (heads == NULL)
762 if (heads == NULL)
763 goto bail;
763 goto bail;
764 if (len == 0) {
764 if (len == 0) {
765 PyObject *nullid = PyInt_FromLong(-1);
765 PyObject *nullid = PyInt_FromLong(-1);
766 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
766 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
767 Py_XDECREF(nullid);
767 Py_XDECREF(nullid);
768 goto bail;
768 goto bail;
769 }
769 }
770 goto done;
770 goto done;
771 }
771 }
772
772
773 nothead = calloc(len, 1);
773 nothead = calloc(len, 1);
774 if (nothead == NULL) {
774 if (nothead == NULL) {
775 PyErr_NoMemory();
775 PyErr_NoMemory();
776 goto bail;
776 goto bail;
777 }
777 }
778
778
779 for (i = len - 1; i >= 0; i--) {
779 for (i = len - 1; i >= 0; i--) {
780 int isfiltered;
780 int isfiltered;
781 int parents[2];
781 int parents[2];
782
782
783 /* If nothead[i] == 1, it means we've seen an unfiltered child of this
783 /* If nothead[i] == 1, it means we've seen an unfiltered child of this
784 * node already, and therefore this node is not filtered. So we can skip
784 * node already, and therefore this node is not filtered. So we can skip
785 * the expensive check_filter step.
785 * the expensive check_filter step.
786 */
786 */
787 if (nothead[i] != 1) {
787 if (nothead[i] != 1) {
788 isfiltered = check_filter(filter, i);
788 isfiltered = check_filter(filter, i);
789 if (isfiltered == -1) {
789 if (isfiltered == -1) {
790 PyErr_SetString(PyExc_TypeError,
790 PyErr_SetString(PyExc_TypeError,
791 "unable to check filter");
791 "unable to check filter");
792 goto bail;
792 goto bail;
793 }
793 }
794
794
795 if (isfiltered) {
795 if (isfiltered) {
796 nothead[i] = 1;
796 nothead[i] = 1;
797 continue;
797 continue;
798 }
798 }
799 }
799 }
800
800
801 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
801 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
802 goto bail;
802 goto bail;
803 for (j = 0; j < 2; j++) {
803 for (j = 0; j < 2; j++) {
804 if (parents[j] >= 0)
804 if (parents[j] >= 0)
805 nothead[parents[j]] = 1;
805 nothead[parents[j]] = 1;
806 }
806 }
807 }
807 }
808
808
809 for (i = 0; i < len; i++) {
809 for (i = 0; i < len; i++) {
810 PyObject *head;
810 PyObject *head;
811
811
812 if (nothead[i])
812 if (nothead[i])
813 continue;
813 continue;
814 head = PyInt_FromSsize_t(i);
814 head = PyInt_FromSsize_t(i);
815 if (head == NULL || PyList_Append(heads, head) == -1) {
815 if (head == NULL || PyList_Append(heads, head) == -1) {
816 Py_XDECREF(head);
816 Py_XDECREF(head);
817 goto bail;
817 goto bail;
818 }
818 }
819 }
819 }
820
820
821 done:
821 done:
822 self->headrevs = heads;
822 self->headrevs = heads;
823 Py_XDECREF(filter);
823 Py_XDECREF(filter);
824 free(nothead);
824 free(nothead);
825 return list_copy(self->headrevs);
825 return list_copy(self->headrevs);
826 bail:
826 bail:
827 Py_XDECREF(filter);
827 Py_XDECREF(filter);
828 Py_XDECREF(heads);
828 Py_XDECREF(heads);
829 free(nothead);
829 free(nothead);
830 return NULL;
830 return NULL;
831 }
831 }
832
832
833 /**
833 /**
834 * Obtain the base revision index entry.
834 * Obtain the base revision index entry.
835 *
835 *
836 * Callers must ensure that rev >= 0 or illegal memory access may occur.
836 * Callers must ensure that rev >= 0 or illegal memory access may occur.
837 */
837 */
838 static inline int index_baserev(indexObject *self, int rev)
838 static inline int index_baserev(indexObject *self, int rev)
839 {
839 {
840 const char *data;
840 const char *data;
841
841
842 if (rev >= self->length - 1) {
842 if (rev >= self->length - 1) {
843 PyObject *tuple = PyList_GET_ITEM(self->added,
843 PyObject *tuple = PyList_GET_ITEM(self->added,
844 rev - self->length + 1);
844 rev - self->length + 1);
845 return (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
845 return (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
846 }
846 }
847 else {
847 else {
848 data = index_deref(self, rev);
848 data = index_deref(self, rev);
849 if (data == NULL) {
849 if (data == NULL) {
850 return -2;
850 return -2;
851 }
851 }
852
852
853 return getbe32(data + 16);
853 return getbe32(data + 16);
854 }
854 }
855 }
855 }
856
856
857 static PyObject *index_deltachain(indexObject *self, PyObject *args)
857 static PyObject *index_deltachain(indexObject *self, PyObject *args)
858 {
858 {
859 int rev, generaldelta;
859 int rev, generaldelta;
860 PyObject *stoparg;
860 PyObject *stoparg;
861 int stoprev, iterrev, baserev = -1;
861 int stoprev, iterrev, baserev = -1;
862 int stopped;
862 int stopped;
863 PyObject *chain = NULL, *result = NULL;
863 PyObject *chain = NULL, *result = NULL;
864 const Py_ssize_t length = index_length(self);
864 const Py_ssize_t length = index_length(self);
865
865
866 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
866 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
867 return NULL;
867 return NULL;
868 }
868 }
869
869
870 if (PyInt_Check(stoparg)) {
870 if (PyInt_Check(stoparg)) {
871 stoprev = (int)PyInt_AsLong(stoparg);
871 stoprev = (int)PyInt_AsLong(stoparg);
872 if (stoprev == -1 && PyErr_Occurred()) {
872 if (stoprev == -1 && PyErr_Occurred()) {
873 return NULL;
873 return NULL;
874 }
874 }
875 }
875 }
876 else if (stoparg == Py_None) {
876 else if (stoparg == Py_None) {
877 stoprev = -2;
877 stoprev = -2;
878 }
878 }
879 else {
879 else {
880 PyErr_SetString(PyExc_ValueError,
880 PyErr_SetString(PyExc_ValueError,
881 "stoprev must be integer or None");
881 "stoprev must be integer or None");
882 return NULL;
882 return NULL;
883 }
883 }
884
884
885 if (rev < 0 || rev >= length - 1) {
885 if (rev < 0 || rev >= length - 1) {
886 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
886 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
887 return NULL;
887 return NULL;
888 }
888 }
889
889
890 chain = PyList_New(0);
890 chain = PyList_New(0);
891 if (chain == NULL) {
891 if (chain == NULL) {
892 return NULL;
892 return NULL;
893 }
893 }
894
894
895 baserev = index_baserev(self, rev);
895 baserev = index_baserev(self, rev);
896
896
897 /* This should never happen. */
897 /* This should never happen. */
898 if (baserev <= -2) {
898 if (baserev <= -2) {
899 /* Error should be set by index_deref() */
899 /* Error should be set by index_deref() */
900 assert(PyErr_Occurred());
900 assert(PyErr_Occurred());
901 goto bail;
901 goto bail;
902 }
902 }
903
903
904 iterrev = rev;
904 iterrev = rev;
905
905
906 while (iterrev != baserev && iterrev != stoprev) {
906 while (iterrev != baserev && iterrev != stoprev) {
907 PyObject *value = PyInt_FromLong(iterrev);
907 PyObject *value = PyInt_FromLong(iterrev);
908 if (value == NULL) {
908 if (value == NULL) {
909 goto bail;
909 goto bail;
910 }
910 }
911 if (PyList_Append(chain, value)) {
911 if (PyList_Append(chain, value)) {
912 Py_DECREF(value);
912 Py_DECREF(value);
913 goto bail;
913 goto bail;
914 }
914 }
915 Py_DECREF(value);
915 Py_DECREF(value);
916
916
917 if (generaldelta) {
917 if (generaldelta) {
918 iterrev = baserev;
918 iterrev = baserev;
919 }
919 }
920 else {
920 else {
921 iterrev--;
921 iterrev--;
922 }
922 }
923
923
924 if (iterrev < 0) {
924 if (iterrev < 0) {
925 break;
925 break;
926 }
926 }
927
927
928 if (iterrev >= length - 1) {
928 if (iterrev >= length - 1) {
929 PyErr_SetString(PyExc_IndexError, "revision outside index");
929 PyErr_SetString(PyExc_IndexError, "revision outside index");
930 return NULL;
930 return NULL;
931 }
931 }
932
932
933 baserev = index_baserev(self, iterrev);
933 baserev = index_baserev(self, iterrev);
934
934
935 /* This should never happen. */
935 /* This should never happen. */
936 if (baserev <= -2) {
936 if (baserev <= -2) {
937 /* Error should be set by index_deref() */
937 /* Error should be set by index_deref() */
938 assert(PyErr_Occurred());
938 assert(PyErr_Occurred());
939 goto bail;
939 goto bail;
940 }
940 }
941 }
941 }
942
942
943 if (iterrev == stoprev) {
943 if (iterrev == stoprev) {
944 stopped = 1;
944 stopped = 1;
945 }
945 }
946 else {
946 else {
947 PyObject *value = PyInt_FromLong(iterrev);
947 PyObject *value = PyInt_FromLong(iterrev);
948 if (value == NULL) {
948 if (value == NULL) {
949 goto bail;
949 goto bail;
950 }
950 }
951 if (PyList_Append(chain, value)) {
951 if (PyList_Append(chain, value)) {
952 Py_DECREF(value);
952 Py_DECREF(value);
953 goto bail;
953 goto bail;
954 }
954 }
955 Py_DECREF(value);
955 Py_DECREF(value);
956
956
957 stopped = 0;
957 stopped = 0;
958 }
958 }
959
959
960 if (PyList_Reverse(chain)) {
960 if (PyList_Reverse(chain)) {
961 goto bail;
961 goto bail;
962 }
962 }
963
963
964 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
964 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
965 Py_DECREF(chain);
965 Py_DECREF(chain);
966 return result;
966 return result;
967
967
968 bail:
968 bail:
969 Py_DECREF(chain);
969 Py_DECREF(chain);
970 return NULL;
970 return NULL;
971 }
971 }
972
972
973 static inline int nt_level(const char *node, Py_ssize_t level)
973 static inline int nt_level(const char *node, Py_ssize_t level)
974 {
974 {
975 int v = node[level>>1];
975 int v = node[level>>1];
976 if (!(level & 1))
976 if (!(level & 1))
977 v >>= 4;
977 v >>= 4;
978 return v & 0xf;
978 return v & 0xf;
979 }
979 }
980
980
981 /*
981 /*
982 * Return values:
982 * Return values:
983 *
983 *
984 * -4: match is ambiguous (multiple candidates)
984 * -4: match is ambiguous (multiple candidates)
985 * -2: not found
985 * -2: not found
986 * rest: valid rev
986 * rest: valid rev
987 */
987 */
988 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
988 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
989 int hex)
989 int hex)
990 {
990 {
991 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
991 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
992 int level, maxlevel, off;
992 int level, maxlevel, off;
993
993
994 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
994 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
995 return -1;
995 return -1;
996
996
997 if (hex)
997 if (hex)
998 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
998 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
999 else
999 else
1000 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1000 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1001
1001
1002 for (level = off = 0; level < maxlevel; level++) {
1002 for (level = off = 0; level < maxlevel; level++) {
1003 int k = getnybble(node, level);
1003 int k = getnybble(node, level);
1004 nodetree *n = &self->nt[off];
1004 nodetree *n = &self->nt[off];
1005 int v = n->children[k];
1005 int v = n->children[k];
1006
1006
1007 if (v < 0) {
1007 if (v < 0) {
1008 const char *n;
1008 const char *n;
1009 Py_ssize_t i;
1009 Py_ssize_t i;
1010
1010
1011 v = -(v + 2);
1011 v = -(v + 2);
1012 n = index_node(self, v);
1012 n = index_node(self, v);
1013 if (n == NULL)
1013 if (n == NULL)
1014 return -2;
1014 return -2;
1015 for (i = level; i < maxlevel; i++)
1015 for (i = level; i < maxlevel; i++)
1016 if (getnybble(node, i) != nt_level(n, i))
1016 if (getnybble(node, i) != nt_level(n, i))
1017 return -2;
1017 return -2;
1018 return v;
1018 return v;
1019 }
1019 }
1020 if (v == 0)
1020 if (v == 0)
1021 return -2;
1021 return -2;
1022 off = v;
1022 off = v;
1023 }
1023 }
1024 /* multiple matches against an ambiguous prefix */
1024 /* multiple matches against an ambiguous prefix */
1025 return -4;
1025 return -4;
1026 }
1026 }
1027
1027
1028 static int nt_new(indexObject *self)
1028 static int nt_new(indexObject *self)
1029 {
1029 {
1030 if (self->ntlength == self->ntcapacity) {
1030 if (self->ntlength == self->ntcapacity) {
1031 if (self->ntcapacity >= INT_MAX / (sizeof(nodetree) * 2)) {
1031 if (self->ntcapacity >= INT_MAX / (sizeof(nodetree) * 2)) {
1032 PyErr_SetString(PyExc_MemoryError,
1032 PyErr_SetString(PyExc_MemoryError,
1033 "overflow in nt_new");
1033 "overflow in nt_new");
1034 return -1;
1034 return -1;
1035 }
1035 }
1036 self->ntcapacity *= 2;
1036 self->ntcapacity *= 2;
1037 self->nt = realloc(self->nt,
1037 self->nt = realloc(self->nt,
1038 self->ntcapacity * sizeof(nodetree));
1038 self->ntcapacity * sizeof(nodetree));
1039 if (self->nt == NULL) {
1039 if (self->nt == NULL) {
1040 PyErr_SetString(PyExc_MemoryError, "out of memory");
1040 PyErr_SetString(PyExc_MemoryError, "out of memory");
1041 return -1;
1041 return -1;
1042 }
1042 }
1043 memset(&self->nt[self->ntlength], 0,
1043 memset(&self->nt[self->ntlength], 0,
1044 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1044 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1045 }
1045 }
1046 return self->ntlength++;
1046 return self->ntlength++;
1047 }
1047 }
1048
1048
1049 static int nt_insert(indexObject *self, const char *node, int rev)
1049 static int nt_insert(indexObject *self, const char *node, int rev)
1050 {
1050 {
1051 int level = 0;
1051 int level = 0;
1052 int off = 0;
1052 int off = 0;
1053
1053
1054 while (level < 40) {
1054 while (level < 40) {
1055 int k = nt_level(node, level);
1055 int k = nt_level(node, level);
1056 nodetree *n;
1056 nodetree *n;
1057 int v;
1057 int v;
1058
1058
1059 n = &self->nt[off];
1059 n = &self->nt[off];
1060 v = n->children[k];
1060 v = n->children[k];
1061
1061
1062 if (v == 0) {
1062 if (v == 0) {
1063 n->children[k] = -rev - 2;
1063 n->children[k] = -rev - 2;
1064 return 0;
1064 return 0;
1065 }
1065 }
1066 if (v < 0) {
1066 if (v < 0) {
1067 const char *oldnode = index_node_existing(self, -(v + 2));
1067 const char *oldnode = index_node_existing(self, -(v + 2));
1068 int noff;
1068 int noff;
1069
1069
1070 if (oldnode == NULL)
1070 if (oldnode == NULL)
1071 return -1;
1071 return -1;
1072 if (!memcmp(oldnode, node, 20)) {
1072 if (!memcmp(oldnode, node, 20)) {
1073 n->children[k] = -rev - 2;
1073 n->children[k] = -rev - 2;
1074 return 0;
1074 return 0;
1075 }
1075 }
1076 noff = nt_new(self);
1076 noff = nt_new(self);
1077 if (noff == -1)
1077 if (noff == -1)
1078 return -1;
1078 return -1;
1079 /* self->nt may have been changed by realloc */
1079 /* self->nt may have been changed by realloc */
1080 self->nt[off].children[k] = noff;
1080 self->nt[off].children[k] = noff;
1081 off = noff;
1081 off = noff;
1082 n = &self->nt[off];
1082 n = &self->nt[off];
1083 n->children[nt_level(oldnode, ++level)] = v;
1083 n->children[nt_level(oldnode, ++level)] = v;
1084 if (level > self->ntdepth)
1084 if (level > self->ntdepth)
1085 self->ntdepth = level;
1085 self->ntdepth = level;
1086 self->ntsplits += 1;
1086 self->ntsplits += 1;
1087 } else {
1087 } else {
1088 level += 1;
1088 level += 1;
1089 off = v;
1089 off = v;
1090 }
1090 }
1091 }
1091 }
1092
1092
1093 return -1;
1093 return -1;
1094 }
1094 }
1095
1095
1096 static int nt_delete_node(indexObject *self, const char *node)
1096 static int nt_delete_node(indexObject *self, const char *node)
1097 {
1097 {
1098 /* rev==-2 happens to get encoded as 0, which is interpreted as not set */
1098 /* rev==-2 happens to get encoded as 0, which is interpreted as not set */
1099 return nt_insert(self, node, -2);
1099 return nt_insert(self, node, -2);
1100 }
1100 }
1101
1101
1102 static int nt_init(indexObject *self)
1102 static int nt_init(indexObject *self)
1103 {
1103 {
1104 if (self->nt == NULL) {
1104 if (self->nt == NULL) {
1105 if ((size_t)self->raw_length > INT_MAX / sizeof(nodetree)) {
1105 if ((size_t)self->raw_length > INT_MAX / sizeof(nodetree)) {
1106 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1106 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1107 return -1;
1107 return -1;
1108 }
1108 }
1109 self->ntcapacity = self->raw_length < 4
1109 self->ntcapacity = self->raw_length < 4
1110 ? 4 : (int)self->raw_length / 2;
1110 ? 4 : (int)self->raw_length / 2;
1111
1111
1112 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1112 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1113 if (self->nt == NULL) {
1113 if (self->nt == NULL) {
1114 PyErr_NoMemory();
1114 PyErr_NoMemory();
1115 return -1;
1115 return -1;
1116 }
1116 }
1117 self->ntlength = 1;
1117 self->ntlength = 1;
1118 self->ntrev = (int)index_length(self) - 1;
1118 self->ntrev = (int)index_length(self) - 1;
1119 self->ntlookups = 1;
1119 self->ntlookups = 1;
1120 self->ntmisses = 0;
1120 self->ntmisses = 0;
1121 if (nt_insert(self, nullid, -1) == -1) {
1121 if (nt_insert(self, nullid, -1) == -1) {
1122 free(self->nt);
1122 free(self->nt);
1123 self->nt = NULL;
1123 self->nt = NULL;
1124 return -1;
1124 return -1;
1125 }
1125 }
1126 }
1126 }
1127 return 0;
1127 return 0;
1128 }
1128 }
1129
1129
1130 /*
1130 /*
1131 * Return values:
1131 * Return values:
1132 *
1132 *
1133 * -3: error (exception set)
1133 * -3: error (exception set)
1134 * -2: not found (no exception set)
1134 * -2: not found (no exception set)
1135 * rest: valid rev
1135 * rest: valid rev
1136 */
1136 */
1137 static int index_find_node(indexObject *self,
1137 static int index_find_node(indexObject *self,
1138 const char *node, Py_ssize_t nodelen)
1138 const char *node, Py_ssize_t nodelen)
1139 {
1139 {
1140 int rev;
1140 int rev;
1141
1141
1142 if (nt_init(self) == -1)
1142 if (nt_init(self) == -1)
1143 return -3;
1143 return -3;
1144
1144
1145 self->ntlookups++;
1145 self->ntlookups++;
1146 rev = nt_find(self, node, nodelen, 0);
1146 rev = nt_find(self, node, nodelen, 0);
1147 if (rev >= -1)
1147 if (rev >= -1)
1148 return rev;
1148 return rev;
1149
1149
1150 /*
1150 /*
1151 * For the first handful of lookups, we scan the entire index,
1151 * For the first handful of lookups, we scan the entire index,
1152 * and cache only the matching nodes. This optimizes for cases
1152 * and cache only the matching nodes. This optimizes for cases
1153 * like "hg tip", where only a few nodes are accessed.
1153 * like "hg tip", where only a few nodes are accessed.
1154 *
1154 *
1155 * After that, we cache every node we visit, using a single
1155 * After that, we cache every node we visit, using a single
1156 * scan amortized over multiple lookups. This gives the best
1156 * scan amortized over multiple lookups. This gives the best
1157 * bulk performance, e.g. for "hg log".
1157 * bulk performance, e.g. for "hg log".
1158 */
1158 */
1159 if (self->ntmisses++ < 4) {
1159 if (self->ntmisses++ < 4) {
1160 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1160 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1161 const char *n = index_node_existing(self, rev);
1161 const char *n = index_node_existing(self, rev);
1162 if (n == NULL)
1162 if (n == NULL)
1163 return -3;
1163 return -3;
1164 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1164 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1165 if (nt_insert(self, n, rev) == -1)
1165 if (nt_insert(self, n, rev) == -1)
1166 return -3;
1166 return -3;
1167 break;
1167 break;
1168 }
1168 }
1169 }
1169 }
1170 } else {
1170 } else {
1171 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1171 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1172 const char *n = index_node_existing(self, rev);
1172 const char *n = index_node_existing(self, rev);
1173 if (n == NULL)
1173 if (n == NULL)
1174 return -3;
1174 return -3;
1175 if (nt_insert(self, n, rev) == -1) {
1175 if (nt_insert(self, n, rev) == -1) {
1176 self->ntrev = rev + 1;
1176 self->ntrev = rev + 1;
1177 return -3;
1177 return -3;
1178 }
1178 }
1179 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1179 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1180 break;
1180 break;
1181 }
1181 }
1182 }
1182 }
1183 self->ntrev = rev;
1183 self->ntrev = rev;
1184 }
1184 }
1185
1185
1186 if (rev >= 0)
1186 if (rev >= 0)
1187 return rev;
1187 return rev;
1188 return -2;
1188 return -2;
1189 }
1189 }
1190
1190
1191 static void raise_revlog_error(void)
1191 static void raise_revlog_error(void)
1192 {
1192 {
1193 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
1193 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
1194
1194
1195 mod = PyImport_ImportModule("mercurial.error");
1195 mod = PyImport_ImportModule("mercurial.error");
1196 if (mod == NULL) {
1196 if (mod == NULL) {
1197 goto cleanup;
1197 goto cleanup;
1198 }
1198 }
1199
1199
1200 dict = PyModule_GetDict(mod);
1200 dict = PyModule_GetDict(mod);
1201 if (dict == NULL) {
1201 if (dict == NULL) {
1202 goto cleanup;
1202 goto cleanup;
1203 }
1203 }
1204 Py_INCREF(dict);
1204 Py_INCREF(dict);
1205
1205
1206 errclass = PyDict_GetItemString(dict, "RevlogError");
1206 errclass = PyDict_GetItemString(dict, "RevlogError");
1207 if (errclass == NULL) {
1207 if (errclass == NULL) {
1208 PyErr_SetString(PyExc_SystemError,
1208 PyErr_SetString(PyExc_SystemError,
1209 "could not find RevlogError");
1209 "could not find RevlogError");
1210 goto cleanup;
1210 goto cleanup;
1211 }
1211 }
1212
1212
1213 /* value of exception is ignored by callers */
1213 /* value of exception is ignored by callers */
1214 PyErr_SetString(errclass, "RevlogError");
1214 PyErr_SetString(errclass, "RevlogError");
1215
1215
1216 cleanup:
1216 cleanup:
1217 Py_XDECREF(dict);
1217 Py_XDECREF(dict);
1218 Py_XDECREF(mod);
1218 Py_XDECREF(mod);
1219 }
1219 }
1220
1220
1221 static PyObject *index_getitem(indexObject *self, PyObject *value)
1221 static PyObject *index_getitem(indexObject *self, PyObject *value)
1222 {
1222 {
1223 char *node;
1223 char *node;
1224 int rev;
1224 int rev;
1225
1225
1226 if (PyInt_Check(value))
1226 if (PyInt_Check(value))
1227 return index_get(self, PyInt_AS_LONG(value));
1227 return index_get(self, PyInt_AS_LONG(value));
1228
1228
1229 if (node_check(value, &node) == -1)
1229 if (node_check(value, &node) == -1)
1230 return NULL;
1230 return NULL;
1231 rev = index_find_node(self, node, 20);
1231 rev = index_find_node(self, node, 20);
1232 if (rev >= -1)
1232 if (rev >= -1)
1233 return PyInt_FromLong(rev);
1233 return PyInt_FromLong(rev);
1234 if (rev == -2)
1234 if (rev == -2)
1235 raise_revlog_error();
1235 raise_revlog_error();
1236 return NULL;
1236 return NULL;
1237 }
1237 }
1238
1238
1239 /*
1239 /*
1240 * Fully populate the radix tree.
1240 * Fully populate the radix tree.
1241 */
1241 */
1242 static int nt_populate(indexObject *self) {
1242 static int nt_populate(indexObject *self) {
1243 int rev;
1243 int rev;
1244 if (self->ntrev > 0) {
1244 if (self->ntrev > 0) {
1245 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1245 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1246 const char *n = index_node_existing(self, rev);
1246 const char *n = index_node_existing(self, rev);
1247 if (n == NULL)
1247 if (n == NULL)
1248 return -1;
1248 return -1;
1249 if (nt_insert(self, n, rev) == -1)
1249 if (nt_insert(self, n, rev) == -1)
1250 return -1;
1250 return -1;
1251 }
1251 }
1252 self->ntrev = -1;
1252 self->ntrev = -1;
1253 }
1253 }
1254 return 0;
1254 return 0;
1255 }
1255 }
1256
1256
1257 static int nt_partialmatch(indexObject *self, const char *node,
1257 static int nt_partialmatch(indexObject *self, const char *node,
1258 Py_ssize_t nodelen)
1258 Py_ssize_t nodelen)
1259 {
1259 {
1260 if (nt_init(self) == -1)
1260 if (nt_init(self) == -1)
1261 return -3;
1261 return -3;
1262 if (nt_populate(self) == -1)
1262 if (nt_populate(self) == -1)
1263 return -3;
1263 return -3;
1264
1264
1265 return nt_find(self, node, nodelen, 1);
1265 return nt_find(self, node, nodelen, 1);
1266 }
1266 }
1267
1267
1268 /*
1268 /*
1269 * Find the length of the shortest unique prefix of node.
1269 * Find the length of the shortest unique prefix of node.
1270 *
1270 *
1271 * Return values:
1271 * Return values:
1272 *
1272 *
1273 * -3: error (exception set)
1273 * -3: error (exception set)
1274 * -2: not found (no exception set)
1274 * -2: not found (no exception set)
1275 * rest: length of shortest prefix
1275 * rest: length of shortest prefix
1276 */
1276 */
1277 static int nt_shortest(indexObject *self, const char *node)
1277 static int nt_shortest(indexObject *self, const char *node)
1278 {
1278 {
1279 int level, off;
1279 int level, off;
1280
1280
1281 if (nt_init(self) == -1)
1281 if (nt_init(self) == -1)
1282 return -3;
1282 return -3;
1283 if (nt_populate(self) == -1)
1283 if (nt_populate(self) == -1)
1284 return -3;
1284 return -3;
1285
1285
1286 for (level = off = 0; level < 40; level++) {
1286 for (level = off = 0; level < 40; level++) {
1287 int k, v;
1287 int k, v;
1288 nodetree *n = &self->nt[off];
1288 nodetree *n = &self->nt[off];
1289 k = nt_level(node, level);
1289 k = nt_level(node, level);
1290 v = n->children[k];
1290 v = n->children[k];
1291 if (v < 0) {
1291 if (v < 0) {
1292 const char *n;
1292 const char *n;
1293 v = -(v + 2);
1293 v = -(v + 2);
1294 n = index_node_existing(self, v);
1294 n = index_node_existing(self, v);
1295 if (n == NULL)
1295 if (n == NULL)
1296 return -3;
1296 return -3;
1297 if (memcmp(node, n, 20) != 0)
1297 if (memcmp(node, n, 20) != 0)
1298 /*
1298 /*
1299 * Found a unique prefix, but it wasn't for the
1299 * Found a unique prefix, but it wasn't for the
1300 * requested node (i.e the requested node does
1300 * requested node (i.e the requested node does
1301 * not exist).
1301 * not exist).
1302 */
1302 */
1303 return -2;
1303 return -2;
1304 return level + 1;
1304 return level + 1;
1305 }
1305 }
1306 if (v == 0)
1306 if (v == 0)
1307 return -2;
1307 return -2;
1308 off = v;
1308 off = v;
1309 }
1309 }
1310 /*
1310 /*
1311 * The node was still not unique after 40 hex digits, so this won't
1311 * The node was still not unique after 40 hex digits, so this won't
1312 * happen. Also, if we get here, then there's a programming error in
1312 * happen. Also, if we get here, then there's a programming error in
1313 * this file that made us insert a node longer than 40 hex digits.
1313 * this file that made us insert a node longer than 40 hex digits.
1314 */
1314 */
1315 PyErr_SetString(PyExc_Exception, "broken node tree");
1315 PyErr_SetString(PyExc_Exception, "broken node tree");
1316 return -3;
1316 return -3;
1317 }
1317 }
1318
1318
1319 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1319 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1320 {
1320 {
1321 const char *fullnode;
1321 const char *fullnode;
1322 int nodelen;
1322 int nodelen;
1323 char *node;
1323 char *node;
1324 int rev, i;
1324 int rev, i;
1325
1325
1326 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1326 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1327 return NULL;
1327 return NULL;
1328
1328
1329 if (nodelen < 1) {
1329 if (nodelen < 1) {
1330 PyErr_SetString(PyExc_ValueError, "key too short");
1330 PyErr_SetString(PyExc_ValueError, "key too short");
1331 return NULL;
1331 return NULL;
1332 }
1332 }
1333
1333
1334 if (nodelen > 40) {
1334 if (nodelen > 40) {
1335 PyErr_SetString(PyExc_ValueError, "key too long");
1335 PyErr_SetString(PyExc_ValueError, "key too long");
1336 return NULL;
1336 return NULL;
1337 }
1337 }
1338
1338
1339 for (i = 0; i < nodelen; i++)
1339 for (i = 0; i < nodelen; i++)
1340 hexdigit(node, i);
1340 hexdigit(node, i);
1341 if (PyErr_Occurred()) {
1341 if (PyErr_Occurred()) {
1342 /* input contains non-hex characters */
1342 /* input contains non-hex characters */
1343 PyErr_Clear();
1343 PyErr_Clear();
1344 Py_RETURN_NONE;
1344 Py_RETURN_NONE;
1345 }
1345 }
1346
1346
1347 rev = nt_partialmatch(self, node, nodelen);
1347 rev = nt_partialmatch(self, node, nodelen);
1348
1348
1349 switch (rev) {
1349 switch (rev) {
1350 case -4:
1350 case -4:
1351 raise_revlog_error();
1351 raise_revlog_error();
1352 case -3:
1352 case -3:
1353 return NULL;
1353 return NULL;
1354 case -2:
1354 case -2:
1355 Py_RETURN_NONE;
1355 Py_RETURN_NONE;
1356 case -1:
1356 case -1:
1357 return PyBytes_FromStringAndSize(nullid, 20);
1357 return PyBytes_FromStringAndSize(nullid, 20);
1358 }
1358 }
1359
1359
1360 fullnode = index_node_existing(self, rev);
1360 fullnode = index_node_existing(self, rev);
1361 if (fullnode == NULL) {
1361 if (fullnode == NULL) {
1362 return NULL;
1362 return NULL;
1363 }
1363 }
1364 return PyBytes_FromStringAndSize(fullnode, 20);
1364 return PyBytes_FromStringAndSize(fullnode, 20);
1365 }
1365 }
1366
1366
1367 static PyObject *index_shortest(indexObject *self, PyObject *args)
1367 static PyObject *index_shortest(indexObject *self, PyObject *args)
1368 {
1368 {
1369 PyObject *val;
1369 PyObject *val;
1370 char *node;
1370 char *node;
1371 int length;
1371 int length;
1372
1372
1373 if (!PyArg_ParseTuple(args, "O", &val))
1373 if (!PyArg_ParseTuple(args, "O", &val))
1374 return NULL;
1374 return NULL;
1375 if (node_check(val, &node) == -1)
1375 if (node_check(val, &node) == -1)
1376 return NULL;
1376 return NULL;
1377
1377
1378 self->ntlookups++;
1378 self->ntlookups++;
1379 length = nt_shortest(self, node);
1379 length = nt_shortest(self, node);
1380 if (length == -3)
1380 if (length == -3)
1381 return NULL;
1381 return NULL;
1382 if (length == -2) {
1382 if (length == -2) {
1383 raise_revlog_error();
1383 raise_revlog_error();
1384 return NULL;
1384 return NULL;
1385 }
1385 }
1386 return PyInt_FromLong(length);
1386 return PyInt_FromLong(length);
1387 }
1387 }
1388
1388
1389 static PyObject *index_m_get(indexObject *self, PyObject *args)
1389 static PyObject *index_m_get(indexObject *self, PyObject *args)
1390 {
1390 {
1391 PyObject *val;
1391 PyObject *val;
1392 char *node;
1392 char *node;
1393 int rev;
1393 int rev;
1394
1394
1395 if (!PyArg_ParseTuple(args, "O", &val))
1395 if (!PyArg_ParseTuple(args, "O", &val))
1396 return NULL;
1396 return NULL;
1397 if (node_check(val, &node) == -1)
1397 if (node_check(val, &node) == -1)
1398 return NULL;
1398 return NULL;
1399 rev = index_find_node(self, node, 20);
1399 rev = index_find_node(self, node, 20);
1400 if (rev == -3)
1400 if (rev == -3)
1401 return NULL;
1401 return NULL;
1402 if (rev == -2)
1402 if (rev == -2)
1403 Py_RETURN_NONE;
1403 Py_RETURN_NONE;
1404 return PyInt_FromLong(rev);
1404 return PyInt_FromLong(rev);
1405 }
1405 }
1406
1406
1407 static int index_contains(indexObject *self, PyObject *value)
1407 static int index_contains(indexObject *self, PyObject *value)
1408 {
1408 {
1409 char *node;
1409 char *node;
1410
1410
1411 if (PyInt_Check(value)) {
1411 if (PyInt_Check(value)) {
1412 long rev = PyInt_AS_LONG(value);
1412 long rev = PyInt_AS_LONG(value);
1413 return rev >= -1 && rev < index_length(self);
1413 return rev >= -1 && rev < index_length(self);
1414 }
1414 }
1415
1415
1416 if (node_check(value, &node) == -1)
1416 if (node_check(value, &node) == -1)
1417 return -1;
1417 return -1;
1418
1418
1419 switch (index_find_node(self, node, 20)) {
1419 switch (index_find_node(self, node, 20)) {
1420 case -3:
1420 case -3:
1421 return -1;
1421 return -1;
1422 case -2:
1422 case -2:
1423 return 0;
1423 return 0;
1424 default:
1424 default:
1425 return 1;
1425 return 1;
1426 }
1426 }
1427 }
1427 }
1428
1428
1429 typedef uint64_t bitmask;
1429 typedef uint64_t bitmask;
1430
1430
1431 /*
1431 /*
1432 * Given a disjoint set of revs, return all candidates for the
1432 * Given a disjoint set of revs, return all candidates for the
1433 * greatest common ancestor. In revset notation, this is the set
1433 * greatest common ancestor. In revset notation, this is the set
1434 * "heads(::a and ::b and ...)"
1434 * "heads(::a and ::b and ...)"
1435 */
1435 */
1436 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1436 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1437 int revcount)
1437 int revcount)
1438 {
1438 {
1439 const bitmask allseen = (1ull << revcount) - 1;
1439 const bitmask allseen = (1ull << revcount) - 1;
1440 const bitmask poison = 1ull << revcount;
1440 const bitmask poison = 1ull << revcount;
1441 PyObject *gca = PyList_New(0);
1441 PyObject *gca = PyList_New(0);
1442 int i, v, interesting;
1442 int i, v, interesting;
1443 int maxrev = -1;
1443 int maxrev = -1;
1444 bitmask sp;
1444 bitmask sp;
1445 bitmask *seen;
1445 bitmask *seen;
1446
1446
1447 if (gca == NULL)
1447 if (gca == NULL)
1448 return PyErr_NoMemory();
1448 return PyErr_NoMemory();
1449
1449
1450 for (i = 0; i < revcount; i++) {
1450 for (i = 0; i < revcount; i++) {
1451 if (revs[i] > maxrev)
1451 if (revs[i] > maxrev)
1452 maxrev = revs[i];
1452 maxrev = revs[i];
1453 }
1453 }
1454
1454
1455 seen = calloc(sizeof(*seen), maxrev + 1);
1455 seen = calloc(sizeof(*seen), maxrev + 1);
1456 if (seen == NULL) {
1456 if (seen == NULL) {
1457 Py_DECREF(gca);
1457 Py_DECREF(gca);
1458 return PyErr_NoMemory();
1458 return PyErr_NoMemory();
1459 }
1459 }
1460
1460
1461 for (i = 0; i < revcount; i++)
1461 for (i = 0; i < revcount; i++)
1462 seen[revs[i]] = 1ull << i;
1462 seen[revs[i]] = 1ull << i;
1463
1463
1464 interesting = revcount;
1464 interesting = revcount;
1465
1465
1466 for (v = maxrev; v >= 0 && interesting; v--) {
1466 for (v = maxrev; v >= 0 && interesting; v--) {
1467 bitmask sv = seen[v];
1467 bitmask sv = seen[v];
1468 int parents[2];
1468 int parents[2];
1469
1469
1470 if (!sv)
1470 if (!sv)
1471 continue;
1471 continue;
1472
1472
1473 if (sv < poison) {
1473 if (sv < poison) {
1474 interesting -= 1;
1474 interesting -= 1;
1475 if (sv == allseen) {
1475 if (sv == allseen) {
1476 PyObject *obj = PyInt_FromLong(v);
1476 PyObject *obj = PyInt_FromLong(v);
1477 if (obj == NULL)
1477 if (obj == NULL)
1478 goto bail;
1478 goto bail;
1479 if (PyList_Append(gca, obj) == -1) {
1479 if (PyList_Append(gca, obj) == -1) {
1480 Py_DECREF(obj);
1480 Py_DECREF(obj);
1481 goto bail;
1481 goto bail;
1482 }
1482 }
1483 sv |= poison;
1483 sv |= poison;
1484 for (i = 0; i < revcount; i++) {
1484 for (i = 0; i < revcount; i++) {
1485 if (revs[i] == v)
1485 if (revs[i] == v)
1486 goto done;
1486 goto done;
1487 }
1487 }
1488 }
1488 }
1489 }
1489 }
1490 if (index_get_parents(self, v, parents, maxrev) < 0)
1490 if (index_get_parents(self, v, parents, maxrev) < 0)
1491 goto bail;
1491 goto bail;
1492
1492
1493 for (i = 0; i < 2; i++) {
1493 for (i = 0; i < 2; i++) {
1494 int p = parents[i];
1494 int p = parents[i];
1495 if (p == -1)
1495 if (p == -1)
1496 continue;
1496 continue;
1497 sp = seen[p];
1497 sp = seen[p];
1498 if (sv < poison) {
1498 if (sv < poison) {
1499 if (sp == 0) {
1499 if (sp == 0) {
1500 seen[p] = sv;
1500 seen[p] = sv;
1501 interesting++;
1501 interesting++;
1502 }
1502 }
1503 else if (sp != sv)
1503 else if (sp != sv)
1504 seen[p] |= sv;
1504 seen[p] |= sv;
1505 } else {
1505 } else {
1506 if (sp && sp < poison)
1506 if (sp && sp < poison)
1507 interesting--;
1507 interesting--;
1508 seen[p] = sv;
1508 seen[p] = sv;
1509 }
1509 }
1510 }
1510 }
1511 }
1511 }
1512
1512
1513 done:
1513 done:
1514 free(seen);
1514 free(seen);
1515 return gca;
1515 return gca;
1516 bail:
1516 bail:
1517 free(seen);
1517 free(seen);
1518 Py_XDECREF(gca);
1518 Py_XDECREF(gca);
1519 return NULL;
1519 return NULL;
1520 }
1520 }
1521
1521
1522 /*
1522 /*
1523 * Given a disjoint set of revs, return the subset with the longest
1523 * Given a disjoint set of revs, return the subset with the longest
1524 * path to the root.
1524 * path to the root.
1525 */
1525 */
1526 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1526 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1527 {
1527 {
1528 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1528 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1529 static const Py_ssize_t capacity = 24;
1529 static const Py_ssize_t capacity = 24;
1530 int *depth, *interesting = NULL;
1530 int *depth, *interesting = NULL;
1531 int i, j, v, ninteresting;
1531 int i, j, v, ninteresting;
1532 PyObject *dict = NULL, *keys = NULL;
1532 PyObject *dict = NULL, *keys = NULL;
1533 long *seen = NULL;
1533 long *seen = NULL;
1534 int maxrev = -1;
1534 int maxrev = -1;
1535 long final;
1535 long final;
1536
1536
1537 if (revcount > capacity) {
1537 if (revcount > capacity) {
1538 PyErr_Format(PyExc_OverflowError,
1538 PyErr_Format(PyExc_OverflowError,
1539 "bitset size (%ld) > capacity (%ld)",
1539 "bitset size (%ld) > capacity (%ld)",
1540 (long)revcount, (long)capacity);
1540 (long)revcount, (long)capacity);
1541 return NULL;
1541 return NULL;
1542 }
1542 }
1543
1543
1544 for (i = 0; i < revcount; i++) {
1544 for (i = 0; i < revcount; i++) {
1545 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1545 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1546 if (n > maxrev)
1546 if (n > maxrev)
1547 maxrev = n;
1547 maxrev = n;
1548 }
1548 }
1549
1549
1550 depth = calloc(sizeof(*depth), maxrev + 1);
1550 depth = calloc(sizeof(*depth), maxrev + 1);
1551 if (depth == NULL)
1551 if (depth == NULL)
1552 return PyErr_NoMemory();
1552 return PyErr_NoMemory();
1553
1553
1554 seen = calloc(sizeof(*seen), maxrev + 1);
1554 seen = calloc(sizeof(*seen), maxrev + 1);
1555 if (seen == NULL) {
1555 if (seen == NULL) {
1556 PyErr_NoMemory();
1556 PyErr_NoMemory();
1557 goto bail;
1557 goto bail;
1558 }
1558 }
1559
1559
1560 interesting = calloc(sizeof(*interesting), 1 << revcount);
1560 interesting = calloc(sizeof(*interesting), 1 << revcount);
1561 if (interesting == NULL) {
1561 if (interesting == NULL) {
1562 PyErr_NoMemory();
1562 PyErr_NoMemory();
1563 goto bail;
1563 goto bail;
1564 }
1564 }
1565
1565
1566 if (PyList_Sort(revs) == -1)
1566 if (PyList_Sort(revs) == -1)
1567 goto bail;
1567 goto bail;
1568
1568
1569 for (i = 0; i < revcount; i++) {
1569 for (i = 0; i < revcount; i++) {
1570 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1570 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1571 long b = 1l << i;
1571 long b = 1l << i;
1572 depth[n] = 1;
1572 depth[n] = 1;
1573 seen[n] = b;
1573 seen[n] = b;
1574 interesting[b] = 1;
1574 interesting[b] = 1;
1575 }
1575 }
1576
1576
1577 /* invariant: ninteresting is the number of non-zero entries in
1577 /* invariant: ninteresting is the number of non-zero entries in
1578 * interesting. */
1578 * interesting. */
1579 ninteresting = (int)revcount;
1579 ninteresting = (int)revcount;
1580
1580
1581 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1581 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1582 int dv = depth[v];
1582 int dv = depth[v];
1583 int parents[2];
1583 int parents[2];
1584 long sv;
1584 long sv;
1585
1585
1586 if (dv == 0)
1586 if (dv == 0)
1587 continue;
1587 continue;
1588
1588
1589 sv = seen[v];
1589 sv = seen[v];
1590 if (index_get_parents(self, v, parents, maxrev) < 0)
1590 if (index_get_parents(self, v, parents, maxrev) < 0)
1591 goto bail;
1591 goto bail;
1592
1592
1593 for (i = 0; i < 2; i++) {
1593 for (i = 0; i < 2; i++) {
1594 int p = parents[i];
1594 int p = parents[i];
1595 long sp;
1595 long sp;
1596 int dp;
1596 int dp;
1597
1597
1598 if (p == -1)
1598 if (p == -1)
1599 continue;
1599 continue;
1600
1600
1601 dp = depth[p];
1601 dp = depth[p];
1602 sp = seen[p];
1602 sp = seen[p];
1603 if (dp <= dv) {
1603 if (dp <= dv) {
1604 depth[p] = dv + 1;
1604 depth[p] = dv + 1;
1605 if (sp != sv) {
1605 if (sp != sv) {
1606 interesting[sv] += 1;
1606 interesting[sv] += 1;
1607 seen[p] = sv;
1607 seen[p] = sv;
1608 if (sp) {
1608 if (sp) {
1609 interesting[sp] -= 1;
1609 interesting[sp] -= 1;
1610 if (interesting[sp] == 0)
1610 if (interesting[sp] == 0)
1611 ninteresting -= 1;
1611 ninteresting -= 1;
1612 }
1612 }
1613 }
1613 }
1614 }
1614 }
1615 else if (dv == dp - 1) {
1615 else if (dv == dp - 1) {
1616 long nsp = sp | sv;
1616 long nsp = sp | sv;
1617 if (nsp == sp)
1617 if (nsp == sp)
1618 continue;
1618 continue;
1619 seen[p] = nsp;
1619 seen[p] = nsp;
1620 interesting[sp] -= 1;
1620 interesting[sp] -= 1;
1621 if (interesting[sp] == 0)
1621 if (interesting[sp] == 0)
1622 ninteresting -= 1;
1622 ninteresting -= 1;
1623 if (interesting[nsp] == 0)
1623 if (interesting[nsp] == 0)
1624 ninteresting += 1;
1624 ninteresting += 1;
1625 interesting[nsp] += 1;
1625 interesting[nsp] += 1;
1626 }
1626 }
1627 }
1627 }
1628 interesting[sv] -= 1;
1628 interesting[sv] -= 1;
1629 if (interesting[sv] == 0)
1629 if (interesting[sv] == 0)
1630 ninteresting -= 1;
1630 ninteresting -= 1;
1631 }
1631 }
1632
1632
1633 final = 0;
1633 final = 0;
1634 j = ninteresting;
1634 j = ninteresting;
1635 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1635 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1636 if (interesting[i] == 0)
1636 if (interesting[i] == 0)
1637 continue;
1637 continue;
1638 final |= i;
1638 final |= i;
1639 j -= 1;
1639 j -= 1;
1640 }
1640 }
1641 if (final == 0) {
1641 if (final == 0) {
1642 keys = PyList_New(0);
1642 keys = PyList_New(0);
1643 goto bail;
1643 goto bail;
1644 }
1644 }
1645
1645
1646 dict = PyDict_New();
1646 dict = PyDict_New();
1647 if (dict == NULL)
1647 if (dict == NULL)
1648 goto bail;
1648 goto bail;
1649
1649
1650 for (i = 0; i < revcount; i++) {
1650 for (i = 0; i < revcount; i++) {
1651 PyObject *key;
1651 PyObject *key;
1652
1652
1653 if ((final & (1 << i)) == 0)
1653 if ((final & (1 << i)) == 0)
1654 continue;
1654 continue;
1655
1655
1656 key = PyList_GET_ITEM(revs, i);
1656 key = PyList_GET_ITEM(revs, i);
1657 Py_INCREF(key);
1657 Py_INCREF(key);
1658 Py_INCREF(Py_None);
1658 Py_INCREF(Py_None);
1659 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1659 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1660 Py_DECREF(key);
1660 Py_DECREF(key);
1661 Py_DECREF(Py_None);
1661 Py_DECREF(Py_None);
1662 goto bail;
1662 goto bail;
1663 }
1663 }
1664 }
1664 }
1665
1665
1666 keys = PyDict_Keys(dict);
1666 keys = PyDict_Keys(dict);
1667
1667
1668 bail:
1668 bail:
1669 free(depth);
1669 free(depth);
1670 free(seen);
1670 free(seen);
1671 free(interesting);
1671 free(interesting);
1672 Py_XDECREF(dict);
1672 Py_XDECREF(dict);
1673
1673
1674 return keys;
1674 return keys;
1675 }
1675 }
1676
1676
1677 /*
1677 /*
1678 * Given a (possibly overlapping) set of revs, return all the
1678 * Given a (possibly overlapping) set of revs, return all the
1679 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1679 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1680 */
1680 */
1681 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1681 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1682 {
1682 {
1683 PyObject *ret = NULL;
1683 PyObject *ret = NULL;
1684 Py_ssize_t argcount, i, len;
1684 Py_ssize_t argcount, i, len;
1685 bitmask repeat = 0;
1685 bitmask repeat = 0;
1686 int revcount = 0;
1686 int revcount = 0;
1687 int *revs;
1687 int *revs;
1688
1688
1689 argcount = PySequence_Length(args);
1689 argcount = PySequence_Length(args);
1690 revs = PyMem_Malloc(argcount * sizeof(*revs));
1690 revs = PyMem_Malloc(argcount * sizeof(*revs));
1691 if (argcount > 0 && revs == NULL)
1691 if (argcount > 0 && revs == NULL)
1692 return PyErr_NoMemory();
1692 return PyErr_NoMemory();
1693 len = index_length(self) - 1;
1693 len = index_length(self) - 1;
1694
1694
1695 for (i = 0; i < argcount; i++) {
1695 for (i = 0; i < argcount; i++) {
1696 static const int capacity = 24;
1696 static const int capacity = 24;
1697 PyObject *obj = PySequence_GetItem(args, i);
1697 PyObject *obj = PySequence_GetItem(args, i);
1698 bitmask x;
1698 bitmask x;
1699 long val;
1699 long val;
1700
1700
1701 if (!PyInt_Check(obj)) {
1701 if (!PyInt_Check(obj)) {
1702 PyErr_SetString(PyExc_TypeError,
1702 PyErr_SetString(PyExc_TypeError,
1703 "arguments must all be ints");
1703 "arguments must all be ints");
1704 Py_DECREF(obj);
1704 Py_DECREF(obj);
1705 goto bail;
1705 goto bail;
1706 }
1706 }
1707 val = PyInt_AsLong(obj);
1707 val = PyInt_AsLong(obj);
1708 Py_DECREF(obj);
1708 Py_DECREF(obj);
1709 if (val == -1) {
1709 if (val == -1) {
1710 ret = PyList_New(0);
1710 ret = PyList_New(0);
1711 goto done;
1711 goto done;
1712 }
1712 }
1713 if (val < 0 || val >= len) {
1713 if (val < 0 || val >= len) {
1714 PyErr_SetString(PyExc_IndexError,
1714 PyErr_SetString(PyExc_IndexError,
1715 "index out of range");
1715 "index out of range");
1716 goto bail;
1716 goto bail;
1717 }
1717 }
1718 /* this cheesy bloom filter lets us avoid some more
1718 /* this cheesy bloom filter lets us avoid some more
1719 * expensive duplicate checks in the common set-is-disjoint
1719 * expensive duplicate checks in the common set-is-disjoint
1720 * case */
1720 * case */
1721 x = 1ull << (val & 0x3f);
1721 x = 1ull << (val & 0x3f);
1722 if (repeat & x) {
1722 if (repeat & x) {
1723 int k;
1723 int k;
1724 for (k = 0; k < revcount; k++) {
1724 for (k = 0; k < revcount; k++) {
1725 if (val == revs[k])
1725 if (val == revs[k])
1726 goto duplicate;
1726 goto duplicate;
1727 }
1727 }
1728 }
1728 }
1729 else repeat |= x;
1729 else repeat |= x;
1730 if (revcount >= capacity) {
1730 if (revcount >= capacity) {
1731 PyErr_Format(PyExc_OverflowError,
1731 PyErr_Format(PyExc_OverflowError,
1732 "bitset size (%d) > capacity (%d)",
1732 "bitset size (%d) > capacity (%d)",
1733 revcount, capacity);
1733 revcount, capacity);
1734 goto bail;
1734 goto bail;
1735 }
1735 }
1736 revs[revcount++] = (int)val;
1736 revs[revcount++] = (int)val;
1737 duplicate:;
1737 duplicate:;
1738 }
1738 }
1739
1739
1740 if (revcount == 0) {
1740 if (revcount == 0) {
1741 ret = PyList_New(0);
1741 ret = PyList_New(0);
1742 goto done;
1742 goto done;
1743 }
1743 }
1744 if (revcount == 1) {
1744 if (revcount == 1) {
1745 PyObject *obj;
1745 PyObject *obj;
1746 ret = PyList_New(1);
1746 ret = PyList_New(1);
1747 if (ret == NULL)
1747 if (ret == NULL)
1748 goto bail;
1748 goto bail;
1749 obj = PyInt_FromLong(revs[0]);
1749 obj = PyInt_FromLong(revs[0]);
1750 if (obj == NULL)
1750 if (obj == NULL)
1751 goto bail;
1751 goto bail;
1752 PyList_SET_ITEM(ret, 0, obj);
1752 PyList_SET_ITEM(ret, 0, obj);
1753 goto done;
1753 goto done;
1754 }
1754 }
1755
1755
1756 ret = find_gca_candidates(self, revs, revcount);
1756 ret = find_gca_candidates(self, revs, revcount);
1757 if (ret == NULL)
1757 if (ret == NULL)
1758 goto bail;
1758 goto bail;
1759
1759
1760 done:
1760 done:
1761 PyMem_Free(revs);
1761 PyMem_Free(revs);
1762 return ret;
1762 return ret;
1763
1763
1764 bail:
1764 bail:
1765 PyMem_Free(revs);
1765 PyMem_Free(revs);
1766 Py_XDECREF(ret);
1766 Py_XDECREF(ret);
1767 return NULL;
1767 return NULL;
1768 }
1768 }
1769
1769
1770 /*
1770 /*
1771 * Given a (possibly overlapping) set of revs, return the greatest
1771 * Given a (possibly overlapping) set of revs, return the greatest
1772 * common ancestors: those with the longest path to the root.
1772 * common ancestors: those with the longest path to the root.
1773 */
1773 */
1774 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1774 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1775 {
1775 {
1776 PyObject *ret;
1776 PyObject *ret;
1777 PyObject *gca = index_commonancestorsheads(self, args);
1777 PyObject *gca = index_commonancestorsheads(self, args);
1778 if (gca == NULL)
1778 if (gca == NULL)
1779 return NULL;
1779 return NULL;
1780
1780
1781 if (PyList_GET_SIZE(gca) <= 1) {
1781 if (PyList_GET_SIZE(gca) <= 1) {
1782 return gca;
1782 return gca;
1783 }
1783 }
1784
1784
1785 ret = find_deepest(self, gca);
1785 ret = find_deepest(self, gca);
1786 Py_DECREF(gca);
1786 Py_DECREF(gca);
1787 return ret;
1787 return ret;
1788 }
1788 }
1789
1789
1790 /*
1790 /*
1791 * Invalidate any trie entries introduced by added revs.
1791 * Invalidate any trie entries introduced by added revs.
1792 */
1792 */
1793 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1793 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1794 {
1794 {
1795 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1795 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1796
1796
1797 for (i = start; i < len; i++) {
1797 for (i = start; i < len; i++) {
1798 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1798 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1799 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1799 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1800
1800
1801 nt_delete_node(self, PyBytes_AS_STRING(node));
1801 nt_delete_node(self, PyBytes_AS_STRING(node));
1802 }
1802 }
1803
1803
1804 if (start == 0)
1804 if (start == 0)
1805 Py_CLEAR(self->added);
1805 Py_CLEAR(self->added);
1806 }
1806 }
1807
1807
1808 /*
1808 /*
1809 * Delete a numeric range of revs, which must be at the end of the
1809 * Delete a numeric range of revs, which must be at the end of the
1810 * range, but exclude the sentinel nullid entry.
1810 * range, but exclude the sentinel nullid entry.
1811 */
1811 */
1812 static int index_slice_del(indexObject *self, PyObject *item)
1812 static int index_slice_del(indexObject *self, PyObject *item)
1813 {
1813 {
1814 Py_ssize_t start, stop, step, slicelength;
1814 Py_ssize_t start, stop, step, slicelength;
1815 Py_ssize_t length = index_length(self);
1815 Py_ssize_t length = index_length(self);
1816 int ret = 0;
1816 int ret = 0;
1817
1817
1818 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
1818 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
1819 #ifdef IS_PY3K
1819 #ifdef IS_PY3K
1820 if (PySlice_GetIndicesEx(item, length,
1820 if (PySlice_GetIndicesEx(item, length,
1821 #else
1821 #else
1822 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1822 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1823 #endif
1823 #endif
1824 &start, &stop, &step, &slicelength) < 0)
1824 &start, &stop, &step, &slicelength) < 0)
1825 return -1;
1825 return -1;
1826
1826
1827 if (slicelength <= 0)
1827 if (slicelength <= 0)
1828 return 0;
1828 return 0;
1829
1829
1830 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1830 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1831 stop = start;
1831 stop = start;
1832
1832
1833 if (step < 0) {
1833 if (step < 0) {
1834 stop = start + 1;
1834 stop = start + 1;
1835 start = stop + step*(slicelength - 1) - 1;
1835 start = stop + step*(slicelength - 1) - 1;
1836 step = -step;
1836 step = -step;
1837 }
1837 }
1838
1838
1839 if (step != 1) {
1839 if (step != 1) {
1840 PyErr_SetString(PyExc_ValueError,
1840 PyErr_SetString(PyExc_ValueError,
1841 "revlog index delete requires step size of 1");
1841 "revlog index delete requires step size of 1");
1842 return -1;
1842 return -1;
1843 }
1843 }
1844
1844
1845 if (stop != length - 1) {
1845 if (stop != length - 1) {
1846 PyErr_SetString(PyExc_IndexError,
1846 PyErr_SetString(PyExc_IndexError,
1847 "revlog index deletion indices are invalid");
1847 "revlog index deletion indices are invalid");
1848 return -1;
1848 return -1;
1849 }
1849 }
1850
1850
1851 if (start < self->length - 1) {
1851 if (start < self->length - 1) {
1852 if (self->nt) {
1852 if (self->nt) {
1853 Py_ssize_t i;
1853 Py_ssize_t i;
1854
1854
1855 for (i = start + 1; i < self->length - 1; i++) {
1855 for (i = start + 1; i < self->length - 1; i++) {
1856 const char *node = index_node_existing(self, i);
1856 const char *node = index_node_existing(self, i);
1857 if (node == NULL)
1857 if (node == NULL)
1858 return -1;
1858 return -1;
1859
1859
1860 nt_delete_node(self, node);
1860 nt_delete_node(self, node);
1861 }
1861 }
1862 if (self->added)
1862 if (self->added)
1863 nt_invalidate_added(self, 0);
1863 nt_invalidate_added(self, 0);
1864 if (self->ntrev > start)
1864 if (self->ntrev > start)
1865 self->ntrev = (int)start;
1865 self->ntrev = (int)start;
1866 }
1866 }
1867 self->length = start + 1;
1867 self->length = start + 1;
1868 if (start < self->raw_length) {
1868 if (start < self->raw_length) {
1869 if (self->cache) {
1869 if (self->cache) {
1870 Py_ssize_t i;
1870 Py_ssize_t i;
1871 for (i = start; i < self->raw_length; i++)
1871 for (i = start; i < self->raw_length; i++)
1872 Py_CLEAR(self->cache[i]);
1872 Py_CLEAR(self->cache[i]);
1873 }
1873 }
1874 self->raw_length = start;
1874 self->raw_length = start;
1875 }
1875 }
1876 goto done;
1876 goto done;
1877 }
1877 }
1878
1878
1879 if (self->nt) {
1879 if (self->nt) {
1880 nt_invalidate_added(self, start - self->length + 1);
1880 nt_invalidate_added(self, start - self->length + 1);
1881 if (self->ntrev > start)
1881 if (self->ntrev > start)
1882 self->ntrev = (int)start;
1882 self->ntrev = (int)start;
1883 }
1883 }
1884 if (self->added)
1884 if (self->added)
1885 ret = PyList_SetSlice(self->added, start - self->length + 1,
1885 ret = PyList_SetSlice(self->added, start - self->length + 1,
1886 PyList_GET_SIZE(self->added), NULL);
1886 PyList_GET_SIZE(self->added), NULL);
1887 done:
1887 done:
1888 Py_CLEAR(self->headrevs);
1888 Py_CLEAR(self->headrevs);
1889 return ret;
1889 return ret;
1890 }
1890 }
1891
1891
1892 /*
1892 /*
1893 * Supported ops:
1893 * Supported ops:
1894 *
1894 *
1895 * slice deletion
1895 * slice deletion
1896 * string assignment (extend node->rev mapping)
1896 * string assignment (extend node->rev mapping)
1897 * string deletion (shrink node->rev mapping)
1897 * string deletion (shrink node->rev mapping)
1898 */
1898 */
1899 static int index_assign_subscript(indexObject *self, PyObject *item,
1899 static int index_assign_subscript(indexObject *self, PyObject *item,
1900 PyObject *value)
1900 PyObject *value)
1901 {
1901 {
1902 char *node;
1902 char *node;
1903 long rev;
1903 long rev;
1904
1904
1905 if (PySlice_Check(item) && value == NULL)
1905 if (PySlice_Check(item) && value == NULL)
1906 return index_slice_del(self, item);
1906 return index_slice_del(self, item);
1907
1907
1908 if (node_check(item, &node) == -1)
1908 if (node_check(item, &node) == -1)
1909 return -1;
1909 return -1;
1910
1910
1911 if (value == NULL)
1911 if (value == NULL)
1912 return self->nt ? nt_delete_node(self, node) : 0;
1912 return self->nt ? nt_delete_node(self, node) : 0;
1913 rev = PyInt_AsLong(value);
1913 rev = PyInt_AsLong(value);
1914 if (rev > INT_MAX || rev < 0) {
1914 if (rev > INT_MAX || rev < 0) {
1915 if (!PyErr_Occurred())
1915 if (!PyErr_Occurred())
1916 PyErr_SetString(PyExc_ValueError, "rev out of range");
1916 PyErr_SetString(PyExc_ValueError, "rev out of range");
1917 return -1;
1917 return -1;
1918 }
1918 }
1919
1919
1920 if (nt_init(self) == -1)
1920 if (nt_init(self) == -1)
1921 return -1;
1921 return -1;
1922 return nt_insert(self, node, (int)rev);
1922 return nt_insert(self, node, (int)rev);
1923 }
1923 }
1924
1924
1925 /*
1925 /*
1926 * Find all RevlogNG entries in an index that has inline data. Update
1926 * Find all RevlogNG entries in an index that has inline data. Update
1927 * the optional "offsets" table with those entries.
1927 * the optional "offsets" table with those entries.
1928 */
1928 */
1929 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
1929 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
1930 {
1930 {
1931 const char *data = (const char *)self->buf.buf;
1931 const char *data = (const char *)self->buf.buf;
1932 Py_ssize_t pos = 0;
1932 Py_ssize_t pos = 0;
1933 Py_ssize_t end = self->buf.len;
1933 Py_ssize_t end = self->buf.len;
1934 long incr = v1_hdrsize;
1934 long incr = v1_hdrsize;
1935 Py_ssize_t len = 0;
1935 Py_ssize_t len = 0;
1936
1936
1937 while (pos + v1_hdrsize <= end && pos >= 0) {
1937 while (pos + v1_hdrsize <= end && pos >= 0) {
1938 uint32_t comp_len;
1938 uint32_t comp_len;
1939 /* 3rd element of header is length of compressed inline data */
1939 /* 3rd element of header is length of compressed inline data */
1940 comp_len = getbe32(data + pos + 8);
1940 comp_len = getbe32(data + pos + 8);
1941 incr = v1_hdrsize + comp_len;
1941 incr = v1_hdrsize + comp_len;
1942 if (offsets)
1942 if (offsets)
1943 offsets[len] = data + pos;
1943 offsets[len] = data + pos;
1944 len++;
1944 len++;
1945 pos += incr;
1945 pos += incr;
1946 }
1946 }
1947
1947
1948 if (pos != end) {
1948 if (pos != end) {
1949 if (!PyErr_Occurred())
1949 if (!PyErr_Occurred())
1950 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1950 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1951 return -1;
1951 return -1;
1952 }
1952 }
1953
1953
1954 return len;
1954 return len;
1955 }
1955 }
1956
1956
1957 static int index_init(indexObject *self, PyObject *args)
1957 static int index_init(indexObject *self, PyObject *args)
1958 {
1958 {
1959 PyObject *data_obj, *inlined_obj;
1959 PyObject *data_obj, *inlined_obj;
1960 Py_ssize_t size;
1960 Py_ssize_t size;
1961
1961
1962 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1962 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1963 self->raw_length = 0;
1963 self->raw_length = 0;
1964 self->added = NULL;
1964 self->added = NULL;
1965 self->cache = NULL;
1965 self->cache = NULL;
1966 self->data = NULL;
1966 self->data = NULL;
1967 memset(&self->buf, 0, sizeof(self->buf));
1967 memset(&self->buf, 0, sizeof(self->buf));
1968 self->headrevs = NULL;
1968 self->headrevs = NULL;
1969 self->filteredrevs = Py_None;
1969 self->filteredrevs = Py_None;
1970 Py_INCREF(Py_None);
1970 Py_INCREF(Py_None);
1971 self->nt = NULL;
1971 self->nt = NULL;
1972 self->offsets = NULL;
1972 self->offsets = NULL;
1973
1973
1974 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1974 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1975 return -1;
1975 return -1;
1976 if (!PyObject_CheckBuffer(data_obj)) {
1976 if (!PyObject_CheckBuffer(data_obj)) {
1977 PyErr_SetString(PyExc_TypeError,
1977 PyErr_SetString(PyExc_TypeError,
1978 "data does not support buffer interface");
1978 "data does not support buffer interface");
1979 return -1;
1979 return -1;
1980 }
1980 }
1981
1981
1982 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
1982 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
1983 return -1;
1983 return -1;
1984 size = self->buf.len;
1984 size = self->buf.len;
1985
1985
1986 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1986 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1987 self->data = data_obj;
1987 self->data = data_obj;
1988
1988
1989 self->ntlength = self->ntcapacity = 0;
1989 self->ntlength = self->ntcapacity = 0;
1990 self->ntdepth = self->ntsplits = 0;
1990 self->ntdepth = self->ntsplits = 0;
1991 self->ntlookups = self->ntmisses = 0;
1991 self->ntlookups = self->ntmisses = 0;
1992 self->ntrev = -1;
1992 self->ntrev = -1;
1993 Py_INCREF(self->data);
1993 Py_INCREF(self->data);
1994
1994
1995 if (self->inlined) {
1995 if (self->inlined) {
1996 Py_ssize_t len = inline_scan(self, NULL);
1996 Py_ssize_t len = inline_scan(self, NULL);
1997 if (len == -1)
1997 if (len == -1)
1998 goto bail;
1998 goto bail;
1999 self->raw_length = len;
1999 self->raw_length = len;
2000 self->length = len + 1;
2000 self->length = len + 1;
2001 } else {
2001 } else {
2002 if (size % v1_hdrsize) {
2002 if (size % v1_hdrsize) {
2003 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2003 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2004 goto bail;
2004 goto bail;
2005 }
2005 }
2006 self->raw_length = size / v1_hdrsize;
2006 self->raw_length = size / v1_hdrsize;
2007 self->length = self->raw_length + 1;
2007 self->length = self->raw_length + 1;
2008 }
2008 }
2009
2009
2010 return 0;
2010 return 0;
2011 bail:
2011 bail:
2012 return -1;
2012 return -1;
2013 }
2013 }
2014
2014
2015 static PyObject *index_nodemap(indexObject *self)
2015 static PyObject *index_nodemap(indexObject *self)
2016 {
2016 {
2017 Py_INCREF(self);
2017 Py_INCREF(self);
2018 return (PyObject *)self;
2018 return (PyObject *)self;
2019 }
2019 }
2020
2020
2021 static void index_dealloc(indexObject *self)
2021 static void index_dealloc(indexObject *self)
2022 {
2022 {
2023 _index_clearcaches(self);
2023 _index_clearcaches(self);
2024 Py_XDECREF(self->filteredrevs);
2024 Py_XDECREF(self->filteredrevs);
2025 if (self->buf.buf) {
2025 if (self->buf.buf) {
2026 PyBuffer_Release(&self->buf);
2026 PyBuffer_Release(&self->buf);
2027 memset(&self->buf, 0, sizeof(self->buf));
2027 memset(&self->buf, 0, sizeof(self->buf));
2028 }
2028 }
2029 Py_XDECREF(self->data);
2029 Py_XDECREF(self->data);
2030 Py_XDECREF(self->added);
2030 Py_XDECREF(self->added);
2031 PyObject_Del(self);
2031 PyObject_Del(self);
2032 }
2032 }
2033
2033
2034 static PySequenceMethods index_sequence_methods = {
2034 static PySequenceMethods index_sequence_methods = {
2035 (lenfunc)index_length, /* sq_length */
2035 (lenfunc)index_length, /* sq_length */
2036 0, /* sq_concat */
2036 0, /* sq_concat */
2037 0, /* sq_repeat */
2037 0, /* sq_repeat */
2038 (ssizeargfunc)index_get, /* sq_item */
2038 (ssizeargfunc)index_get, /* sq_item */
2039 0, /* sq_slice */
2039 0, /* sq_slice */
2040 0, /* sq_ass_item */
2040 0, /* sq_ass_item */
2041 0, /* sq_ass_slice */
2041 0, /* sq_ass_slice */
2042 (objobjproc)index_contains, /* sq_contains */
2042 (objobjproc)index_contains, /* sq_contains */
2043 };
2043 };
2044
2044
2045 static PyMappingMethods index_mapping_methods = {
2045 static PyMappingMethods index_mapping_methods = {
2046 (lenfunc)index_length, /* mp_length */
2046 (lenfunc)index_length, /* mp_length */
2047 (binaryfunc)index_getitem, /* mp_subscript */
2047 (binaryfunc)index_getitem, /* mp_subscript */
2048 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2048 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2049 };
2049 };
2050
2050
2051 static PyMethodDef index_methods[] = {
2051 static PyMethodDef index_methods[] = {
2052 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2052 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2053 "return the gca set of the given revs"},
2053 "return the gca set of the given revs"},
2054 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2054 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2055 METH_VARARGS,
2055 METH_VARARGS,
2056 "return the heads of the common ancestors of the given revs"},
2056 "return the heads of the common ancestors of the given revs"},
2057 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2057 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2058 "clear the index caches"},
2058 "clear the index caches"},
2059 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2059 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2060 "get an index entry"},
2060 "get an index entry"},
2061 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
2061 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
2062 METH_VARARGS, "compute phases"},
2062 METH_VARARGS, "compute phases"},
2063 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2063 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2064 "reachableroots"},
2064 "reachableroots"},
2065 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2065 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2066 "get head revisions"}, /* Can do filtering since 3.2 */
2066 "get head revisions"}, /* Can do filtering since 3.2 */
2067 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2067 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2068 "get filtered head revisions"}, /* Can always do filtering */
2068 "get filtered head revisions"}, /* Can always do filtering */
2069 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2069 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2070 "determine revisions with deltas to reconstruct fulltext"},
2070 "determine revisions with deltas to reconstruct fulltext"},
2071 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2071 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2072 "insert an index entry"},
2072 "insert an index entry"},
2073 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2073 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2074 "match a potentially ambiguous node ID"},
2074 "match a potentially ambiguous node ID"},
2075 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2075 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2076 "find length of shortest hex nodeid of a binary ID"},
2076 "find length of shortest hex nodeid of a binary ID"},
2077 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2077 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2078 "stats for the index"},
2078 "stats for the index"},
2079 {NULL} /* Sentinel */
2079 {NULL} /* Sentinel */
2080 };
2080 };
2081
2081
2082 static PyGetSetDef index_getset[] = {
2082 static PyGetSetDef index_getset[] = {
2083 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2083 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2084 {NULL} /* Sentinel */
2084 {NULL} /* Sentinel */
2085 };
2085 };
2086
2086
2087 static PyTypeObject indexType = {
2087 static PyTypeObject indexType = {
2088 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2088 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2089 "parsers.index", /* tp_name */
2089 "parsers.index", /* tp_name */
2090 sizeof(indexObject), /* tp_basicsize */
2090 sizeof(indexObject), /* tp_basicsize */
2091 0, /* tp_itemsize */
2091 0, /* tp_itemsize */
2092 (destructor)index_dealloc, /* tp_dealloc */
2092 (destructor)index_dealloc, /* tp_dealloc */
2093 0, /* tp_print */
2093 0, /* tp_print */
2094 0, /* tp_getattr */
2094 0, /* tp_getattr */
2095 0, /* tp_setattr */
2095 0, /* tp_setattr */
2096 0, /* tp_compare */
2096 0, /* tp_compare */
2097 0, /* tp_repr */
2097 0, /* tp_repr */
2098 0, /* tp_as_number */
2098 0, /* tp_as_number */
2099 &index_sequence_methods, /* tp_as_sequence */
2099 &index_sequence_methods, /* tp_as_sequence */
2100 &index_mapping_methods, /* tp_as_mapping */
2100 &index_mapping_methods, /* tp_as_mapping */
2101 0, /* tp_hash */
2101 0, /* tp_hash */
2102 0, /* tp_call */
2102 0, /* tp_call */
2103 0, /* tp_str */
2103 0, /* tp_str */
2104 0, /* tp_getattro */
2104 0, /* tp_getattro */
2105 0, /* tp_setattro */
2105 0, /* tp_setattro */
2106 0, /* tp_as_buffer */
2106 0, /* tp_as_buffer */
2107 Py_TPFLAGS_DEFAULT, /* tp_flags */
2107 Py_TPFLAGS_DEFAULT, /* tp_flags */
2108 "revlog index", /* tp_doc */
2108 "revlog index", /* tp_doc */
2109 0, /* tp_traverse */
2109 0, /* tp_traverse */
2110 0, /* tp_clear */
2110 0, /* tp_clear */
2111 0, /* tp_richcompare */
2111 0, /* tp_richcompare */
2112 0, /* tp_weaklistoffset */
2112 0, /* tp_weaklistoffset */
2113 0, /* tp_iter */
2113 0, /* tp_iter */
2114 0, /* tp_iternext */
2114 0, /* tp_iternext */
2115 index_methods, /* tp_methods */
2115 index_methods, /* tp_methods */
2116 0, /* tp_members */
2116 0, /* tp_members */
2117 index_getset, /* tp_getset */
2117 index_getset, /* tp_getset */
2118 0, /* tp_base */
2118 0, /* tp_base */
2119 0, /* tp_dict */
2119 0, /* tp_dict */
2120 0, /* tp_descr_get */
2120 0, /* tp_descr_get */
2121 0, /* tp_descr_set */
2121 0, /* tp_descr_set */
2122 0, /* tp_dictoffset */
2122 0, /* tp_dictoffset */
2123 (initproc)index_init, /* tp_init */
2123 (initproc)index_init, /* tp_init */
2124 0, /* tp_alloc */
2124 0, /* tp_alloc */
2125 };
2125 };
2126
2126
2127 /*
2127 /*
2128 * returns a tuple of the form (index, index, cache) with elements as
2128 * returns a tuple of the form (index, index, cache) with elements as
2129 * follows:
2129 * follows:
2130 *
2130 *
2131 * index: an index object that lazily parses RevlogNG records
2131 * index: an index object that lazily parses RevlogNG records
2132 * cache: if data is inlined, a tuple (0, index_file_content), else None
2132 * cache: if data is inlined, a tuple (0, index_file_content), else None
2133 * index_file_content could be a string, or a buffer
2133 * index_file_content could be a string, or a buffer
2134 *
2134 *
2135 * added complications are for backwards compatibility
2135 * added complications are for backwards compatibility
2136 */
2136 */
2137 PyObject *parse_index2(PyObject *self, PyObject *args)
2137 PyObject *parse_index2(PyObject *self, PyObject *args)
2138 {
2138 {
2139 PyObject *tuple = NULL, *cache = NULL;
2139 PyObject *tuple = NULL, *cache = NULL;
2140 indexObject *idx;
2140 indexObject *idx;
2141 int ret;
2141 int ret;
2142
2142
2143 idx = PyObject_New(indexObject, &indexType);
2143 idx = PyObject_New(indexObject, &indexType);
2144 if (idx == NULL)
2144 if (idx == NULL)
2145 goto bail;
2145 goto bail;
2146
2146
2147 ret = index_init(idx, args);
2147 ret = index_init(idx, args);
2148 if (ret == -1)
2148 if (ret == -1)
2149 goto bail;
2149 goto bail;
2150
2150
2151 if (idx->inlined) {
2151 if (idx->inlined) {
2152 cache = Py_BuildValue("iO", 0, idx->data);
2152 cache = Py_BuildValue("iO", 0, idx->data);
2153 if (cache == NULL)
2153 if (cache == NULL)
2154 goto bail;
2154 goto bail;
2155 } else {
2155 } else {
2156 cache = Py_None;
2156 cache = Py_None;
2157 Py_INCREF(cache);
2157 Py_INCREF(cache);
2158 }
2158 }
2159
2159
2160 tuple = Py_BuildValue("NN", idx, cache);
2160 tuple = Py_BuildValue("NN", idx, cache);
2161 if (!tuple)
2161 if (!tuple)
2162 goto bail;
2162 goto bail;
2163 return tuple;
2163 return tuple;
2164
2164
2165 bail:
2165 bail:
2166 Py_XDECREF(idx);
2166 Py_XDECREF(idx);
2167 Py_XDECREF(cache);
2167 Py_XDECREF(cache);
2168 Py_XDECREF(tuple);
2168 Py_XDECREF(tuple);
2169 return NULL;
2169 return NULL;
2170 }
2170 }
2171
2171
2172 void revlog_module_init(PyObject *mod)
2172 void revlog_module_init(PyObject *mod)
2173 {
2173 {
2174 indexType.tp_new = PyType_GenericNew;
2174 indexType.tp_new = PyType_GenericNew;
2175 if (PyType_Ready(&indexType) < 0)
2175 if (PyType_Ready(&indexType) < 0)
2176 return;
2176 return;
2177 Py_INCREF(&indexType);
2177 Py_INCREF(&indexType);
2178 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2178 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2179
2179
2180 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0,
2180 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0,
2181 -1, -1, -1, -1, nullid, 20);
2181 -1, -1, -1, -1, nullid, 20);
2182 if (nullentry)
2182 if (nullentry)
2183 PyObject_GC_UnTrack(nullentry);
2183 PyObject_GC_UnTrack(nullentry);
2184 }
2184 }
@@ -1,179 +1,179
1 # parsers.py - Python implementation of parsers.c
1 # parsers.py - Python implementation of parsers.c
2 #
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import struct
10 import struct
11 import zlib
11 import zlib
12
12
13 from ..node import nullid
13 from ..node import nullid
14 from .. import pycompat
14 from .. import pycompat
15 stringio = pycompat.bytesio
15 stringio = pycompat.bytesio
16
16
17
17
18 _pack = struct.pack
18 _pack = struct.pack
19 _unpack = struct.unpack
19 _unpack = struct.unpack
20 _compress = zlib.compress
20 _compress = zlib.compress
21 _decompress = zlib.decompress
21 _decompress = zlib.decompress
22
22
23 # Some code below makes tuples directly because it's more convenient. However,
23 # Some code below makes tuples directly because it's more convenient. However,
24 # code outside this module should always use dirstatetuple.
24 # code outside this module should always use dirstatetuple.
25 def dirstatetuple(*x):
25 def dirstatetuple(*x):
26 # x is a tuple
26 # x is a tuple
27 return x
27 return x
28
28
29 indexformatng = ">Qiiiiii20s12x"
29 indexformatng = ">Qiiiiii20s12x"
30 indexfirst = struct.calcsize('Q')
30 indexfirst = struct.calcsize('Q')
31 sizeint = struct.calcsize('i')
31 sizeint = struct.calcsize('i')
32 indexsize = struct.calcsize(indexformatng)
32 indexsize = struct.calcsize(indexformatng)
33
33
34 def gettype(q):
34 def gettype(q):
35 return int(q & 0xFFFF)
35 return int(q & 0xFFFF)
36
36
37 def offset_type(offset, type):
37 def offset_type(offset, type):
38 return int(int(offset) << 16 | type)
38 return int(int(offset) << 16 | type)
39
39
40 class BaseIndexObject(object):
40 class BaseIndexObject(object):
41 def __len__(self):
41 def __len__(self):
42 return self._lgt + len(self._extra) + 1
42 return self._lgt + len(self._extra) + 1
43
43
44 def insert(self, i, tup):
44 def insert(self, i, tup):
45 assert i == -1
45 assert i == -1
46 self._extra.append(tup)
46 self._extra.append(tup)
47
47
48 def _fix_index(self, i):
48 def _fix_index(self, i):
49 if not isinstance(i, int):
49 if not isinstance(i, int):
50 raise TypeError("expecting int indexes")
50 raise TypeError("expecting int indexes")
51 if i < 0:
51 if i < 0:
52 i = len(self) + i
52 i = len(self) + i
53 if i < 0 or i >= len(self):
53 if i < 0 or i >= len(self):
54 raise IndexError
54 raise IndexError
55 return i
55 return i
56
56
57 def __getitem__(self, i):
57 def __getitem__(self, i):
58 if i == -1 or i == len(self) - 1:
59 return (0, 0, 0, -1, -1, -1, -1, nullid)
58 i = self._fix_index(i)
60 i = self._fix_index(i)
59 if i == len(self) - 1:
60 return (0, 0, 0, -1, -1, -1, -1, nullid)
61 if i >= self._lgt:
61 if i >= self._lgt:
62 return self._extra[i - self._lgt]
62 return self._extra[i - self._lgt]
63 index = self._calculate_index(i)
63 index = self._calculate_index(i)
64 r = struct.unpack(indexformatng, self._data[index:index + indexsize])
64 r = struct.unpack(indexformatng, self._data[index:index + indexsize])
65 if i == 0:
65 if i == 0:
66 e = list(r)
66 e = list(r)
67 type = gettype(e[0])
67 type = gettype(e[0])
68 e[0] = offset_type(0, type)
68 e[0] = offset_type(0, type)
69 return tuple(e)
69 return tuple(e)
70 return r
70 return r
71
71
72 class IndexObject(BaseIndexObject):
72 class IndexObject(BaseIndexObject):
73 def __init__(self, data):
73 def __init__(self, data):
74 assert len(data) % indexsize == 0
74 assert len(data) % indexsize == 0
75 self._data = data
75 self._data = data
76 self._lgt = len(data) // indexsize
76 self._lgt = len(data) // indexsize
77 self._extra = []
77 self._extra = []
78
78
79 def _calculate_index(self, i):
79 def _calculate_index(self, i):
80 return i * indexsize
80 return i * indexsize
81
81
82 def __delitem__(self, i):
82 def __delitem__(self, i):
83 if not isinstance(i, slice) or not i.stop == -1 or i.step is not None:
83 if not isinstance(i, slice) or not i.stop == -1 or i.step is not None:
84 raise ValueError("deleting slices only supports a:-1 with step 1")
84 raise ValueError("deleting slices only supports a:-1 with step 1")
85 i = self._fix_index(i.start)
85 i = self._fix_index(i.start)
86 if i < self._lgt:
86 if i < self._lgt:
87 self._data = self._data[:i * indexsize]
87 self._data = self._data[:i * indexsize]
88 self._lgt = i
88 self._lgt = i
89 self._extra = []
89 self._extra = []
90 else:
90 else:
91 self._extra = self._extra[:i - self._lgt]
91 self._extra = self._extra[:i - self._lgt]
92
92
93 class InlinedIndexObject(BaseIndexObject):
93 class InlinedIndexObject(BaseIndexObject):
94 def __init__(self, data, inline=0):
94 def __init__(self, data, inline=0):
95 self._data = data
95 self._data = data
96 self._lgt = self._inline_scan(None)
96 self._lgt = self._inline_scan(None)
97 self._inline_scan(self._lgt)
97 self._inline_scan(self._lgt)
98 self._extra = []
98 self._extra = []
99
99
100 def _inline_scan(self, lgt):
100 def _inline_scan(self, lgt):
101 off = 0
101 off = 0
102 if lgt is not None:
102 if lgt is not None:
103 self._offsets = [0] * lgt
103 self._offsets = [0] * lgt
104 count = 0
104 count = 0
105 while off <= len(self._data) - indexsize:
105 while off <= len(self._data) - indexsize:
106 s, = struct.unpack('>i',
106 s, = struct.unpack('>i',
107 self._data[off + indexfirst:off + sizeint + indexfirst])
107 self._data[off + indexfirst:off + sizeint + indexfirst])
108 if lgt is not None:
108 if lgt is not None:
109 self._offsets[count] = off
109 self._offsets[count] = off
110 count += 1
110 count += 1
111 off += indexsize + s
111 off += indexsize + s
112 if off != len(self._data):
112 if off != len(self._data):
113 raise ValueError("corrupted data")
113 raise ValueError("corrupted data")
114 return count
114 return count
115
115
116 def __delitem__(self, i):
116 def __delitem__(self, i):
117 if not isinstance(i, slice) or not i.stop == -1 or i.step is not None:
117 if not isinstance(i, slice) or not i.stop == -1 or i.step is not None:
118 raise ValueError("deleting slices only supports a:-1 with step 1")
118 raise ValueError("deleting slices only supports a:-1 with step 1")
119 i = self._fix_index(i.start)
119 i = self._fix_index(i.start)
120 if i < self._lgt:
120 if i < self._lgt:
121 self._offsets = self._offsets[:i]
121 self._offsets = self._offsets[:i]
122 self._lgt = i
122 self._lgt = i
123 self._extra = []
123 self._extra = []
124 else:
124 else:
125 self._extra = self._extra[:i - self._lgt]
125 self._extra = self._extra[:i - self._lgt]
126
126
127 def _calculate_index(self, i):
127 def _calculate_index(self, i):
128 return self._offsets[i]
128 return self._offsets[i]
129
129
130 def parse_index2(data, inline):
130 def parse_index2(data, inline):
131 if not inline:
131 if not inline:
132 return IndexObject(data), None
132 return IndexObject(data), None
133 return InlinedIndexObject(data, inline), (0, data)
133 return InlinedIndexObject(data, inline), (0, data)
134
134
135 def parse_dirstate(dmap, copymap, st):
135 def parse_dirstate(dmap, copymap, st):
136 parents = [st[:20], st[20: 40]]
136 parents = [st[:20], st[20: 40]]
137 # dereference fields so they will be local in loop
137 # dereference fields so they will be local in loop
138 format = ">cllll"
138 format = ">cllll"
139 e_size = struct.calcsize(format)
139 e_size = struct.calcsize(format)
140 pos1 = 40
140 pos1 = 40
141 l = len(st)
141 l = len(st)
142
142
143 # the inner loop
143 # the inner loop
144 while pos1 < l:
144 while pos1 < l:
145 pos2 = pos1 + e_size
145 pos2 = pos1 + e_size
146 e = _unpack(">cllll", st[pos1:pos2]) # a literal here is faster
146 e = _unpack(">cllll", st[pos1:pos2]) # a literal here is faster
147 pos1 = pos2 + e[4]
147 pos1 = pos2 + e[4]
148 f = st[pos2:pos1]
148 f = st[pos2:pos1]
149 if '\0' in f:
149 if '\0' in f:
150 f, c = f.split('\0')
150 f, c = f.split('\0')
151 copymap[f] = c
151 copymap[f] = c
152 dmap[f] = e[:4]
152 dmap[f] = e[:4]
153 return parents
153 return parents
154
154
155 def pack_dirstate(dmap, copymap, pl, now):
155 def pack_dirstate(dmap, copymap, pl, now):
156 now = int(now)
156 now = int(now)
157 cs = stringio()
157 cs = stringio()
158 write = cs.write
158 write = cs.write
159 write("".join(pl))
159 write("".join(pl))
160 for f, e in dmap.iteritems():
160 for f, e in dmap.iteritems():
161 if e[0] == 'n' and e[3] == now:
161 if e[0] == 'n' and e[3] == now:
162 # The file was last modified "simultaneously" with the current
162 # The file was last modified "simultaneously" with the current
163 # write to dirstate (i.e. within the same second for file-
163 # write to dirstate (i.e. within the same second for file-
164 # systems with a granularity of 1 sec). This commonly happens
164 # systems with a granularity of 1 sec). This commonly happens
165 # for at least a couple of files on 'update'.
165 # for at least a couple of files on 'update'.
166 # The user could change the file without changing its size
166 # The user could change the file without changing its size
167 # within the same second. Invalidate the file's mtime in
167 # within the same second. Invalidate the file's mtime in
168 # dirstate, forcing future 'status' calls to compare the
168 # dirstate, forcing future 'status' calls to compare the
169 # contents of the file if the size is the same. This prevents
169 # contents of the file if the size is the same. This prevents
170 # mistakenly treating such files as clean.
170 # mistakenly treating such files as clean.
171 e = dirstatetuple(e[0], e[1], e[2], -1)
171 e = dirstatetuple(e[0], e[1], e[2], -1)
172 dmap[f] = e
172 dmap[f] = e
173
173
174 if f in copymap:
174 if f in copymap:
175 f = "%s\0%s" % (f, copymap[f])
175 f = "%s\0%s" % (f, copymap[f])
176 e = _pack(">cllll", e[0], e[1], e[2], e[3], len(f))
176 e = _pack(">cllll", e[0], e[1], e[2], e[3], len(f))
177 write(e)
177 write(e)
178 write(f)
178 write(f)
179 return cs.getvalue()
179 return cs.getvalue()
General Comments 0
You need to be logged in to leave comments. Login now