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