##// END OF EJS Templates
obsolete: use C code for headrevs calculation...
Durham Goode -
r22484:2b5940f6 default
parent child Browse files
Show More
@@ -1,352 +1,357 b''
1 # changelog.py - changelog class for mercurial
1 # changelog.py - changelog class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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 node import bin, hex, nullid
8 from node import bin, hex, nullid
9 from i18n import _
9 from i18n import _
10 import util, error, revlog, encoding
10 import util, error, revlog, encoding
11
11
12 _defaultextra = {'branch': 'default'}
12 _defaultextra = {'branch': 'default'}
13
13
14 def _string_escape(text):
14 def _string_escape(text):
15 """
15 """
16 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
16 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
17 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
17 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
18 >>> s
18 >>> s
19 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
19 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
20 >>> res = _string_escape(s)
20 >>> res = _string_escape(s)
21 >>> s == res.decode('string_escape')
21 >>> s == res.decode('string_escape')
22 True
22 True
23 """
23 """
24 # subset of the string_escape codec
24 # subset of the string_escape codec
25 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
25 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
26 return text.replace('\0', '\\0')
26 return text.replace('\0', '\\0')
27
27
28 def decodeextra(text):
28 def decodeextra(text):
29 """
29 """
30 >>> sorted(decodeextra(encodeextra({'foo': 'bar', 'baz': chr(0) + '2'})
30 >>> sorted(decodeextra(encodeextra({'foo': 'bar', 'baz': chr(0) + '2'})
31 ... ).iteritems())
31 ... ).iteritems())
32 [('baz', '\\x002'), ('branch', 'default'), ('foo', 'bar')]
32 [('baz', '\\x002'), ('branch', 'default'), ('foo', 'bar')]
33 >>> sorted(decodeextra(encodeextra({'foo': 'bar',
33 >>> sorted(decodeextra(encodeextra({'foo': 'bar',
34 ... 'baz': chr(92) + chr(0) + '2'})
34 ... 'baz': chr(92) + chr(0) + '2'})
35 ... ).iteritems())
35 ... ).iteritems())
36 [('baz', '\\\\\\x002'), ('branch', 'default'), ('foo', 'bar')]
36 [('baz', '\\\\\\x002'), ('branch', 'default'), ('foo', 'bar')]
37 """
37 """
38 extra = _defaultextra.copy()
38 extra = _defaultextra.copy()
39 for l in text.split('\0'):
39 for l in text.split('\0'):
40 if l:
40 if l:
41 if '\\0' in l:
41 if '\\0' in l:
42 # fix up \0 without getting into trouble with \\0
42 # fix up \0 without getting into trouble with \\0
43 l = l.replace('\\\\', '\\\\\n')
43 l = l.replace('\\\\', '\\\\\n')
44 l = l.replace('\\0', '\0')
44 l = l.replace('\\0', '\0')
45 l = l.replace('\n', '')
45 l = l.replace('\n', '')
46 k, v = l.decode('string_escape').split(':', 1)
46 k, v = l.decode('string_escape').split(':', 1)
47 extra[k] = v
47 extra[k] = v
48 return extra
48 return extra
49
49
50 def encodeextra(d):
50 def encodeextra(d):
51 # keys must be sorted to produce a deterministic changelog entry
51 # keys must be sorted to produce a deterministic changelog entry
52 items = [_string_escape('%s:%s' % (k, d[k])) for k in sorted(d)]
52 items = [_string_escape('%s:%s' % (k, d[k])) for k in sorted(d)]
53 return "\0".join(items)
53 return "\0".join(items)
54
54
55 def stripdesc(desc):
55 def stripdesc(desc):
56 """strip trailing whitespace and leading and trailing empty lines"""
56 """strip trailing whitespace and leading and trailing empty lines"""
57 return '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
57 return '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
58
58
59 class appender(object):
59 class appender(object):
60 '''the changelog index must be updated last on disk, so we use this class
60 '''the changelog index must be updated last on disk, so we use this class
61 to delay writes to it'''
61 to delay writes to it'''
62 def __init__(self, vfs, name, mode, buf):
62 def __init__(self, vfs, name, mode, buf):
63 self.data = buf
63 self.data = buf
64 fp = vfs(name, mode)
64 fp = vfs(name, mode)
65 self.fp = fp
65 self.fp = fp
66 self.offset = fp.tell()
66 self.offset = fp.tell()
67 self.size = vfs.fstat(fp).st_size
67 self.size = vfs.fstat(fp).st_size
68
68
69 def end(self):
69 def end(self):
70 return self.size + len("".join(self.data))
70 return self.size + len("".join(self.data))
71 def tell(self):
71 def tell(self):
72 return self.offset
72 return self.offset
73 def flush(self):
73 def flush(self):
74 pass
74 pass
75 def close(self):
75 def close(self):
76 self.fp.close()
76 self.fp.close()
77
77
78 def seek(self, offset, whence=0):
78 def seek(self, offset, whence=0):
79 '''virtual file offset spans real file and data'''
79 '''virtual file offset spans real file and data'''
80 if whence == 0:
80 if whence == 0:
81 self.offset = offset
81 self.offset = offset
82 elif whence == 1:
82 elif whence == 1:
83 self.offset += offset
83 self.offset += offset
84 elif whence == 2:
84 elif whence == 2:
85 self.offset = self.end() + offset
85 self.offset = self.end() + offset
86 if self.offset < self.size:
86 if self.offset < self.size:
87 self.fp.seek(self.offset)
87 self.fp.seek(self.offset)
88
88
89 def read(self, count=-1):
89 def read(self, count=-1):
90 '''only trick here is reads that span real file and data'''
90 '''only trick here is reads that span real file and data'''
91 ret = ""
91 ret = ""
92 if self.offset < self.size:
92 if self.offset < self.size:
93 s = self.fp.read(count)
93 s = self.fp.read(count)
94 ret = s
94 ret = s
95 self.offset += len(s)
95 self.offset += len(s)
96 if count > 0:
96 if count > 0:
97 count -= len(s)
97 count -= len(s)
98 if count != 0:
98 if count != 0:
99 doff = self.offset - self.size
99 doff = self.offset - self.size
100 self.data.insert(0, "".join(self.data))
100 self.data.insert(0, "".join(self.data))
101 del self.data[1:]
101 del self.data[1:]
102 s = self.data[0][doff:doff + count]
102 s = self.data[0][doff:doff + count]
103 self.offset += len(s)
103 self.offset += len(s)
104 ret += s
104 ret += s
105 return ret
105 return ret
106
106
107 def write(self, s):
107 def write(self, s):
108 self.data.append(str(s))
108 self.data.append(str(s))
109 self.offset += len(s)
109 self.offset += len(s)
110
110
111 def delayopener(opener, target, divert, buf):
111 def delayopener(opener, target, divert, buf):
112 def o(name, mode='r'):
112 def o(name, mode='r'):
113 if name != target:
113 if name != target:
114 return opener(name, mode)
114 return opener(name, mode)
115 if divert:
115 if divert:
116 return opener(name + ".a", mode.replace('a', 'w'))
116 return opener(name + ".a", mode.replace('a', 'w'))
117 # otherwise, divert to memory
117 # otherwise, divert to memory
118 return appender(opener, name, mode, buf)
118 return appender(opener, name, mode, buf)
119 return o
119 return o
120
120
121 class changelog(revlog.revlog):
121 class changelog(revlog.revlog):
122 def __init__(self, opener):
122 def __init__(self, opener):
123 revlog.revlog.__init__(self, opener, "00changelog.i")
123 revlog.revlog.__init__(self, opener, "00changelog.i")
124 if self._initempty:
124 if self._initempty:
125 # changelogs don't benefit from generaldelta
125 # changelogs don't benefit from generaldelta
126 self.version &= ~revlog.REVLOGGENERALDELTA
126 self.version &= ~revlog.REVLOGGENERALDELTA
127 self._generaldelta = False
127 self._generaldelta = False
128 self._realopener = opener
128 self._realopener = opener
129 self._delayed = False
129 self._delayed = False
130 self._delaybuf = []
130 self._delaybuf = []
131 self._divert = False
131 self._divert = False
132 self.filteredrevs = frozenset()
132 self.filteredrevs = frozenset()
133
133
134 def tip(self):
134 def tip(self):
135 """filtered version of revlog.tip"""
135 """filtered version of revlog.tip"""
136 for i in xrange(len(self) -1, -2, -1):
136 for i in xrange(len(self) -1, -2, -1):
137 if i not in self.filteredrevs:
137 if i not in self.filteredrevs:
138 return self.node(i)
138 return self.node(i)
139
139
140 def __iter__(self):
140 def __iter__(self):
141 """filtered version of revlog.__iter__"""
141 """filtered version of revlog.__iter__"""
142 if len(self.filteredrevs) == 0:
142 if len(self.filteredrevs) == 0:
143 return revlog.revlog.__iter__(self)
143 return revlog.revlog.__iter__(self)
144
144
145 def filterediter():
145 def filterediter():
146 for i in xrange(len(self)):
146 for i in xrange(len(self)):
147 if i not in self.filteredrevs:
147 if i not in self.filteredrevs:
148 yield i
148 yield i
149
149
150 return filterediter()
150 return filterediter()
151
151
152 def revs(self, start=0, stop=None):
152 def revs(self, start=0, stop=None):
153 """filtered version of revlog.revs"""
153 """filtered version of revlog.revs"""
154 for i in super(changelog, self).revs(start, stop):
154 for i in super(changelog, self).revs(start, stop):
155 if i not in self.filteredrevs:
155 if i not in self.filteredrevs:
156 yield i
156 yield i
157
157
158 @util.propertycache
158 @util.propertycache
159 def nodemap(self):
159 def nodemap(self):
160 # XXX need filtering too
160 # XXX need filtering too
161 self.rev(self.node(0))
161 self.rev(self.node(0))
162 return self._nodecache
162 return self._nodecache
163
163
164 def hasnode(self, node):
164 def hasnode(self, node):
165 """filtered version of revlog.hasnode"""
165 """filtered version of revlog.hasnode"""
166 try:
166 try:
167 i = self.rev(node)
167 i = self.rev(node)
168 return i not in self.filteredrevs
168 return i not in self.filteredrevs
169 except KeyError:
169 except KeyError:
170 return False
170 return False
171
171
172 def headrevs(self):
172 def headrevs(self):
173 if self.filteredrevs:
173 if self.filteredrevs:
174 # XXX we should fix and use the C version
174 try:
175 return self.index.headrevs(self.filteredrevs)
176 # AttributeError covers non-c-extension environments.
177 # TypeError allows us work with old c extensions.
178 except (AttributeError, TypeError):
175 return self._headrevs()
179 return self._headrevs()
180
176 return super(changelog, self).headrevs()
181 return super(changelog, self).headrevs()
177
182
178 def strip(self, *args, **kwargs):
183 def strip(self, *args, **kwargs):
179 # XXX make something better than assert
184 # XXX make something better than assert
180 # We can't expect proper strip behavior if we are filtered.
185 # We can't expect proper strip behavior if we are filtered.
181 assert not self.filteredrevs
186 assert not self.filteredrevs
182 super(changelog, self).strip(*args, **kwargs)
187 super(changelog, self).strip(*args, **kwargs)
183
188
184 def rev(self, node):
189 def rev(self, node):
185 """filtered version of revlog.rev"""
190 """filtered version of revlog.rev"""
186 r = super(changelog, self).rev(node)
191 r = super(changelog, self).rev(node)
187 if r in self.filteredrevs:
192 if r in self.filteredrevs:
188 raise error.LookupError(hex(node), self.indexfile, _('no node'))
193 raise error.LookupError(hex(node), self.indexfile, _('no node'))
189 return r
194 return r
190
195
191 def node(self, rev):
196 def node(self, rev):
192 """filtered version of revlog.node"""
197 """filtered version of revlog.node"""
193 if rev in self.filteredrevs:
198 if rev in self.filteredrevs:
194 raise IndexError(rev)
199 raise IndexError(rev)
195 return super(changelog, self).node(rev)
200 return super(changelog, self).node(rev)
196
201
197 def linkrev(self, rev):
202 def linkrev(self, rev):
198 """filtered version of revlog.linkrev"""
203 """filtered version of revlog.linkrev"""
199 if rev in self.filteredrevs:
204 if rev in self.filteredrevs:
200 raise IndexError(rev)
205 raise IndexError(rev)
201 return super(changelog, self).linkrev(rev)
206 return super(changelog, self).linkrev(rev)
202
207
203 def parentrevs(self, rev):
208 def parentrevs(self, rev):
204 """filtered version of revlog.parentrevs"""
209 """filtered version of revlog.parentrevs"""
205 if rev in self.filteredrevs:
210 if rev in self.filteredrevs:
206 raise IndexError(rev)
211 raise IndexError(rev)
207 return super(changelog, self).parentrevs(rev)
212 return super(changelog, self).parentrevs(rev)
208
213
209 def flags(self, rev):
214 def flags(self, rev):
210 """filtered version of revlog.flags"""
215 """filtered version of revlog.flags"""
211 if rev in self.filteredrevs:
216 if rev in self.filteredrevs:
212 raise IndexError(rev)
217 raise IndexError(rev)
213 return super(changelog, self).flags(rev)
218 return super(changelog, self).flags(rev)
214
219
215 def delayupdate(self):
220 def delayupdate(self):
216 "delay visibility of index updates to other readers"
221 "delay visibility of index updates to other readers"
217 self._delayed = True
222 self._delayed = True
218 self._divert = (len(self) == 0)
223 self._divert = (len(self) == 0)
219 self._delaybuf = []
224 self._delaybuf = []
220 self.opener = delayopener(self._realopener, self.indexfile,
225 self.opener = delayopener(self._realopener, self.indexfile,
221 self._divert, self._delaybuf)
226 self._divert, self._delaybuf)
222
227
223 def finalize(self, tr):
228 def finalize(self, tr):
224 "finalize index updates"
229 "finalize index updates"
225 self._delayed = False
230 self._delayed = False
226 self.opener = self._realopener
231 self.opener = self._realopener
227 # move redirected index data back into place
232 # move redirected index data back into place
228 if self._divert:
233 if self._divert:
229 tmpname = self.indexfile + ".a"
234 tmpname = self.indexfile + ".a"
230 nfile = self.opener.open(tmpname)
235 nfile = self.opener.open(tmpname)
231 nfile.close()
236 nfile.close()
232 self.opener.rename(tmpname, self.indexfile)
237 self.opener.rename(tmpname, self.indexfile)
233 elif self._delaybuf:
238 elif self._delaybuf:
234 fp = self.opener(self.indexfile, 'a')
239 fp = self.opener(self.indexfile, 'a')
235 fp.write("".join(self._delaybuf))
240 fp.write("".join(self._delaybuf))
236 fp.close()
241 fp.close()
237 self._delaybuf = []
242 self._delaybuf = []
238 # split when we're done
243 # split when we're done
239 self.checkinlinesize(tr)
244 self.checkinlinesize(tr)
240
245
241 def readpending(self, file):
246 def readpending(self, file):
242 r = revlog.revlog(self.opener, file)
247 r = revlog.revlog(self.opener, file)
243 self.index = r.index
248 self.index = r.index
244 self.nodemap = r.nodemap
249 self.nodemap = r.nodemap
245 self._nodecache = r._nodecache
250 self._nodecache = r._nodecache
246 self._chunkcache = r._chunkcache
251 self._chunkcache = r._chunkcache
247
252
248 def writepending(self):
253 def writepending(self):
249 "create a file containing the unfinalized state for pretxnchangegroup"
254 "create a file containing the unfinalized state for pretxnchangegroup"
250 if self._delaybuf:
255 if self._delaybuf:
251 # make a temporary copy of the index
256 # make a temporary copy of the index
252 fp1 = self._realopener(self.indexfile)
257 fp1 = self._realopener(self.indexfile)
253 fp2 = self._realopener(self.indexfile + ".a", "w")
258 fp2 = self._realopener(self.indexfile + ".a", "w")
254 fp2.write(fp1.read())
259 fp2.write(fp1.read())
255 # add pending data
260 # add pending data
256 fp2.write("".join(self._delaybuf))
261 fp2.write("".join(self._delaybuf))
257 fp2.close()
262 fp2.close()
258 # switch modes so finalize can simply rename
263 # switch modes so finalize can simply rename
259 self._delaybuf = []
264 self._delaybuf = []
260 self._divert = True
265 self._divert = True
261
266
262 if self._divert:
267 if self._divert:
263 return True
268 return True
264
269
265 return False
270 return False
266
271
267 def checkinlinesize(self, tr, fp=None):
272 def checkinlinesize(self, tr, fp=None):
268 if not self._delayed:
273 if not self._delayed:
269 revlog.revlog.checkinlinesize(self, tr, fp)
274 revlog.revlog.checkinlinesize(self, tr, fp)
270
275
271 def read(self, node):
276 def read(self, node):
272 """
277 """
273 format used:
278 format used:
274 nodeid\n : manifest node in ascii
279 nodeid\n : manifest node in ascii
275 user\n : user, no \n or \r allowed
280 user\n : user, no \n or \r allowed
276 time tz extra\n : date (time is int or float, timezone is int)
281 time tz extra\n : date (time is int or float, timezone is int)
277 : extra is metadata, encoded and separated by '\0'
282 : extra is metadata, encoded and separated by '\0'
278 : older versions ignore it
283 : older versions ignore it
279 files\n\n : files modified by the cset, no \n or \r allowed
284 files\n\n : files modified by the cset, no \n or \r allowed
280 (.*) : comment (free text, ideally utf-8)
285 (.*) : comment (free text, ideally utf-8)
281
286
282 changelog v0 doesn't use extra
287 changelog v0 doesn't use extra
283 """
288 """
284 text = self.revision(node)
289 text = self.revision(node)
285 if not text:
290 if not text:
286 return (nullid, "", (0, 0), [], "", _defaultextra)
291 return (nullid, "", (0, 0), [], "", _defaultextra)
287 last = text.index("\n\n")
292 last = text.index("\n\n")
288 desc = encoding.tolocal(text[last + 2:])
293 desc = encoding.tolocal(text[last + 2:])
289 l = text[:last].split('\n')
294 l = text[:last].split('\n')
290 manifest = bin(l[0])
295 manifest = bin(l[0])
291 user = encoding.tolocal(l[1])
296 user = encoding.tolocal(l[1])
292
297
293 tdata = l[2].split(' ', 2)
298 tdata = l[2].split(' ', 2)
294 if len(tdata) != 3:
299 if len(tdata) != 3:
295 time = float(tdata[0])
300 time = float(tdata[0])
296 try:
301 try:
297 # various tools did silly things with the time zone field.
302 # various tools did silly things with the time zone field.
298 timezone = int(tdata[1])
303 timezone = int(tdata[1])
299 except ValueError:
304 except ValueError:
300 timezone = 0
305 timezone = 0
301 extra = _defaultextra
306 extra = _defaultextra
302 else:
307 else:
303 time, timezone = float(tdata[0]), int(tdata[1])
308 time, timezone = float(tdata[0]), int(tdata[1])
304 extra = decodeextra(tdata[2])
309 extra = decodeextra(tdata[2])
305
310
306 files = l[3:]
311 files = l[3:]
307 return (manifest, user, (time, timezone), files, desc, extra)
312 return (manifest, user, (time, timezone), files, desc, extra)
308
313
309 def add(self, manifest, files, desc, transaction, p1, p2,
314 def add(self, manifest, files, desc, transaction, p1, p2,
310 user, date=None, extra=None):
315 user, date=None, extra=None):
311 # Convert to UTF-8 encoded bytestrings as the very first
316 # Convert to UTF-8 encoded bytestrings as the very first
312 # thing: calling any method on a localstr object will turn it
317 # thing: calling any method on a localstr object will turn it
313 # into a str object and the cached UTF-8 string is thus lost.
318 # into a str object and the cached UTF-8 string is thus lost.
314 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
319 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
315
320
316 user = user.strip()
321 user = user.strip()
317 # An empty username or a username with a "\n" will make the
322 # An empty username or a username with a "\n" will make the
318 # revision text contain two "\n\n" sequences -> corrupt
323 # revision text contain two "\n\n" sequences -> corrupt
319 # repository since read cannot unpack the revision.
324 # repository since read cannot unpack the revision.
320 if not user:
325 if not user:
321 raise error.RevlogError(_("empty username"))
326 raise error.RevlogError(_("empty username"))
322 if "\n" in user:
327 if "\n" in user:
323 raise error.RevlogError(_("username %s contains a newline")
328 raise error.RevlogError(_("username %s contains a newline")
324 % repr(user))
329 % repr(user))
325
330
326 desc = stripdesc(desc)
331 desc = stripdesc(desc)
327
332
328 if date:
333 if date:
329 parseddate = "%d %d" % util.parsedate(date)
334 parseddate = "%d %d" % util.parsedate(date)
330 else:
335 else:
331 parseddate = "%d %d" % util.makedate()
336 parseddate = "%d %d" % util.makedate()
332 if extra:
337 if extra:
333 branch = extra.get("branch")
338 branch = extra.get("branch")
334 if branch in ("default", ""):
339 if branch in ("default", ""):
335 del extra["branch"]
340 del extra["branch"]
336 elif branch in (".", "null", "tip"):
341 elif branch in (".", "null", "tip"):
337 raise error.RevlogError(_('the name \'%s\' is reserved')
342 raise error.RevlogError(_('the name \'%s\' is reserved')
338 % branch)
343 % branch)
339 if extra:
344 if extra:
340 extra = encodeextra(extra)
345 extra = encodeextra(extra)
341 parseddate = "%s %s" % (parseddate, extra)
346 parseddate = "%s %s" % (parseddate, extra)
342 l = [hex(manifest), user, parseddate] + sorted(files) + ["", desc]
347 l = [hex(manifest), user, parseddate] + sorted(files) + ["", desc]
343 text = "\n".join(l)
348 text = "\n".join(l)
344 return self.addrevision(text, transaction, len(self), p1, p2)
349 return self.addrevision(text, transaction, len(self), p1, p2)
345
350
346 def branchinfo(self, rev):
351 def branchinfo(self, rev):
347 """return the branch name and open/close state of a revision
352 """return the branch name and open/close state of a revision
348
353
349 This function exists because creating a changectx object
354 This function exists because creating a changectx object
350 just to access this is costly."""
355 just to access this is costly."""
351 extra = self.read(rev)[5]
356 extra = self.read(rev)[5]
352 return encoding.tolocal(extra.get("branch")), 'close' in extra
357 return encoding.tolocal(extra.get("branch")), 'close' in extra
@@ -1,2177 +1,2258 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 <ctype.h>
11 #include <ctype.h>
12 #include <stddef.h>
12 #include <stddef.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "util.h"
15 #include "util.h"
16
16
17 static char *versionerrortext = "Python minor version mismatch";
17 static char *versionerrortext = "Python minor version mismatch";
18
18
19 static int8_t hextable[256] = {
19 static int8_t hextable[256] = {
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 };
36 };
37
37
38 static inline int hexdigit(const char *p, Py_ssize_t off)
38 static inline int hexdigit(const char *p, Py_ssize_t off)
39 {
39 {
40 int8_t val = hextable[(unsigned char)p[off]];
40 int8_t val = hextable[(unsigned char)p[off]];
41
41
42 if (val >= 0) {
42 if (val >= 0) {
43 return val;
43 return val;
44 }
44 }
45
45
46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
47 return 0;
47 return 0;
48 }
48 }
49
49
50 /*
50 /*
51 * Turn a hex-encoded string into binary.
51 * Turn a hex-encoded string into binary.
52 */
52 */
53 static PyObject *unhexlify(const char *str, int len)
53 static PyObject *unhexlify(const char *str, int len)
54 {
54 {
55 PyObject *ret;
55 PyObject *ret;
56 char *d;
56 char *d;
57 int i;
57 int i;
58
58
59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
60
60
61 if (!ret)
61 if (!ret)
62 return NULL;
62 return NULL;
63
63
64 d = PyBytes_AsString(ret);
64 d = PyBytes_AsString(ret);
65
65
66 for (i = 0; i < len;) {
66 for (i = 0; i < len;) {
67 int hi = hexdigit(str, i++);
67 int hi = hexdigit(str, i++);
68 int lo = hexdigit(str, i++);
68 int lo = hexdigit(str, i++);
69 *d++ = (hi << 4) | lo;
69 *d++ = (hi << 4) | lo;
70 }
70 }
71
71
72 return ret;
72 return ret;
73 }
73 }
74
74
75 /*
75 /*
76 * This code assumes that a manifest is stitched together with newline
76 * This code assumes that a manifest is stitched together with newline
77 * ('\n') characters.
77 * ('\n') characters.
78 */
78 */
79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
80 {
80 {
81 PyObject *mfdict, *fdict;
81 PyObject *mfdict, *fdict;
82 char *str, *start, *end;
82 char *str, *start, *end;
83 int len;
83 int len;
84
84
85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
86 &PyDict_Type, &mfdict,
86 &PyDict_Type, &mfdict,
87 &PyDict_Type, &fdict,
87 &PyDict_Type, &fdict,
88 &str, &len))
88 &str, &len))
89 goto quit;
89 goto quit;
90
90
91 start = str;
91 start = str;
92 end = str + len;
92 end = str + len;
93 while (start < end) {
93 while (start < end) {
94 PyObject *file = NULL, *node = NULL;
94 PyObject *file = NULL, *node = NULL;
95 PyObject *flags = NULL;
95 PyObject *flags = NULL;
96 char *zero = NULL, *newline = NULL;
96 char *zero = NULL, *newline = NULL;
97 ptrdiff_t nlen;
97 ptrdiff_t nlen;
98
98
99 zero = memchr(start, '\0', end - start);
99 zero = memchr(start, '\0', end - start);
100 if (!zero) {
100 if (!zero) {
101 PyErr_SetString(PyExc_ValueError,
101 PyErr_SetString(PyExc_ValueError,
102 "manifest entry has no separator");
102 "manifest entry has no separator");
103 goto quit;
103 goto quit;
104 }
104 }
105
105
106 newline = memchr(zero + 1, '\n', end - (zero + 1));
106 newline = memchr(zero + 1, '\n', end - (zero + 1));
107 if (!newline) {
107 if (!newline) {
108 PyErr_SetString(PyExc_ValueError,
108 PyErr_SetString(PyExc_ValueError,
109 "manifest contains trailing garbage");
109 "manifest contains trailing garbage");
110 goto quit;
110 goto quit;
111 }
111 }
112
112
113 file = PyBytes_FromStringAndSize(start, zero - start);
113 file = PyBytes_FromStringAndSize(start, zero - start);
114
114
115 if (!file)
115 if (!file)
116 goto bail;
116 goto bail;
117
117
118 nlen = newline - zero - 1;
118 nlen = newline - zero - 1;
119
119
120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
121 if (!node)
121 if (!node)
122 goto bail;
122 goto bail;
123
123
124 if (nlen > 40) {
124 if (nlen > 40) {
125 flags = PyBytes_FromStringAndSize(zero + 41,
125 flags = PyBytes_FromStringAndSize(zero + 41,
126 nlen - 40);
126 nlen - 40);
127 if (!flags)
127 if (!flags)
128 goto bail;
128 goto bail;
129
129
130 if (PyDict_SetItem(fdict, file, flags) == -1)
130 if (PyDict_SetItem(fdict, file, flags) == -1)
131 goto bail;
131 goto bail;
132 }
132 }
133
133
134 if (PyDict_SetItem(mfdict, file, node) == -1)
134 if (PyDict_SetItem(mfdict, file, node) == -1)
135 goto bail;
135 goto bail;
136
136
137 start = newline + 1;
137 start = newline + 1;
138
138
139 Py_XDECREF(flags);
139 Py_XDECREF(flags);
140 Py_XDECREF(node);
140 Py_XDECREF(node);
141 Py_XDECREF(file);
141 Py_XDECREF(file);
142 continue;
142 continue;
143 bail:
143 bail:
144 Py_XDECREF(flags);
144 Py_XDECREF(flags);
145 Py_XDECREF(node);
145 Py_XDECREF(node);
146 Py_XDECREF(file);
146 Py_XDECREF(file);
147 goto quit;
147 goto quit;
148 }
148 }
149
149
150 Py_INCREF(Py_None);
150 Py_INCREF(Py_None);
151 return Py_None;
151 return Py_None;
152 quit:
152 quit:
153 return NULL;
153 return NULL;
154 }
154 }
155
155
156 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
156 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
157 int size, int mtime)
157 int size, int mtime)
158 {
158 {
159 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
159 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
160 &dirstateTupleType);
160 &dirstateTupleType);
161 if (!t)
161 if (!t)
162 return NULL;
162 return NULL;
163 t->state = state;
163 t->state = state;
164 t->mode = mode;
164 t->mode = mode;
165 t->size = size;
165 t->size = size;
166 t->mtime = mtime;
166 t->mtime = mtime;
167 return t;
167 return t;
168 }
168 }
169
169
170 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
170 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
171 PyObject *kwds)
171 PyObject *kwds)
172 {
172 {
173 /* We do all the initialization here and not a tp_init function because
173 /* We do all the initialization here and not a tp_init function because
174 * dirstate_tuple is immutable. */
174 * dirstate_tuple is immutable. */
175 dirstateTupleObject *t;
175 dirstateTupleObject *t;
176 char state;
176 char state;
177 int size, mode, mtime;
177 int size, mode, mtime;
178 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
178 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
179 return NULL;
179 return NULL;
180
180
181 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
181 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
182 if (!t)
182 if (!t)
183 return NULL;
183 return NULL;
184 t->state = state;
184 t->state = state;
185 t->mode = mode;
185 t->mode = mode;
186 t->size = size;
186 t->size = size;
187 t->mtime = mtime;
187 t->mtime = mtime;
188
188
189 return (PyObject *)t;
189 return (PyObject *)t;
190 }
190 }
191
191
192 static void dirstate_tuple_dealloc(PyObject *o)
192 static void dirstate_tuple_dealloc(PyObject *o)
193 {
193 {
194 PyObject_Del(o);
194 PyObject_Del(o);
195 }
195 }
196
196
197 static Py_ssize_t dirstate_tuple_length(PyObject *o)
197 static Py_ssize_t dirstate_tuple_length(PyObject *o)
198 {
198 {
199 return 4;
199 return 4;
200 }
200 }
201
201
202 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
202 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
203 {
203 {
204 dirstateTupleObject *t = (dirstateTupleObject *)o;
204 dirstateTupleObject *t = (dirstateTupleObject *)o;
205 switch (i) {
205 switch (i) {
206 case 0:
206 case 0:
207 return PyBytes_FromStringAndSize(&t->state, 1);
207 return PyBytes_FromStringAndSize(&t->state, 1);
208 case 1:
208 case 1:
209 return PyInt_FromLong(t->mode);
209 return PyInt_FromLong(t->mode);
210 case 2:
210 case 2:
211 return PyInt_FromLong(t->size);
211 return PyInt_FromLong(t->size);
212 case 3:
212 case 3:
213 return PyInt_FromLong(t->mtime);
213 return PyInt_FromLong(t->mtime);
214 default:
214 default:
215 PyErr_SetString(PyExc_IndexError, "index out of range");
215 PyErr_SetString(PyExc_IndexError, "index out of range");
216 return NULL;
216 return NULL;
217 }
217 }
218 }
218 }
219
219
220 static PySequenceMethods dirstate_tuple_sq = {
220 static PySequenceMethods dirstate_tuple_sq = {
221 dirstate_tuple_length, /* sq_length */
221 dirstate_tuple_length, /* sq_length */
222 0, /* sq_concat */
222 0, /* sq_concat */
223 0, /* sq_repeat */
223 0, /* sq_repeat */
224 dirstate_tuple_item, /* sq_item */
224 dirstate_tuple_item, /* sq_item */
225 0, /* sq_ass_item */
225 0, /* sq_ass_item */
226 0, /* sq_contains */
226 0, /* sq_contains */
227 0, /* sq_inplace_concat */
227 0, /* sq_inplace_concat */
228 0 /* sq_inplace_repeat */
228 0 /* sq_inplace_repeat */
229 };
229 };
230
230
231 PyTypeObject dirstateTupleType = {
231 PyTypeObject dirstateTupleType = {
232 PyVarObject_HEAD_INIT(NULL, 0)
232 PyVarObject_HEAD_INIT(NULL, 0)
233 "dirstate_tuple", /* tp_name */
233 "dirstate_tuple", /* tp_name */
234 sizeof(dirstateTupleObject),/* tp_basicsize */
234 sizeof(dirstateTupleObject),/* tp_basicsize */
235 0, /* tp_itemsize */
235 0, /* tp_itemsize */
236 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
236 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
237 0, /* tp_print */
237 0, /* tp_print */
238 0, /* tp_getattr */
238 0, /* tp_getattr */
239 0, /* tp_setattr */
239 0, /* tp_setattr */
240 0, /* tp_compare */
240 0, /* tp_compare */
241 0, /* tp_repr */
241 0, /* tp_repr */
242 0, /* tp_as_number */
242 0, /* tp_as_number */
243 &dirstate_tuple_sq, /* tp_as_sequence */
243 &dirstate_tuple_sq, /* tp_as_sequence */
244 0, /* tp_as_mapping */
244 0, /* tp_as_mapping */
245 0, /* tp_hash */
245 0, /* tp_hash */
246 0, /* tp_call */
246 0, /* tp_call */
247 0, /* tp_str */
247 0, /* tp_str */
248 0, /* tp_getattro */
248 0, /* tp_getattro */
249 0, /* tp_setattro */
249 0, /* tp_setattro */
250 0, /* tp_as_buffer */
250 0, /* tp_as_buffer */
251 Py_TPFLAGS_DEFAULT, /* tp_flags */
251 Py_TPFLAGS_DEFAULT, /* tp_flags */
252 "dirstate tuple", /* tp_doc */
252 "dirstate tuple", /* tp_doc */
253 0, /* tp_traverse */
253 0, /* tp_traverse */
254 0, /* tp_clear */
254 0, /* tp_clear */
255 0, /* tp_richcompare */
255 0, /* tp_richcompare */
256 0, /* tp_weaklistoffset */
256 0, /* tp_weaklistoffset */
257 0, /* tp_iter */
257 0, /* tp_iter */
258 0, /* tp_iternext */
258 0, /* tp_iternext */
259 0, /* tp_methods */
259 0, /* tp_methods */
260 0, /* tp_members */
260 0, /* tp_members */
261 0, /* tp_getset */
261 0, /* tp_getset */
262 0, /* tp_base */
262 0, /* tp_base */
263 0, /* tp_dict */
263 0, /* tp_dict */
264 0, /* tp_descr_get */
264 0, /* tp_descr_get */
265 0, /* tp_descr_set */
265 0, /* tp_descr_set */
266 0, /* tp_dictoffset */
266 0, /* tp_dictoffset */
267 0, /* tp_init */
267 0, /* tp_init */
268 0, /* tp_alloc */
268 0, /* tp_alloc */
269 dirstate_tuple_new, /* tp_new */
269 dirstate_tuple_new, /* tp_new */
270 };
270 };
271
271
272 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
272 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
273 {
273 {
274 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
274 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
275 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
275 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
276 char state, *cur, *str, *cpos;
276 char state, *cur, *str, *cpos;
277 int mode, size, mtime;
277 int mode, size, mtime;
278 unsigned int flen, len, pos = 40;
278 unsigned int flen, len, pos = 40;
279 int readlen;
279 int readlen;
280
280
281 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
281 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
282 &PyDict_Type, &dmap,
282 &PyDict_Type, &dmap,
283 &PyDict_Type, &cmap,
283 &PyDict_Type, &cmap,
284 &str, &readlen))
284 &str, &readlen))
285 goto quit;
285 goto quit;
286
286
287 if (readlen < 0)
287 if (readlen < 0)
288 goto quit;
288 goto quit;
289
289
290 len = readlen;
290 len = readlen;
291
291
292 /* read parents */
292 /* read parents */
293 if (len < 40)
293 if (len < 40)
294 goto quit;
294 goto quit;
295
295
296 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
296 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
297 if (!parents)
297 if (!parents)
298 goto quit;
298 goto quit;
299
299
300 /* read filenames */
300 /* read filenames */
301 while (pos >= 40 && pos < len) {
301 while (pos >= 40 && pos < len) {
302 cur = str + pos;
302 cur = str + pos;
303 /* unpack header */
303 /* unpack header */
304 state = *cur;
304 state = *cur;
305 mode = getbe32(cur + 1);
305 mode = getbe32(cur + 1);
306 size = getbe32(cur + 5);
306 size = getbe32(cur + 5);
307 mtime = getbe32(cur + 9);
307 mtime = getbe32(cur + 9);
308 flen = getbe32(cur + 13);
308 flen = getbe32(cur + 13);
309 pos += 17;
309 pos += 17;
310 cur += 17;
310 cur += 17;
311 if (flen > len - pos) {
311 if (flen > len - pos) {
312 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
312 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
313 goto quit;
313 goto quit;
314 }
314 }
315
315
316 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
316 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
317 mtime);
317 mtime);
318 cpos = memchr(cur, 0, flen);
318 cpos = memchr(cur, 0, flen);
319 if (cpos) {
319 if (cpos) {
320 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
320 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
321 cname = PyBytes_FromStringAndSize(cpos + 1,
321 cname = PyBytes_FromStringAndSize(cpos + 1,
322 flen - (cpos - cur) - 1);
322 flen - (cpos - cur) - 1);
323 if (!fname || !cname ||
323 if (!fname || !cname ||
324 PyDict_SetItem(cmap, fname, cname) == -1 ||
324 PyDict_SetItem(cmap, fname, cname) == -1 ||
325 PyDict_SetItem(dmap, fname, entry) == -1)
325 PyDict_SetItem(dmap, fname, entry) == -1)
326 goto quit;
326 goto quit;
327 Py_DECREF(cname);
327 Py_DECREF(cname);
328 } else {
328 } else {
329 fname = PyBytes_FromStringAndSize(cur, flen);
329 fname = PyBytes_FromStringAndSize(cur, flen);
330 if (!fname ||
330 if (!fname ||
331 PyDict_SetItem(dmap, fname, entry) == -1)
331 PyDict_SetItem(dmap, fname, entry) == -1)
332 goto quit;
332 goto quit;
333 }
333 }
334 Py_DECREF(fname);
334 Py_DECREF(fname);
335 Py_DECREF(entry);
335 Py_DECREF(entry);
336 fname = cname = entry = NULL;
336 fname = cname = entry = NULL;
337 pos += flen;
337 pos += flen;
338 }
338 }
339
339
340 ret = parents;
340 ret = parents;
341 Py_INCREF(ret);
341 Py_INCREF(ret);
342 quit:
342 quit:
343 Py_XDECREF(fname);
343 Py_XDECREF(fname);
344 Py_XDECREF(cname);
344 Py_XDECREF(cname);
345 Py_XDECREF(entry);
345 Py_XDECREF(entry);
346 Py_XDECREF(parents);
346 Py_XDECREF(parents);
347 return ret;
347 return ret;
348 }
348 }
349
349
350 /*
350 /*
351 * Efficiently pack a dirstate object into its on-disk format.
351 * Efficiently pack a dirstate object into its on-disk format.
352 */
352 */
353 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
353 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
354 {
354 {
355 PyObject *packobj = NULL;
355 PyObject *packobj = NULL;
356 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
356 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
357 Py_ssize_t nbytes, pos, l;
357 Py_ssize_t nbytes, pos, l;
358 PyObject *k, *v, *pn;
358 PyObject *k, *v, *pn;
359 char *p, *s;
359 char *p, *s;
360 double now;
360 double now;
361
361
362 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
362 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
363 &PyDict_Type, &map, &PyDict_Type, &copymap,
363 &PyDict_Type, &map, &PyDict_Type, &copymap,
364 &pl, &now))
364 &pl, &now))
365 return NULL;
365 return NULL;
366
366
367 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
367 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
368 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
368 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
369 return NULL;
369 return NULL;
370 }
370 }
371
371
372 /* Figure out how much we need to allocate. */
372 /* Figure out how much we need to allocate. */
373 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
373 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
374 PyObject *c;
374 PyObject *c;
375 if (!PyString_Check(k)) {
375 if (!PyString_Check(k)) {
376 PyErr_SetString(PyExc_TypeError, "expected string key");
376 PyErr_SetString(PyExc_TypeError, "expected string key");
377 goto bail;
377 goto bail;
378 }
378 }
379 nbytes += PyString_GET_SIZE(k) + 17;
379 nbytes += PyString_GET_SIZE(k) + 17;
380 c = PyDict_GetItem(copymap, k);
380 c = PyDict_GetItem(copymap, k);
381 if (c) {
381 if (c) {
382 if (!PyString_Check(c)) {
382 if (!PyString_Check(c)) {
383 PyErr_SetString(PyExc_TypeError,
383 PyErr_SetString(PyExc_TypeError,
384 "expected string key");
384 "expected string key");
385 goto bail;
385 goto bail;
386 }
386 }
387 nbytes += PyString_GET_SIZE(c) + 1;
387 nbytes += PyString_GET_SIZE(c) + 1;
388 }
388 }
389 }
389 }
390
390
391 packobj = PyString_FromStringAndSize(NULL, nbytes);
391 packobj = PyString_FromStringAndSize(NULL, nbytes);
392 if (packobj == NULL)
392 if (packobj == NULL)
393 goto bail;
393 goto bail;
394
394
395 p = PyString_AS_STRING(packobj);
395 p = PyString_AS_STRING(packobj);
396
396
397 pn = PySequence_ITEM(pl, 0);
397 pn = PySequence_ITEM(pl, 0);
398 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
398 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
399 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
399 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
400 goto bail;
400 goto bail;
401 }
401 }
402 memcpy(p, s, l);
402 memcpy(p, s, l);
403 p += 20;
403 p += 20;
404 pn = PySequence_ITEM(pl, 1);
404 pn = PySequence_ITEM(pl, 1);
405 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
405 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
406 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
406 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
407 goto bail;
407 goto bail;
408 }
408 }
409 memcpy(p, s, l);
409 memcpy(p, s, l);
410 p += 20;
410 p += 20;
411
411
412 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
412 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
413 dirstateTupleObject *tuple;
413 dirstateTupleObject *tuple;
414 char state;
414 char state;
415 uint32_t mode, size, mtime;
415 uint32_t mode, size, mtime;
416 Py_ssize_t len, l;
416 Py_ssize_t len, l;
417 PyObject *o;
417 PyObject *o;
418 char *t;
418 char *t;
419
419
420 if (!dirstate_tuple_check(v)) {
420 if (!dirstate_tuple_check(v)) {
421 PyErr_SetString(PyExc_TypeError,
421 PyErr_SetString(PyExc_TypeError,
422 "expected a dirstate tuple");
422 "expected a dirstate tuple");
423 goto bail;
423 goto bail;
424 }
424 }
425 tuple = (dirstateTupleObject *)v;
425 tuple = (dirstateTupleObject *)v;
426
426
427 state = tuple->state;
427 state = tuple->state;
428 mode = tuple->mode;
428 mode = tuple->mode;
429 size = tuple->size;
429 size = tuple->size;
430 mtime = tuple->mtime;
430 mtime = tuple->mtime;
431 if (state == 'n' && mtime == (uint32_t)now) {
431 if (state == 'n' && mtime == (uint32_t)now) {
432 /* See pure/parsers.py:pack_dirstate for why we do
432 /* See pure/parsers.py:pack_dirstate for why we do
433 * this. */
433 * this. */
434 mtime = -1;
434 mtime = -1;
435 mtime_unset = (PyObject *)make_dirstate_tuple(
435 mtime_unset = (PyObject *)make_dirstate_tuple(
436 state, mode, size, mtime);
436 state, mode, size, mtime);
437 if (!mtime_unset)
437 if (!mtime_unset)
438 goto bail;
438 goto bail;
439 if (PyDict_SetItem(map, k, mtime_unset) == -1)
439 if (PyDict_SetItem(map, k, mtime_unset) == -1)
440 goto bail;
440 goto bail;
441 Py_DECREF(mtime_unset);
441 Py_DECREF(mtime_unset);
442 mtime_unset = NULL;
442 mtime_unset = NULL;
443 }
443 }
444 *p++ = state;
444 *p++ = state;
445 putbe32(mode, p);
445 putbe32(mode, p);
446 putbe32(size, p + 4);
446 putbe32(size, p + 4);
447 putbe32(mtime, p + 8);
447 putbe32(mtime, p + 8);
448 t = p + 12;
448 t = p + 12;
449 p += 16;
449 p += 16;
450 len = PyString_GET_SIZE(k);
450 len = PyString_GET_SIZE(k);
451 memcpy(p, PyString_AS_STRING(k), len);
451 memcpy(p, PyString_AS_STRING(k), len);
452 p += len;
452 p += len;
453 o = PyDict_GetItem(copymap, k);
453 o = PyDict_GetItem(copymap, k);
454 if (o) {
454 if (o) {
455 *p++ = '\0';
455 *p++ = '\0';
456 l = PyString_GET_SIZE(o);
456 l = PyString_GET_SIZE(o);
457 memcpy(p, PyString_AS_STRING(o), l);
457 memcpy(p, PyString_AS_STRING(o), l);
458 p += l;
458 p += l;
459 len += l + 1;
459 len += l + 1;
460 }
460 }
461 putbe32((uint32_t)len, t);
461 putbe32((uint32_t)len, t);
462 }
462 }
463
463
464 pos = p - PyString_AS_STRING(packobj);
464 pos = p - PyString_AS_STRING(packobj);
465 if (pos != nbytes) {
465 if (pos != nbytes) {
466 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
466 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
467 (long)pos, (long)nbytes);
467 (long)pos, (long)nbytes);
468 goto bail;
468 goto bail;
469 }
469 }
470
470
471 return packobj;
471 return packobj;
472 bail:
472 bail:
473 Py_XDECREF(mtime_unset);
473 Py_XDECREF(mtime_unset);
474 Py_XDECREF(packobj);
474 Py_XDECREF(packobj);
475 return NULL;
475 return NULL;
476 }
476 }
477
477
478 /*
478 /*
479 * A base-16 trie for fast node->rev mapping.
479 * A base-16 trie for fast node->rev mapping.
480 *
480 *
481 * Positive value is index of the next node in the trie
481 * Positive value is index of the next node in the trie
482 * Negative value is a leaf: -(rev + 1)
482 * Negative value is a leaf: -(rev + 1)
483 * Zero is empty
483 * Zero is empty
484 */
484 */
485 typedef struct {
485 typedef struct {
486 int children[16];
486 int children[16];
487 } nodetree;
487 } nodetree;
488
488
489 /*
489 /*
490 * This class has two behaviours.
490 * This class has two behaviours.
491 *
491 *
492 * When used in a list-like way (with integer keys), we decode an
492 * When used in a list-like way (with integer keys), we decode an
493 * entry in a RevlogNG index file on demand. Our last entry is a
493 * entry in a RevlogNG index file on demand. Our last entry is a
494 * sentinel, always a nullid. We have limited support for
494 * sentinel, always a nullid. We have limited support for
495 * integer-keyed insert and delete, only at elements right before the
495 * integer-keyed insert and delete, only at elements right before the
496 * sentinel.
496 * sentinel.
497 *
497 *
498 * With string keys, we lazily perform a reverse mapping from node to
498 * With string keys, we lazily perform a reverse mapping from node to
499 * rev, using a base-16 trie.
499 * rev, using a base-16 trie.
500 */
500 */
501 typedef struct {
501 typedef struct {
502 PyObject_HEAD
502 PyObject_HEAD
503 /* Type-specific fields go here. */
503 /* Type-specific fields go here. */
504 PyObject *data; /* raw bytes of index */
504 PyObject *data; /* raw bytes of index */
505 PyObject **cache; /* cached tuples */
505 PyObject **cache; /* cached tuples */
506 const char **offsets; /* populated on demand */
506 const char **offsets; /* populated on demand */
507 Py_ssize_t raw_length; /* original number of elements */
507 Py_ssize_t raw_length; /* original number of elements */
508 Py_ssize_t length; /* current number of elements */
508 Py_ssize_t length; /* current number of elements */
509 PyObject *added; /* populated on demand */
509 PyObject *added; /* populated on demand */
510 PyObject *headrevs; /* cache, invalidated on changes */
510 PyObject *headrevs; /* cache, invalidated on changes */
511 PyObject *filteredrevs;/* filtered revs set */
511 nodetree *nt; /* base-16 trie */
512 nodetree *nt; /* base-16 trie */
512 int ntlength; /* # nodes in use */
513 int ntlength; /* # nodes in use */
513 int ntcapacity; /* # nodes allocated */
514 int ntcapacity; /* # nodes allocated */
514 int ntdepth; /* maximum depth of tree */
515 int ntdepth; /* maximum depth of tree */
515 int ntsplits; /* # splits performed */
516 int ntsplits; /* # splits performed */
516 int ntrev; /* last rev scanned */
517 int ntrev; /* last rev scanned */
517 int ntlookups; /* # lookups */
518 int ntlookups; /* # lookups */
518 int ntmisses; /* # lookups that miss the cache */
519 int ntmisses; /* # lookups that miss the cache */
519 int inlined;
520 int inlined;
520 } indexObject;
521 } indexObject;
521
522
522 static Py_ssize_t index_length(const indexObject *self)
523 static Py_ssize_t index_length(const indexObject *self)
523 {
524 {
524 if (self->added == NULL)
525 if (self->added == NULL)
525 return self->length;
526 return self->length;
526 return self->length + PyList_GET_SIZE(self->added);
527 return self->length + PyList_GET_SIZE(self->added);
527 }
528 }
528
529
529 static PyObject *nullentry;
530 static PyObject *nullentry;
530 static const char nullid[20];
531 static const char nullid[20];
531
532
532 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
533 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
533
534
534 #if LONG_MAX == 0x7fffffffL
535 #if LONG_MAX == 0x7fffffffL
535 static char *tuple_format = "Kiiiiiis#";
536 static char *tuple_format = "Kiiiiiis#";
536 #else
537 #else
537 static char *tuple_format = "kiiiiiis#";
538 static char *tuple_format = "kiiiiiis#";
538 #endif
539 #endif
539
540
540 /* A RevlogNG v1 index entry is 64 bytes long. */
541 /* A RevlogNG v1 index entry is 64 bytes long. */
541 static const long v1_hdrsize = 64;
542 static const long v1_hdrsize = 64;
542
543
543 /*
544 /*
544 * Return a pointer to the beginning of a RevlogNG record.
545 * Return a pointer to the beginning of a RevlogNG record.
545 */
546 */
546 static const char *index_deref(indexObject *self, Py_ssize_t pos)
547 static const char *index_deref(indexObject *self, Py_ssize_t pos)
547 {
548 {
548 if (self->inlined && pos > 0) {
549 if (self->inlined && pos > 0) {
549 if (self->offsets == NULL) {
550 if (self->offsets == NULL) {
550 self->offsets = malloc(self->raw_length *
551 self->offsets = malloc(self->raw_length *
551 sizeof(*self->offsets));
552 sizeof(*self->offsets));
552 if (self->offsets == NULL)
553 if (self->offsets == NULL)
553 return (const char *)PyErr_NoMemory();
554 return (const char *)PyErr_NoMemory();
554 inline_scan(self, self->offsets);
555 inline_scan(self, self->offsets);
555 }
556 }
556 return self->offsets[pos];
557 return self->offsets[pos];
557 }
558 }
558
559
559 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
560 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
560 }
561 }
561
562
562 /*
563 /*
563 * RevlogNG format (all in big endian, data may be inlined):
564 * RevlogNG format (all in big endian, data may be inlined):
564 * 6 bytes: offset
565 * 6 bytes: offset
565 * 2 bytes: flags
566 * 2 bytes: flags
566 * 4 bytes: compressed length
567 * 4 bytes: compressed length
567 * 4 bytes: uncompressed length
568 * 4 bytes: uncompressed length
568 * 4 bytes: base revision
569 * 4 bytes: base revision
569 * 4 bytes: link revision
570 * 4 bytes: link revision
570 * 4 bytes: parent 1 revision
571 * 4 bytes: parent 1 revision
571 * 4 bytes: parent 2 revision
572 * 4 bytes: parent 2 revision
572 * 32 bytes: nodeid (only 20 bytes used)
573 * 32 bytes: nodeid (only 20 bytes used)
573 */
574 */
574 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
575 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
575 {
576 {
576 uint64_t offset_flags;
577 uint64_t offset_flags;
577 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
578 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
578 const char *c_node_id;
579 const char *c_node_id;
579 const char *data;
580 const char *data;
580 Py_ssize_t length = index_length(self);
581 Py_ssize_t length = index_length(self);
581 PyObject *entry;
582 PyObject *entry;
582
583
583 if (pos < 0)
584 if (pos < 0)
584 pos += length;
585 pos += length;
585
586
586 if (pos < 0 || pos >= length) {
587 if (pos < 0 || pos >= length) {
587 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
588 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
588 return NULL;
589 return NULL;
589 }
590 }
590
591
591 if (pos == length - 1) {
592 if (pos == length - 1) {
592 Py_INCREF(nullentry);
593 Py_INCREF(nullentry);
593 return nullentry;
594 return nullentry;
594 }
595 }
595
596
596 if (pos >= self->length - 1) {
597 if (pos >= self->length - 1) {
597 PyObject *obj;
598 PyObject *obj;
598 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
599 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
599 Py_INCREF(obj);
600 Py_INCREF(obj);
600 return obj;
601 return obj;
601 }
602 }
602
603
603 if (self->cache) {
604 if (self->cache) {
604 if (self->cache[pos]) {
605 if (self->cache[pos]) {
605 Py_INCREF(self->cache[pos]);
606 Py_INCREF(self->cache[pos]);
606 return self->cache[pos];
607 return self->cache[pos];
607 }
608 }
608 } else {
609 } else {
609 self->cache = calloc(self->raw_length, sizeof(PyObject *));
610 self->cache = calloc(self->raw_length, sizeof(PyObject *));
610 if (self->cache == NULL)
611 if (self->cache == NULL)
611 return PyErr_NoMemory();
612 return PyErr_NoMemory();
612 }
613 }
613
614
614 data = index_deref(self, pos);
615 data = index_deref(self, pos);
615 if (data == NULL)
616 if (data == NULL)
616 return NULL;
617 return NULL;
617
618
618 offset_flags = getbe32(data + 4);
619 offset_flags = getbe32(data + 4);
619 if (pos == 0) /* mask out version number for the first entry */
620 if (pos == 0) /* mask out version number for the first entry */
620 offset_flags &= 0xFFFF;
621 offset_flags &= 0xFFFF;
621 else {
622 else {
622 uint32_t offset_high = getbe32(data);
623 uint32_t offset_high = getbe32(data);
623 offset_flags |= ((uint64_t)offset_high) << 32;
624 offset_flags |= ((uint64_t)offset_high) << 32;
624 }
625 }
625
626
626 comp_len = getbe32(data + 8);
627 comp_len = getbe32(data + 8);
627 uncomp_len = getbe32(data + 12);
628 uncomp_len = getbe32(data + 12);
628 base_rev = getbe32(data + 16);
629 base_rev = getbe32(data + 16);
629 link_rev = getbe32(data + 20);
630 link_rev = getbe32(data + 20);
630 parent_1 = getbe32(data + 24);
631 parent_1 = getbe32(data + 24);
631 parent_2 = getbe32(data + 28);
632 parent_2 = getbe32(data + 28);
632 c_node_id = data + 32;
633 c_node_id = data + 32;
633
634
634 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
635 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
635 uncomp_len, base_rev, link_rev,
636 uncomp_len, base_rev, link_rev,
636 parent_1, parent_2, c_node_id, 20);
637 parent_1, parent_2, c_node_id, 20);
637
638
638 if (entry) {
639 if (entry) {
639 PyObject_GC_UnTrack(entry);
640 PyObject_GC_UnTrack(entry);
640 Py_INCREF(entry);
641 Py_INCREF(entry);
641 }
642 }
642
643
643 self->cache[pos] = entry;
644 self->cache[pos] = entry;
644
645
645 return entry;
646 return entry;
646 }
647 }
647
648
648 /*
649 /*
649 * Return the 20-byte SHA of the node corresponding to the given rev.
650 * Return the 20-byte SHA of the node corresponding to the given rev.
650 */
651 */
651 static const char *index_node(indexObject *self, Py_ssize_t pos)
652 static const char *index_node(indexObject *self, Py_ssize_t pos)
652 {
653 {
653 Py_ssize_t length = index_length(self);
654 Py_ssize_t length = index_length(self);
654 const char *data;
655 const char *data;
655
656
656 if (pos == length - 1 || pos == INT_MAX)
657 if (pos == length - 1 || pos == INT_MAX)
657 return nullid;
658 return nullid;
658
659
659 if (pos >= length)
660 if (pos >= length)
660 return NULL;
661 return NULL;
661
662
662 if (pos >= self->length - 1) {
663 if (pos >= self->length - 1) {
663 PyObject *tuple, *str;
664 PyObject *tuple, *str;
664 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
665 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
665 str = PyTuple_GetItem(tuple, 7);
666 str = PyTuple_GetItem(tuple, 7);
666 return str ? PyString_AS_STRING(str) : NULL;
667 return str ? PyString_AS_STRING(str) : NULL;
667 }
668 }
668
669
669 data = index_deref(self, pos);
670 data = index_deref(self, pos);
670 return data ? data + 32 : NULL;
671 return data ? data + 32 : NULL;
671 }
672 }
672
673
673 static int nt_insert(indexObject *self, const char *node, int rev);
674 static int nt_insert(indexObject *self, const char *node, int rev);
674
675
675 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
676 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
676 {
677 {
677 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
678 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
678 return -1;
679 return -1;
679 if (*nodelen == 20)
680 if (*nodelen == 20)
680 return 0;
681 return 0;
681 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
682 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
682 return -1;
683 return -1;
683 }
684 }
684
685
685 static PyObject *index_insert(indexObject *self, PyObject *args)
686 static PyObject *index_insert(indexObject *self, PyObject *args)
686 {
687 {
687 PyObject *obj;
688 PyObject *obj;
688 char *node;
689 char *node;
689 Py_ssize_t offset, len, nodelen;
690 Py_ssize_t offset, len, nodelen;
690
691
691 if (!PyArg_ParseTuple(args, "nO", &offset, &obj))
692 if (!PyArg_ParseTuple(args, "nO", &offset, &obj))
692 return NULL;
693 return NULL;
693
694
694 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
695 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
695 PyErr_SetString(PyExc_TypeError, "8-tuple required");
696 PyErr_SetString(PyExc_TypeError, "8-tuple required");
696 return NULL;
697 return NULL;
697 }
698 }
698
699
699 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
700 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
700 return NULL;
701 return NULL;
701
702
702 len = index_length(self);
703 len = index_length(self);
703
704
704 if (offset < 0)
705 if (offset < 0)
705 offset += len;
706 offset += len;
706
707
707 if (offset != len - 1) {
708 if (offset != len - 1) {
708 PyErr_SetString(PyExc_IndexError,
709 PyErr_SetString(PyExc_IndexError,
709 "insert only supported at index -1");
710 "insert only supported at index -1");
710 return NULL;
711 return NULL;
711 }
712 }
712
713
713 if (offset > INT_MAX) {
714 if (offset > INT_MAX) {
714 PyErr_SetString(PyExc_ValueError,
715 PyErr_SetString(PyExc_ValueError,
715 "currently only 2**31 revs supported");
716 "currently only 2**31 revs supported");
716 return NULL;
717 return NULL;
717 }
718 }
718
719
719 if (self->added == NULL) {
720 if (self->added == NULL) {
720 self->added = PyList_New(0);
721 self->added = PyList_New(0);
721 if (self->added == NULL)
722 if (self->added == NULL)
722 return NULL;
723 return NULL;
723 }
724 }
724
725
725 if (PyList_Append(self->added, obj) == -1)
726 if (PyList_Append(self->added, obj) == -1)
726 return NULL;
727 return NULL;
727
728
728 if (self->nt)
729 if (self->nt)
729 nt_insert(self, node, (int)offset);
730 nt_insert(self, node, (int)offset);
730
731
731 Py_CLEAR(self->headrevs);
732 Py_CLEAR(self->headrevs);
732 Py_RETURN_NONE;
733 Py_RETURN_NONE;
733 }
734 }
734
735
735 static void _index_clearcaches(indexObject *self)
736 static void _index_clearcaches(indexObject *self)
736 {
737 {
737 if (self->cache) {
738 if (self->cache) {
738 Py_ssize_t i;
739 Py_ssize_t i;
739
740
740 for (i = 0; i < self->raw_length; i++)
741 for (i = 0; i < self->raw_length; i++)
741 Py_CLEAR(self->cache[i]);
742 Py_CLEAR(self->cache[i]);
742 free(self->cache);
743 free(self->cache);
743 self->cache = NULL;
744 self->cache = NULL;
744 }
745 }
745 if (self->offsets) {
746 if (self->offsets) {
746 free(self->offsets);
747 free(self->offsets);
747 self->offsets = NULL;
748 self->offsets = NULL;
748 }
749 }
749 if (self->nt) {
750 if (self->nt) {
750 free(self->nt);
751 free(self->nt);
751 self->nt = NULL;
752 self->nt = NULL;
752 }
753 }
753 Py_CLEAR(self->headrevs);
754 Py_CLEAR(self->headrevs);
754 }
755 }
755
756
756 static PyObject *index_clearcaches(indexObject *self)
757 static PyObject *index_clearcaches(indexObject *self)
757 {
758 {
758 _index_clearcaches(self);
759 _index_clearcaches(self);
759 self->ntlength = self->ntcapacity = 0;
760 self->ntlength = self->ntcapacity = 0;
760 self->ntdepth = self->ntsplits = 0;
761 self->ntdepth = self->ntsplits = 0;
761 self->ntrev = -1;
762 self->ntrev = -1;
762 self->ntlookups = self->ntmisses = 0;
763 self->ntlookups = self->ntmisses = 0;
763 Py_RETURN_NONE;
764 Py_RETURN_NONE;
764 }
765 }
765
766
766 static PyObject *index_stats(indexObject *self)
767 static PyObject *index_stats(indexObject *self)
767 {
768 {
768 PyObject *obj = PyDict_New();
769 PyObject *obj = PyDict_New();
769
770
770 if (obj == NULL)
771 if (obj == NULL)
771 return NULL;
772 return NULL;
772
773
773 #define istat(__n, __d) \
774 #define istat(__n, __d) \
774 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
775 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
775 goto bail;
776 goto bail;
776
777
777 if (self->added) {
778 if (self->added) {
778 Py_ssize_t len = PyList_GET_SIZE(self->added);
779 Py_ssize_t len = PyList_GET_SIZE(self->added);
779 if (PyDict_SetItemString(obj, "index entries added",
780 if (PyDict_SetItemString(obj, "index entries added",
780 PyInt_FromSsize_t(len)) == -1)
781 PyInt_FromSsize_t(len)) == -1)
781 goto bail;
782 goto bail;
782 }
783 }
783
784
784 if (self->raw_length != self->length - 1)
785 if (self->raw_length != self->length - 1)
785 istat(raw_length, "revs on disk");
786 istat(raw_length, "revs on disk");
786 istat(length, "revs in memory");
787 istat(length, "revs in memory");
787 istat(ntcapacity, "node trie capacity");
788 istat(ntcapacity, "node trie capacity");
788 istat(ntdepth, "node trie depth");
789 istat(ntdepth, "node trie depth");
789 istat(ntlength, "node trie count");
790 istat(ntlength, "node trie count");
790 istat(ntlookups, "node trie lookups");
791 istat(ntlookups, "node trie lookups");
791 istat(ntmisses, "node trie misses");
792 istat(ntmisses, "node trie misses");
792 istat(ntrev, "node trie last rev scanned");
793 istat(ntrev, "node trie last rev scanned");
793 istat(ntsplits, "node trie splits");
794 istat(ntsplits, "node trie splits");
794
795
795 #undef istat
796 #undef istat
796
797
797 return obj;
798 return obj;
798
799
799 bail:
800 bail:
800 Py_XDECREF(obj);
801 Py_XDECREF(obj);
801 return NULL;
802 return NULL;
802 }
803 }
803
804
804 /*
805 /*
805 * When we cache a list, we want to be sure the caller can't mutate
806 * When we cache a list, we want to be sure the caller can't mutate
806 * the cached copy.
807 * the cached copy.
807 */
808 */
808 static PyObject *list_copy(PyObject *list)
809 static PyObject *list_copy(PyObject *list)
809 {
810 {
810 Py_ssize_t len = PyList_GET_SIZE(list);
811 Py_ssize_t len = PyList_GET_SIZE(list);
811 PyObject *newlist = PyList_New(len);
812 PyObject *newlist = PyList_New(len);
812 Py_ssize_t i;
813 Py_ssize_t i;
813
814
814 if (newlist == NULL)
815 if (newlist == NULL)
815 return NULL;
816 return NULL;
816
817
817 for (i = 0; i < len; i++) {
818 for (i = 0; i < len; i++) {
818 PyObject *obj = PyList_GET_ITEM(list, i);
819 PyObject *obj = PyList_GET_ITEM(list, i);
819 Py_INCREF(obj);
820 Py_INCREF(obj);
820 PyList_SET_ITEM(newlist, i, obj);
821 PyList_SET_ITEM(newlist, i, obj);
821 }
822 }
822
823
823 return newlist;
824 return newlist;
824 }
825 }
825
826
826 static PyObject *index_headrevs(indexObject *self)
827 static int check_filter(PyObject *filter, Py_ssize_t arg) {
828 if (filter) {
829 PyObject *arglist, *result;
830 int isfiltered;
831
832 arglist = Py_BuildValue("(n)", arg);
833 if (!arglist) {
834 return -1;
835 }
836
837 result = PyEval_CallObject(filter, arglist);
838 Py_DECREF(arglist);
839 if (!result) {
840 return -1;
841 }
842
843 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
844 * same as this function, so we can just return it directly.*/
845 isfiltered = PyObject_IsTrue(result);
846 Py_DECREF(result);
847 return isfiltered;
848 } else {
849 return 0;
850 }
851 }
852
853 static PyObject *index_headrevs(indexObject *self, PyObject *args)
827 {
854 {
828 Py_ssize_t i, len, addlen;
855 Py_ssize_t i, len, addlen;
829 char *nothead = NULL;
856 char *nothead = NULL;
830 PyObject *heads;
857 PyObject *heads;
858 PyObject *filter = NULL;
859 PyObject *filteredrevs = Py_None;
831
860
832 if (self->headrevs)
861 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
862 return NULL;
863 }
864
865 if (self->headrevs && filteredrevs == self->filteredrevs)
833 return list_copy(self->headrevs);
866 return list_copy(self->headrevs);
834
867
868 Py_DECREF(self->filteredrevs);
869 self->filteredrevs = filteredrevs;
870 Py_INCREF(filteredrevs);
871
872 if (filteredrevs != Py_None) {
873 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
874 if (!filter) {
875 PyErr_SetString(PyExc_TypeError,
876 "filteredrevs has no attribute __contains__");
877 goto bail;
878 }
879 }
880
835 len = index_length(self) - 1;
881 len = index_length(self) - 1;
836 heads = PyList_New(0);
882 heads = PyList_New(0);
837 if (heads == NULL)
883 if (heads == NULL)
838 goto bail;
884 goto bail;
839 if (len == 0) {
885 if (len == 0) {
840 PyObject *nullid = PyInt_FromLong(-1);
886 PyObject *nullid = PyInt_FromLong(-1);
841 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
887 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
842 Py_XDECREF(nullid);
888 Py_XDECREF(nullid);
843 goto bail;
889 goto bail;
844 }
890 }
845 goto done;
891 goto done;
846 }
892 }
847
893
848 nothead = calloc(len, 1);
894 nothead = calloc(len, 1);
849 if (nothead == NULL)
895 if (nothead == NULL)
850 goto bail;
896 goto bail;
851
897
852 for (i = 0; i < self->raw_length; i++) {
898 for (i = 0; i < self->raw_length; i++) {
853 const char *data = index_deref(self, i);
899 const char *data;
854 int parent_1 = getbe32(data + 24);
900 int parent_1, parent_2, isfiltered;
855 int parent_2 = getbe32(data + 28);
901
902 isfiltered = check_filter(filter, i);
903 if (isfiltered == -1) {
904 PyErr_SetString(PyExc_TypeError,
905 "unable to check filter");
906 goto bail;
907 }
908
909 if (isfiltered) {
910 nothead[i] = 1;
911 continue;
912 }
913
914 data = index_deref(self, i);
915 parent_1 = getbe32(data + 24);
916 parent_2 = getbe32(data + 28);
917
856 if (parent_1 >= 0)
918 if (parent_1 >= 0)
857 nothead[parent_1] = 1;
919 nothead[parent_1] = 1;
858 if (parent_2 >= 0)
920 if (parent_2 >= 0)
859 nothead[parent_2] = 1;
921 nothead[parent_2] = 1;
860 }
922 }
861
923
862 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
924 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
863
925
864 for (i = 0; i < addlen; i++) {
926 for (i = 0; i < addlen; i++) {
865 PyObject *rev = PyList_GET_ITEM(self->added, i);
927 PyObject *rev = PyList_GET_ITEM(self->added, i);
866 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
928 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
867 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
929 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
868 long parent_1, parent_2;
930 long parent_1, parent_2;
931 int isfiltered;
869
932
870 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
933 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
871 PyErr_SetString(PyExc_TypeError,
934 PyErr_SetString(PyExc_TypeError,
872 "revlog parents are invalid");
935 "revlog parents are invalid");
873 goto bail;
936 goto bail;
874 }
937 }
938
939 isfiltered = check_filter(filter, i);
940 if (isfiltered == -1) {
941 PyErr_SetString(PyExc_TypeError,
942 "unable to check filter");
943 goto bail;
944 }
945
946 if (isfiltered) {
947 nothead[i] = 1;
948 continue;
949 }
950
875 parent_1 = PyInt_AS_LONG(p1);
951 parent_1 = PyInt_AS_LONG(p1);
876 parent_2 = PyInt_AS_LONG(p2);
952 parent_2 = PyInt_AS_LONG(p2);
877 if (parent_1 >= 0)
953 if (parent_1 >= 0)
878 nothead[parent_1] = 1;
954 nothead[parent_1] = 1;
879 if (parent_2 >= 0)
955 if (parent_2 >= 0)
880 nothead[parent_2] = 1;
956 nothead[parent_2] = 1;
881 }
957 }
882
958
883 for (i = 0; i < len; i++) {
959 for (i = 0; i < len; i++) {
884 PyObject *head;
960 PyObject *head;
885
961
886 if (nothead[i])
962 if (nothead[i])
887 continue;
963 continue;
888 head = PyInt_FromSsize_t(i);
964 head = PyInt_FromSsize_t(i);
889 if (head == NULL || PyList_Append(heads, head) == -1) {
965 if (head == NULL || PyList_Append(heads, head) == -1) {
890 Py_XDECREF(head);
966 Py_XDECREF(head);
891 goto bail;
967 goto bail;
892 }
968 }
893 }
969 }
894
970
895 done:
971 done:
896 self->headrevs = heads;
972 self->headrevs = heads;
973 Py_XDECREF(filter);
897 free(nothead);
974 free(nothead);
898 return list_copy(self->headrevs);
975 return list_copy(self->headrevs);
899 bail:
976 bail:
977 Py_XDECREF(filter);
900 Py_XDECREF(heads);
978 Py_XDECREF(heads);
901 free(nothead);
979 free(nothead);
902 return NULL;
980 return NULL;
903 }
981 }
904
982
905 static inline int nt_level(const char *node, Py_ssize_t level)
983 static inline int nt_level(const char *node, Py_ssize_t level)
906 {
984 {
907 int v = node[level>>1];
985 int v = node[level>>1];
908 if (!(level & 1))
986 if (!(level & 1))
909 v >>= 4;
987 v >>= 4;
910 return v & 0xf;
988 return v & 0xf;
911 }
989 }
912
990
913 /*
991 /*
914 * Return values:
992 * Return values:
915 *
993 *
916 * -4: match is ambiguous (multiple candidates)
994 * -4: match is ambiguous (multiple candidates)
917 * -2: not found
995 * -2: not found
918 * rest: valid rev
996 * rest: valid rev
919 */
997 */
920 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
998 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
921 int hex)
999 int hex)
922 {
1000 {
923 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1001 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
924 int level, maxlevel, off;
1002 int level, maxlevel, off;
925
1003
926 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1004 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
927 return -1;
1005 return -1;
928
1006
929 if (self->nt == NULL)
1007 if (self->nt == NULL)
930 return -2;
1008 return -2;
931
1009
932 if (hex)
1010 if (hex)
933 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1011 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
934 else
1012 else
935 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1013 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
936
1014
937 for (level = off = 0; level < maxlevel; level++) {
1015 for (level = off = 0; level < maxlevel; level++) {
938 int k = getnybble(node, level);
1016 int k = getnybble(node, level);
939 nodetree *n = &self->nt[off];
1017 nodetree *n = &self->nt[off];
940 int v = n->children[k];
1018 int v = n->children[k];
941
1019
942 if (v < 0) {
1020 if (v < 0) {
943 const char *n;
1021 const char *n;
944 Py_ssize_t i;
1022 Py_ssize_t i;
945
1023
946 v = -v - 1;
1024 v = -v - 1;
947 n = index_node(self, v);
1025 n = index_node(self, v);
948 if (n == NULL)
1026 if (n == NULL)
949 return -2;
1027 return -2;
950 for (i = level; i < maxlevel; i++)
1028 for (i = level; i < maxlevel; i++)
951 if (getnybble(node, i) != nt_level(n, i))
1029 if (getnybble(node, i) != nt_level(n, i))
952 return -2;
1030 return -2;
953 return v;
1031 return v;
954 }
1032 }
955 if (v == 0)
1033 if (v == 0)
956 return -2;
1034 return -2;
957 off = v;
1035 off = v;
958 }
1036 }
959 /* multiple matches against an ambiguous prefix */
1037 /* multiple matches against an ambiguous prefix */
960 return -4;
1038 return -4;
961 }
1039 }
962
1040
963 static int nt_new(indexObject *self)
1041 static int nt_new(indexObject *self)
964 {
1042 {
965 if (self->ntlength == self->ntcapacity) {
1043 if (self->ntlength == self->ntcapacity) {
966 self->ntcapacity *= 2;
1044 self->ntcapacity *= 2;
967 self->nt = realloc(self->nt,
1045 self->nt = realloc(self->nt,
968 self->ntcapacity * sizeof(nodetree));
1046 self->ntcapacity * sizeof(nodetree));
969 if (self->nt == NULL) {
1047 if (self->nt == NULL) {
970 PyErr_SetString(PyExc_MemoryError, "out of memory");
1048 PyErr_SetString(PyExc_MemoryError, "out of memory");
971 return -1;
1049 return -1;
972 }
1050 }
973 memset(&self->nt[self->ntlength], 0,
1051 memset(&self->nt[self->ntlength], 0,
974 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1052 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
975 }
1053 }
976 return self->ntlength++;
1054 return self->ntlength++;
977 }
1055 }
978
1056
979 static int nt_insert(indexObject *self, const char *node, int rev)
1057 static int nt_insert(indexObject *self, const char *node, int rev)
980 {
1058 {
981 int level = 0;
1059 int level = 0;
982 int off = 0;
1060 int off = 0;
983
1061
984 while (level < 40) {
1062 while (level < 40) {
985 int k = nt_level(node, level);
1063 int k = nt_level(node, level);
986 nodetree *n;
1064 nodetree *n;
987 int v;
1065 int v;
988
1066
989 n = &self->nt[off];
1067 n = &self->nt[off];
990 v = n->children[k];
1068 v = n->children[k];
991
1069
992 if (v == 0) {
1070 if (v == 0) {
993 n->children[k] = -rev - 1;
1071 n->children[k] = -rev - 1;
994 return 0;
1072 return 0;
995 }
1073 }
996 if (v < 0) {
1074 if (v < 0) {
997 const char *oldnode = index_node(self, -v - 1);
1075 const char *oldnode = index_node(self, -v - 1);
998 int noff;
1076 int noff;
999
1077
1000 if (!oldnode || !memcmp(oldnode, node, 20)) {
1078 if (!oldnode || !memcmp(oldnode, node, 20)) {
1001 n->children[k] = -rev - 1;
1079 n->children[k] = -rev - 1;
1002 return 0;
1080 return 0;
1003 }
1081 }
1004 noff = nt_new(self);
1082 noff = nt_new(self);
1005 if (noff == -1)
1083 if (noff == -1)
1006 return -1;
1084 return -1;
1007 /* self->nt may have been changed by realloc */
1085 /* self->nt may have been changed by realloc */
1008 self->nt[off].children[k] = noff;
1086 self->nt[off].children[k] = noff;
1009 off = noff;
1087 off = noff;
1010 n = &self->nt[off];
1088 n = &self->nt[off];
1011 n->children[nt_level(oldnode, ++level)] = v;
1089 n->children[nt_level(oldnode, ++level)] = v;
1012 if (level > self->ntdepth)
1090 if (level > self->ntdepth)
1013 self->ntdepth = level;
1091 self->ntdepth = level;
1014 self->ntsplits += 1;
1092 self->ntsplits += 1;
1015 } else {
1093 } else {
1016 level += 1;
1094 level += 1;
1017 off = v;
1095 off = v;
1018 }
1096 }
1019 }
1097 }
1020
1098
1021 return -1;
1099 return -1;
1022 }
1100 }
1023
1101
1024 static int nt_init(indexObject *self)
1102 static int nt_init(indexObject *self)
1025 {
1103 {
1026 if (self->nt == NULL) {
1104 if (self->nt == NULL) {
1027 if (self->raw_length > INT_MAX) {
1105 if (self->raw_length > INT_MAX) {
1028 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1106 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1029 return -1;
1107 return -1;
1030 }
1108 }
1031 self->ntcapacity = self->raw_length < 4
1109 self->ntcapacity = self->raw_length < 4
1032 ? 4 : (int)self->raw_length / 2;
1110 ? 4 : (int)self->raw_length / 2;
1033
1111
1034 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1112 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1035 if (self->nt == NULL) {
1113 if (self->nt == NULL) {
1036 PyErr_NoMemory();
1114 PyErr_NoMemory();
1037 return -1;
1115 return -1;
1038 }
1116 }
1039 self->ntlength = 1;
1117 self->ntlength = 1;
1040 self->ntrev = (int)index_length(self) - 1;
1118 self->ntrev = (int)index_length(self) - 1;
1041 self->ntlookups = 1;
1119 self->ntlookups = 1;
1042 self->ntmisses = 0;
1120 self->ntmisses = 0;
1043 if (nt_insert(self, nullid, INT_MAX) == -1)
1121 if (nt_insert(self, nullid, INT_MAX) == -1)
1044 return -1;
1122 return -1;
1045 }
1123 }
1046 return 0;
1124 return 0;
1047 }
1125 }
1048
1126
1049 /*
1127 /*
1050 * Return values:
1128 * Return values:
1051 *
1129 *
1052 * -3: error (exception set)
1130 * -3: error (exception set)
1053 * -2: not found (no exception set)
1131 * -2: not found (no exception set)
1054 * rest: valid rev
1132 * rest: valid rev
1055 */
1133 */
1056 static int index_find_node(indexObject *self,
1134 static int index_find_node(indexObject *self,
1057 const char *node, Py_ssize_t nodelen)
1135 const char *node, Py_ssize_t nodelen)
1058 {
1136 {
1059 int rev;
1137 int rev;
1060
1138
1061 self->ntlookups++;
1139 self->ntlookups++;
1062 rev = nt_find(self, node, nodelen, 0);
1140 rev = nt_find(self, node, nodelen, 0);
1063 if (rev >= -1)
1141 if (rev >= -1)
1064 return rev;
1142 return rev;
1065
1143
1066 if (nt_init(self) == -1)
1144 if (nt_init(self) == -1)
1067 return -3;
1145 return -3;
1068
1146
1069 /*
1147 /*
1070 * For the first handful of lookups, we scan the entire index,
1148 * For the first handful of lookups, we scan the entire index,
1071 * and cache only the matching nodes. This optimizes for cases
1149 * and cache only the matching nodes. This optimizes for cases
1072 * like "hg tip", where only a few nodes are accessed.
1150 * like "hg tip", where only a few nodes are accessed.
1073 *
1151 *
1074 * After that, we cache every node we visit, using a single
1152 * After that, we cache every node we visit, using a single
1075 * scan amortized over multiple lookups. This gives the best
1153 * scan amortized over multiple lookups. This gives the best
1076 * bulk performance, e.g. for "hg log".
1154 * bulk performance, e.g. for "hg log".
1077 */
1155 */
1078 if (self->ntmisses++ < 4) {
1156 if (self->ntmisses++ < 4) {
1079 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1157 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1080 const char *n = index_node(self, rev);
1158 const char *n = index_node(self, rev);
1081 if (n == NULL)
1159 if (n == NULL)
1082 return -2;
1160 return -2;
1083 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1161 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1084 if (nt_insert(self, n, rev) == -1)
1162 if (nt_insert(self, n, rev) == -1)
1085 return -3;
1163 return -3;
1086 break;
1164 break;
1087 }
1165 }
1088 }
1166 }
1089 } else {
1167 } else {
1090 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1168 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1091 const char *n = index_node(self, rev);
1169 const char *n = index_node(self, rev);
1092 if (n == NULL) {
1170 if (n == NULL) {
1093 self->ntrev = rev + 1;
1171 self->ntrev = rev + 1;
1094 return -2;
1172 return -2;
1095 }
1173 }
1096 if (nt_insert(self, n, rev) == -1) {
1174 if (nt_insert(self, n, rev) == -1) {
1097 self->ntrev = rev + 1;
1175 self->ntrev = rev + 1;
1098 return -3;
1176 return -3;
1099 }
1177 }
1100 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1178 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1101 break;
1179 break;
1102 }
1180 }
1103 }
1181 }
1104 self->ntrev = rev;
1182 self->ntrev = rev;
1105 }
1183 }
1106
1184
1107 if (rev >= 0)
1185 if (rev >= 0)
1108 return rev;
1186 return rev;
1109 return -2;
1187 return -2;
1110 }
1188 }
1111
1189
1112 static PyObject *raise_revlog_error(void)
1190 static PyObject *raise_revlog_error(void)
1113 {
1191 {
1114 static PyObject *errclass;
1192 static PyObject *errclass;
1115 PyObject *mod = NULL, *errobj;
1193 PyObject *mod = NULL, *errobj;
1116
1194
1117 if (errclass == NULL) {
1195 if (errclass == NULL) {
1118 PyObject *dict;
1196 PyObject *dict;
1119
1197
1120 mod = PyImport_ImportModule("mercurial.error");
1198 mod = PyImport_ImportModule("mercurial.error");
1121 if (mod == NULL)
1199 if (mod == NULL)
1122 goto classfail;
1200 goto classfail;
1123
1201
1124 dict = PyModule_GetDict(mod);
1202 dict = PyModule_GetDict(mod);
1125 if (dict == NULL)
1203 if (dict == NULL)
1126 goto classfail;
1204 goto classfail;
1127
1205
1128 errclass = PyDict_GetItemString(dict, "RevlogError");
1206 errclass = PyDict_GetItemString(dict, "RevlogError");
1129 if (errclass == NULL) {
1207 if (errclass == NULL) {
1130 PyErr_SetString(PyExc_SystemError,
1208 PyErr_SetString(PyExc_SystemError,
1131 "could not find RevlogError");
1209 "could not find RevlogError");
1132 goto classfail;
1210 goto classfail;
1133 }
1211 }
1134 Py_INCREF(errclass);
1212 Py_INCREF(errclass);
1135 }
1213 }
1136
1214
1137 errobj = PyObject_CallFunction(errclass, NULL);
1215 errobj = PyObject_CallFunction(errclass, NULL);
1138 if (errobj == NULL)
1216 if (errobj == NULL)
1139 return NULL;
1217 return NULL;
1140 PyErr_SetObject(errclass, errobj);
1218 PyErr_SetObject(errclass, errobj);
1141 return errobj;
1219 return errobj;
1142
1220
1143 classfail:
1221 classfail:
1144 Py_XDECREF(mod);
1222 Py_XDECREF(mod);
1145 return NULL;
1223 return NULL;
1146 }
1224 }
1147
1225
1148 static PyObject *index_getitem(indexObject *self, PyObject *value)
1226 static PyObject *index_getitem(indexObject *self, PyObject *value)
1149 {
1227 {
1150 char *node;
1228 char *node;
1151 Py_ssize_t nodelen;
1229 Py_ssize_t nodelen;
1152 int rev;
1230 int rev;
1153
1231
1154 if (PyInt_Check(value))
1232 if (PyInt_Check(value))
1155 return index_get(self, PyInt_AS_LONG(value));
1233 return index_get(self, PyInt_AS_LONG(value));
1156
1234
1157 if (node_check(value, &node, &nodelen) == -1)
1235 if (node_check(value, &node, &nodelen) == -1)
1158 return NULL;
1236 return NULL;
1159 rev = index_find_node(self, node, nodelen);
1237 rev = index_find_node(self, node, nodelen);
1160 if (rev >= -1)
1238 if (rev >= -1)
1161 return PyInt_FromLong(rev);
1239 return PyInt_FromLong(rev);
1162 if (rev == -2)
1240 if (rev == -2)
1163 raise_revlog_error();
1241 raise_revlog_error();
1164 return NULL;
1242 return NULL;
1165 }
1243 }
1166
1244
1167 static int nt_partialmatch(indexObject *self, const char *node,
1245 static int nt_partialmatch(indexObject *self, const char *node,
1168 Py_ssize_t nodelen)
1246 Py_ssize_t nodelen)
1169 {
1247 {
1170 int rev;
1248 int rev;
1171
1249
1172 if (nt_init(self) == -1)
1250 if (nt_init(self) == -1)
1173 return -3;
1251 return -3;
1174
1252
1175 if (self->ntrev > 0) {
1253 if (self->ntrev > 0) {
1176 /* ensure that the radix tree is fully populated */
1254 /* ensure that the radix tree is fully populated */
1177 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1255 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1178 const char *n = index_node(self, rev);
1256 const char *n = index_node(self, rev);
1179 if (n == NULL)
1257 if (n == NULL)
1180 return -2;
1258 return -2;
1181 if (nt_insert(self, n, rev) == -1)
1259 if (nt_insert(self, n, rev) == -1)
1182 return -3;
1260 return -3;
1183 }
1261 }
1184 self->ntrev = rev;
1262 self->ntrev = rev;
1185 }
1263 }
1186
1264
1187 return nt_find(self, node, nodelen, 1);
1265 return nt_find(self, node, nodelen, 1);
1188 }
1266 }
1189
1267
1190 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1268 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1191 {
1269 {
1192 const char *fullnode;
1270 const char *fullnode;
1193 int nodelen;
1271 int nodelen;
1194 char *node;
1272 char *node;
1195 int rev, i;
1273 int rev, i;
1196
1274
1197 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1275 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1198 return NULL;
1276 return NULL;
1199
1277
1200 if (nodelen < 4) {
1278 if (nodelen < 4) {
1201 PyErr_SetString(PyExc_ValueError, "key too short");
1279 PyErr_SetString(PyExc_ValueError, "key too short");
1202 return NULL;
1280 return NULL;
1203 }
1281 }
1204
1282
1205 if (nodelen > 40) {
1283 if (nodelen > 40) {
1206 PyErr_SetString(PyExc_ValueError, "key too long");
1284 PyErr_SetString(PyExc_ValueError, "key too long");
1207 return NULL;
1285 return NULL;
1208 }
1286 }
1209
1287
1210 for (i = 0; i < nodelen; i++)
1288 for (i = 0; i < nodelen; i++)
1211 hexdigit(node, i);
1289 hexdigit(node, i);
1212 if (PyErr_Occurred()) {
1290 if (PyErr_Occurred()) {
1213 /* input contains non-hex characters */
1291 /* input contains non-hex characters */
1214 PyErr_Clear();
1292 PyErr_Clear();
1215 Py_RETURN_NONE;
1293 Py_RETURN_NONE;
1216 }
1294 }
1217
1295
1218 rev = nt_partialmatch(self, node, nodelen);
1296 rev = nt_partialmatch(self, node, nodelen);
1219
1297
1220 switch (rev) {
1298 switch (rev) {
1221 case -4:
1299 case -4:
1222 raise_revlog_error();
1300 raise_revlog_error();
1223 case -3:
1301 case -3:
1224 return NULL;
1302 return NULL;
1225 case -2:
1303 case -2:
1226 Py_RETURN_NONE;
1304 Py_RETURN_NONE;
1227 case -1:
1305 case -1:
1228 return PyString_FromStringAndSize(nullid, 20);
1306 return PyString_FromStringAndSize(nullid, 20);
1229 }
1307 }
1230
1308
1231 fullnode = index_node(self, rev);
1309 fullnode = index_node(self, rev);
1232 if (fullnode == NULL) {
1310 if (fullnode == NULL) {
1233 PyErr_Format(PyExc_IndexError,
1311 PyErr_Format(PyExc_IndexError,
1234 "could not access rev %d", rev);
1312 "could not access rev %d", rev);
1235 return NULL;
1313 return NULL;
1236 }
1314 }
1237 return PyString_FromStringAndSize(fullnode, 20);
1315 return PyString_FromStringAndSize(fullnode, 20);
1238 }
1316 }
1239
1317
1240 static PyObject *index_m_get(indexObject *self, PyObject *args)
1318 static PyObject *index_m_get(indexObject *self, PyObject *args)
1241 {
1319 {
1242 Py_ssize_t nodelen;
1320 Py_ssize_t nodelen;
1243 PyObject *val;
1321 PyObject *val;
1244 char *node;
1322 char *node;
1245 int rev;
1323 int rev;
1246
1324
1247 if (!PyArg_ParseTuple(args, "O", &val))
1325 if (!PyArg_ParseTuple(args, "O", &val))
1248 return NULL;
1326 return NULL;
1249 if (node_check(val, &node, &nodelen) == -1)
1327 if (node_check(val, &node, &nodelen) == -1)
1250 return NULL;
1328 return NULL;
1251 rev = index_find_node(self, node, nodelen);
1329 rev = index_find_node(self, node, nodelen);
1252 if (rev == -3)
1330 if (rev == -3)
1253 return NULL;
1331 return NULL;
1254 if (rev == -2)
1332 if (rev == -2)
1255 Py_RETURN_NONE;
1333 Py_RETURN_NONE;
1256 return PyInt_FromLong(rev);
1334 return PyInt_FromLong(rev);
1257 }
1335 }
1258
1336
1259 static int index_contains(indexObject *self, PyObject *value)
1337 static int index_contains(indexObject *self, PyObject *value)
1260 {
1338 {
1261 char *node;
1339 char *node;
1262 Py_ssize_t nodelen;
1340 Py_ssize_t nodelen;
1263
1341
1264 if (PyInt_Check(value)) {
1342 if (PyInt_Check(value)) {
1265 long rev = PyInt_AS_LONG(value);
1343 long rev = PyInt_AS_LONG(value);
1266 return rev >= -1 && rev < index_length(self);
1344 return rev >= -1 && rev < index_length(self);
1267 }
1345 }
1268
1346
1269 if (node_check(value, &node, &nodelen) == -1)
1347 if (node_check(value, &node, &nodelen) == -1)
1270 return -1;
1348 return -1;
1271
1349
1272 switch (index_find_node(self, node, nodelen)) {
1350 switch (index_find_node(self, node, nodelen)) {
1273 case -3:
1351 case -3:
1274 return -1;
1352 return -1;
1275 case -2:
1353 case -2:
1276 return 0;
1354 return 0;
1277 default:
1355 default:
1278 return 1;
1356 return 1;
1279 }
1357 }
1280 }
1358 }
1281
1359
1282 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1360 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1283 {
1361 {
1284 if (rev >= self->length - 1) {
1362 if (rev >= self->length - 1) {
1285 PyObject *tuple = PyList_GET_ITEM(self->added,
1363 PyObject *tuple = PyList_GET_ITEM(self->added,
1286 rev - self->length + 1);
1364 rev - self->length + 1);
1287 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1365 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1288 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1366 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1289 } else {
1367 } else {
1290 const char *data = index_deref(self, rev);
1368 const char *data = index_deref(self, rev);
1291 ps[0] = getbe32(data + 24);
1369 ps[0] = getbe32(data + 24);
1292 ps[1] = getbe32(data + 28);
1370 ps[1] = getbe32(data + 28);
1293 }
1371 }
1294 }
1372 }
1295
1373
1296 typedef uint64_t bitmask;
1374 typedef uint64_t bitmask;
1297
1375
1298 /*
1376 /*
1299 * Given a disjoint set of revs, return all candidates for the
1377 * Given a disjoint set of revs, return all candidates for the
1300 * greatest common ancestor. In revset notation, this is the set
1378 * greatest common ancestor. In revset notation, this is the set
1301 * "heads(::a and ::b and ...)"
1379 * "heads(::a and ::b and ...)"
1302 */
1380 */
1303 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1381 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1304 int revcount)
1382 int revcount)
1305 {
1383 {
1306 const bitmask allseen = (1ull << revcount) - 1;
1384 const bitmask allseen = (1ull << revcount) - 1;
1307 const bitmask poison = 1ull << revcount;
1385 const bitmask poison = 1ull << revcount;
1308 PyObject *gca = PyList_New(0);
1386 PyObject *gca = PyList_New(0);
1309 int i, v, interesting;
1387 int i, v, interesting;
1310 int maxrev = -1;
1388 int maxrev = -1;
1311 bitmask sp;
1389 bitmask sp;
1312 bitmask *seen;
1390 bitmask *seen;
1313
1391
1314 if (gca == NULL)
1392 if (gca == NULL)
1315 return PyErr_NoMemory();
1393 return PyErr_NoMemory();
1316
1394
1317 for (i = 0; i < revcount; i++) {
1395 for (i = 0; i < revcount; i++) {
1318 if (revs[i] > maxrev)
1396 if (revs[i] > maxrev)
1319 maxrev = revs[i];
1397 maxrev = revs[i];
1320 }
1398 }
1321
1399
1322 seen = calloc(sizeof(*seen), maxrev + 1);
1400 seen = calloc(sizeof(*seen), maxrev + 1);
1323 if (seen == NULL) {
1401 if (seen == NULL) {
1324 Py_DECREF(gca);
1402 Py_DECREF(gca);
1325 return PyErr_NoMemory();
1403 return PyErr_NoMemory();
1326 }
1404 }
1327
1405
1328 for (i = 0; i < revcount; i++)
1406 for (i = 0; i < revcount; i++)
1329 seen[revs[i]] = 1ull << i;
1407 seen[revs[i]] = 1ull << i;
1330
1408
1331 interesting = revcount;
1409 interesting = revcount;
1332
1410
1333 for (v = maxrev; v >= 0 && interesting; v--) {
1411 for (v = maxrev; v >= 0 && interesting; v--) {
1334 bitmask sv = seen[v];
1412 bitmask sv = seen[v];
1335 int parents[2];
1413 int parents[2];
1336
1414
1337 if (!sv)
1415 if (!sv)
1338 continue;
1416 continue;
1339
1417
1340 if (sv < poison) {
1418 if (sv < poison) {
1341 interesting -= 1;
1419 interesting -= 1;
1342 if (sv == allseen) {
1420 if (sv == allseen) {
1343 PyObject *obj = PyInt_FromLong(v);
1421 PyObject *obj = PyInt_FromLong(v);
1344 if (obj == NULL)
1422 if (obj == NULL)
1345 goto bail;
1423 goto bail;
1346 if (PyList_Append(gca, obj) == -1) {
1424 if (PyList_Append(gca, obj) == -1) {
1347 Py_DECREF(obj);
1425 Py_DECREF(obj);
1348 goto bail;
1426 goto bail;
1349 }
1427 }
1350 sv |= poison;
1428 sv |= poison;
1351 for (i = 0; i < revcount; i++) {
1429 for (i = 0; i < revcount; i++) {
1352 if (revs[i] == v)
1430 if (revs[i] == v)
1353 goto done;
1431 goto done;
1354 }
1432 }
1355 }
1433 }
1356 }
1434 }
1357 index_get_parents(self, v, parents);
1435 index_get_parents(self, v, parents);
1358
1436
1359 for (i = 0; i < 2; i++) {
1437 for (i = 0; i < 2; i++) {
1360 int p = parents[i];
1438 int p = parents[i];
1361 if (p == -1)
1439 if (p == -1)
1362 continue;
1440 continue;
1363 sp = seen[p];
1441 sp = seen[p];
1364 if (sv < poison) {
1442 if (sv < poison) {
1365 if (sp == 0) {
1443 if (sp == 0) {
1366 seen[p] = sv;
1444 seen[p] = sv;
1367 interesting++;
1445 interesting++;
1368 }
1446 }
1369 else if (sp != sv)
1447 else if (sp != sv)
1370 seen[p] |= sv;
1448 seen[p] |= sv;
1371 } else {
1449 } else {
1372 if (sp && sp < poison)
1450 if (sp && sp < poison)
1373 interesting--;
1451 interesting--;
1374 seen[p] = sv;
1452 seen[p] = sv;
1375 }
1453 }
1376 }
1454 }
1377 }
1455 }
1378
1456
1379 done:
1457 done:
1380 free(seen);
1458 free(seen);
1381 return gca;
1459 return gca;
1382 bail:
1460 bail:
1383 free(seen);
1461 free(seen);
1384 Py_XDECREF(gca);
1462 Py_XDECREF(gca);
1385 return NULL;
1463 return NULL;
1386 }
1464 }
1387
1465
1388 /*
1466 /*
1389 * Given a disjoint set of revs, return the subset with the longest
1467 * Given a disjoint set of revs, return the subset with the longest
1390 * path to the root.
1468 * path to the root.
1391 */
1469 */
1392 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1470 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1393 {
1471 {
1394 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1472 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1395 static const Py_ssize_t capacity = 24;
1473 static const Py_ssize_t capacity = 24;
1396 int *depth, *interesting = NULL;
1474 int *depth, *interesting = NULL;
1397 int i, j, v, ninteresting;
1475 int i, j, v, ninteresting;
1398 PyObject *dict = NULL, *keys = NULL;
1476 PyObject *dict = NULL, *keys = NULL;
1399 long *seen = NULL;
1477 long *seen = NULL;
1400 int maxrev = -1;
1478 int maxrev = -1;
1401 long final;
1479 long final;
1402
1480
1403 if (revcount > capacity) {
1481 if (revcount > capacity) {
1404 PyErr_Format(PyExc_OverflowError,
1482 PyErr_Format(PyExc_OverflowError,
1405 "bitset size (%ld) > capacity (%ld)",
1483 "bitset size (%ld) > capacity (%ld)",
1406 (long)revcount, (long)capacity);
1484 (long)revcount, (long)capacity);
1407 return NULL;
1485 return NULL;
1408 }
1486 }
1409
1487
1410 for (i = 0; i < revcount; i++) {
1488 for (i = 0; i < revcount; i++) {
1411 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1489 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1412 if (n > maxrev)
1490 if (n > maxrev)
1413 maxrev = n;
1491 maxrev = n;
1414 }
1492 }
1415
1493
1416 depth = calloc(sizeof(*depth), maxrev + 1);
1494 depth = calloc(sizeof(*depth), maxrev + 1);
1417 if (depth == NULL)
1495 if (depth == NULL)
1418 return PyErr_NoMemory();
1496 return PyErr_NoMemory();
1419
1497
1420 seen = calloc(sizeof(*seen), maxrev + 1);
1498 seen = calloc(sizeof(*seen), maxrev + 1);
1421 if (seen == NULL) {
1499 if (seen == NULL) {
1422 PyErr_NoMemory();
1500 PyErr_NoMemory();
1423 goto bail;
1501 goto bail;
1424 }
1502 }
1425
1503
1426 interesting = calloc(sizeof(*interesting), 2 << revcount);
1504 interesting = calloc(sizeof(*interesting), 2 << revcount);
1427 if (interesting == NULL) {
1505 if (interesting == NULL) {
1428 PyErr_NoMemory();
1506 PyErr_NoMemory();
1429 goto bail;
1507 goto bail;
1430 }
1508 }
1431
1509
1432 if (PyList_Sort(revs) == -1)
1510 if (PyList_Sort(revs) == -1)
1433 goto bail;
1511 goto bail;
1434
1512
1435 for (i = 0; i < revcount; i++) {
1513 for (i = 0; i < revcount; i++) {
1436 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1514 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1437 long b = 1l << i;
1515 long b = 1l << i;
1438 depth[n] = 1;
1516 depth[n] = 1;
1439 seen[n] = b;
1517 seen[n] = b;
1440 interesting[b] = 1;
1518 interesting[b] = 1;
1441 }
1519 }
1442
1520
1443 ninteresting = (int)revcount;
1521 ninteresting = (int)revcount;
1444
1522
1445 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1523 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1446 int dv = depth[v];
1524 int dv = depth[v];
1447 int parents[2];
1525 int parents[2];
1448 long sv;
1526 long sv;
1449
1527
1450 if (dv == 0)
1528 if (dv == 0)
1451 continue;
1529 continue;
1452
1530
1453 sv = seen[v];
1531 sv = seen[v];
1454 index_get_parents(self, v, parents);
1532 index_get_parents(self, v, parents);
1455
1533
1456 for (i = 0; i < 2; i++) {
1534 for (i = 0; i < 2; i++) {
1457 int p = parents[i];
1535 int p = parents[i];
1458 long nsp, sp;
1536 long nsp, sp;
1459 int dp;
1537 int dp;
1460
1538
1461 if (p == -1)
1539 if (p == -1)
1462 continue;
1540 continue;
1463
1541
1464 dp = depth[p];
1542 dp = depth[p];
1465 nsp = sp = seen[p];
1543 nsp = sp = seen[p];
1466 if (dp <= dv) {
1544 if (dp <= dv) {
1467 depth[p] = dv + 1;
1545 depth[p] = dv + 1;
1468 if (sp != sv) {
1546 if (sp != sv) {
1469 interesting[sv] += 1;
1547 interesting[sv] += 1;
1470 nsp = seen[p] = sv;
1548 nsp = seen[p] = sv;
1471 if (sp) {
1549 if (sp) {
1472 interesting[sp] -= 1;
1550 interesting[sp] -= 1;
1473 if (interesting[sp] == 0)
1551 if (interesting[sp] == 0)
1474 ninteresting -= 1;
1552 ninteresting -= 1;
1475 }
1553 }
1476 }
1554 }
1477 }
1555 }
1478 else if (dv == dp - 1) {
1556 else if (dv == dp - 1) {
1479 nsp = sp | sv;
1557 nsp = sp | sv;
1480 if (nsp == sp)
1558 if (nsp == sp)
1481 continue;
1559 continue;
1482 seen[p] = nsp;
1560 seen[p] = nsp;
1483 interesting[sp] -= 1;
1561 interesting[sp] -= 1;
1484 if (interesting[sp] == 0 && interesting[nsp] > 0)
1562 if (interesting[sp] == 0 && interesting[nsp] > 0)
1485 ninteresting -= 1;
1563 ninteresting -= 1;
1486 interesting[nsp] += 1;
1564 interesting[nsp] += 1;
1487 }
1565 }
1488 }
1566 }
1489 interesting[sv] -= 1;
1567 interesting[sv] -= 1;
1490 if (interesting[sv] == 0)
1568 if (interesting[sv] == 0)
1491 ninteresting -= 1;
1569 ninteresting -= 1;
1492 }
1570 }
1493
1571
1494 final = 0;
1572 final = 0;
1495 j = ninteresting;
1573 j = ninteresting;
1496 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1574 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1497 if (interesting[i] == 0)
1575 if (interesting[i] == 0)
1498 continue;
1576 continue;
1499 final |= i;
1577 final |= i;
1500 j -= 1;
1578 j -= 1;
1501 }
1579 }
1502 if (final == 0) {
1580 if (final == 0) {
1503 keys = PyList_New(0);
1581 keys = PyList_New(0);
1504 goto bail;
1582 goto bail;
1505 }
1583 }
1506
1584
1507 dict = PyDict_New();
1585 dict = PyDict_New();
1508 if (dict == NULL)
1586 if (dict == NULL)
1509 goto bail;
1587 goto bail;
1510
1588
1511 for (i = 0; i < revcount; i++) {
1589 for (i = 0; i < revcount; i++) {
1512 PyObject *key;
1590 PyObject *key;
1513
1591
1514 if ((final & (1 << i)) == 0)
1592 if ((final & (1 << i)) == 0)
1515 continue;
1593 continue;
1516
1594
1517 key = PyList_GET_ITEM(revs, i);
1595 key = PyList_GET_ITEM(revs, i);
1518 Py_INCREF(key);
1596 Py_INCREF(key);
1519 Py_INCREF(Py_None);
1597 Py_INCREF(Py_None);
1520 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1598 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1521 Py_DECREF(key);
1599 Py_DECREF(key);
1522 Py_DECREF(Py_None);
1600 Py_DECREF(Py_None);
1523 goto bail;
1601 goto bail;
1524 }
1602 }
1525 }
1603 }
1526
1604
1527 keys = PyDict_Keys(dict);
1605 keys = PyDict_Keys(dict);
1528
1606
1529 bail:
1607 bail:
1530 free(depth);
1608 free(depth);
1531 free(seen);
1609 free(seen);
1532 free(interesting);
1610 free(interesting);
1533 Py_XDECREF(dict);
1611 Py_XDECREF(dict);
1534
1612
1535 return keys;
1613 return keys;
1536 }
1614 }
1537
1615
1538 /*
1616 /*
1539 * Given a (possibly overlapping) set of revs, return the greatest
1617 * Given a (possibly overlapping) set of revs, return the greatest
1540 * common ancestors: those with the longest path to the root.
1618 * common ancestors: those with the longest path to the root.
1541 */
1619 */
1542 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1620 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1543 {
1621 {
1544 PyObject *ret = NULL, *gca = NULL;
1622 PyObject *ret = NULL, *gca = NULL;
1545 Py_ssize_t argcount, i, len;
1623 Py_ssize_t argcount, i, len;
1546 bitmask repeat = 0;
1624 bitmask repeat = 0;
1547 int revcount = 0;
1625 int revcount = 0;
1548 int *revs;
1626 int *revs;
1549
1627
1550 argcount = PySequence_Length(args);
1628 argcount = PySequence_Length(args);
1551 revs = malloc(argcount * sizeof(*revs));
1629 revs = malloc(argcount * sizeof(*revs));
1552 if (argcount > 0 && revs == NULL)
1630 if (argcount > 0 && revs == NULL)
1553 return PyErr_NoMemory();
1631 return PyErr_NoMemory();
1554 len = index_length(self) - 1;
1632 len = index_length(self) - 1;
1555
1633
1556 for (i = 0; i < argcount; i++) {
1634 for (i = 0; i < argcount; i++) {
1557 static const int capacity = 24;
1635 static const int capacity = 24;
1558 PyObject *obj = PySequence_GetItem(args, i);
1636 PyObject *obj = PySequence_GetItem(args, i);
1559 bitmask x;
1637 bitmask x;
1560 long val;
1638 long val;
1561
1639
1562 if (!PyInt_Check(obj)) {
1640 if (!PyInt_Check(obj)) {
1563 PyErr_SetString(PyExc_TypeError,
1641 PyErr_SetString(PyExc_TypeError,
1564 "arguments must all be ints");
1642 "arguments must all be ints");
1565 goto bail;
1643 goto bail;
1566 }
1644 }
1567 val = PyInt_AsLong(obj);
1645 val = PyInt_AsLong(obj);
1568 if (val == -1) {
1646 if (val == -1) {
1569 ret = PyList_New(0);
1647 ret = PyList_New(0);
1570 goto done;
1648 goto done;
1571 }
1649 }
1572 if (val < 0 || val >= len) {
1650 if (val < 0 || val >= len) {
1573 PyErr_SetString(PyExc_IndexError,
1651 PyErr_SetString(PyExc_IndexError,
1574 "index out of range");
1652 "index out of range");
1575 goto bail;
1653 goto bail;
1576 }
1654 }
1577 /* this cheesy bloom filter lets us avoid some more
1655 /* this cheesy bloom filter lets us avoid some more
1578 * expensive duplicate checks in the common set-is-disjoint
1656 * expensive duplicate checks in the common set-is-disjoint
1579 * case */
1657 * case */
1580 x = 1ull << (val & 0x3f);
1658 x = 1ull << (val & 0x3f);
1581 if (repeat & x) {
1659 if (repeat & x) {
1582 int k;
1660 int k;
1583 for (k = 0; k < revcount; k++) {
1661 for (k = 0; k < revcount; k++) {
1584 if (val == revs[k])
1662 if (val == revs[k])
1585 goto duplicate;
1663 goto duplicate;
1586 }
1664 }
1587 }
1665 }
1588 else repeat |= x;
1666 else repeat |= x;
1589 if (revcount >= capacity) {
1667 if (revcount >= capacity) {
1590 PyErr_Format(PyExc_OverflowError,
1668 PyErr_Format(PyExc_OverflowError,
1591 "bitset size (%d) > capacity (%d)",
1669 "bitset size (%d) > capacity (%d)",
1592 revcount, capacity);
1670 revcount, capacity);
1593 goto bail;
1671 goto bail;
1594 }
1672 }
1595 revs[revcount++] = (int)val;
1673 revs[revcount++] = (int)val;
1596 duplicate:;
1674 duplicate:;
1597 }
1675 }
1598
1676
1599 if (revcount == 0) {
1677 if (revcount == 0) {
1600 ret = PyList_New(0);
1678 ret = PyList_New(0);
1601 goto done;
1679 goto done;
1602 }
1680 }
1603 if (revcount == 1) {
1681 if (revcount == 1) {
1604 PyObject *obj;
1682 PyObject *obj;
1605 ret = PyList_New(1);
1683 ret = PyList_New(1);
1606 if (ret == NULL)
1684 if (ret == NULL)
1607 goto bail;
1685 goto bail;
1608 obj = PyInt_FromLong(revs[0]);
1686 obj = PyInt_FromLong(revs[0]);
1609 if (obj == NULL)
1687 if (obj == NULL)
1610 goto bail;
1688 goto bail;
1611 PyList_SET_ITEM(ret, 0, obj);
1689 PyList_SET_ITEM(ret, 0, obj);
1612 goto done;
1690 goto done;
1613 }
1691 }
1614
1692
1615 gca = find_gca_candidates(self, revs, revcount);
1693 gca = find_gca_candidates(self, revs, revcount);
1616 if (gca == NULL)
1694 if (gca == NULL)
1617 goto bail;
1695 goto bail;
1618
1696
1619 if (PyList_GET_SIZE(gca) <= 1) {
1697 if (PyList_GET_SIZE(gca) <= 1) {
1620 ret = gca;
1698 ret = gca;
1621 Py_INCREF(gca);
1699 Py_INCREF(gca);
1622 }
1700 }
1623 else ret = find_deepest(self, gca);
1701 else ret = find_deepest(self, gca);
1624
1702
1625 done:
1703 done:
1626 free(revs);
1704 free(revs);
1627 Py_XDECREF(gca);
1705 Py_XDECREF(gca);
1628
1706
1629 return ret;
1707 return ret;
1630
1708
1631 bail:
1709 bail:
1632 free(revs);
1710 free(revs);
1633 Py_XDECREF(gca);
1711 Py_XDECREF(gca);
1634 Py_XDECREF(ret);
1712 Py_XDECREF(ret);
1635 return NULL;
1713 return NULL;
1636 }
1714 }
1637
1715
1638 /*
1716 /*
1639 * Given a (possibly overlapping) set of revs, return all the
1717 * Given a (possibly overlapping) set of revs, return all the
1640 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1718 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1641 */
1719 */
1642 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1720 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1643 {
1721 {
1644 PyObject *ret = NULL;
1722 PyObject *ret = NULL;
1645 Py_ssize_t argcount, i, len;
1723 Py_ssize_t argcount, i, len;
1646 bitmask repeat = 0;
1724 bitmask repeat = 0;
1647 int revcount = 0;
1725 int revcount = 0;
1648 int *revs;
1726 int *revs;
1649
1727
1650 argcount = PySequence_Length(args);
1728 argcount = PySequence_Length(args);
1651 revs = malloc(argcount * sizeof(*revs));
1729 revs = malloc(argcount * sizeof(*revs));
1652 if (argcount > 0 && revs == NULL)
1730 if (argcount > 0 && revs == NULL)
1653 return PyErr_NoMemory();
1731 return PyErr_NoMemory();
1654 len = index_length(self) - 1;
1732 len = index_length(self) - 1;
1655
1733
1656 for (i = 0; i < argcount; i++) {
1734 for (i = 0; i < argcount; i++) {
1657 static const int capacity = 24;
1735 static const int capacity = 24;
1658 PyObject *obj = PySequence_GetItem(args, i);
1736 PyObject *obj = PySequence_GetItem(args, i);
1659 bitmask x;
1737 bitmask x;
1660 long val;
1738 long val;
1661
1739
1662 if (!PyInt_Check(obj)) {
1740 if (!PyInt_Check(obj)) {
1663 PyErr_SetString(PyExc_TypeError,
1741 PyErr_SetString(PyExc_TypeError,
1664 "arguments must all be ints");
1742 "arguments must all be ints");
1665 goto bail;
1743 goto bail;
1666 }
1744 }
1667 val = PyInt_AsLong(obj);
1745 val = PyInt_AsLong(obj);
1668 if (val == -1) {
1746 if (val == -1) {
1669 ret = PyList_New(0);
1747 ret = PyList_New(0);
1670 goto done;
1748 goto done;
1671 }
1749 }
1672 if (val < 0 || val >= len) {
1750 if (val < 0 || val >= len) {
1673 PyErr_SetString(PyExc_IndexError,
1751 PyErr_SetString(PyExc_IndexError,
1674 "index out of range");
1752 "index out of range");
1675 goto bail;
1753 goto bail;
1676 }
1754 }
1677 /* this cheesy bloom filter lets us avoid some more
1755 /* this cheesy bloom filter lets us avoid some more
1678 * expensive duplicate checks in the common set-is-disjoint
1756 * expensive duplicate checks in the common set-is-disjoint
1679 * case */
1757 * case */
1680 x = 1ull << (val & 0x3f);
1758 x = 1ull << (val & 0x3f);
1681 if (repeat & x) {
1759 if (repeat & x) {
1682 int k;
1760 int k;
1683 for (k = 0; k < revcount; k++) {
1761 for (k = 0; k < revcount; k++) {
1684 if (val == revs[k])
1762 if (val == revs[k])
1685 goto duplicate;
1763 goto duplicate;
1686 }
1764 }
1687 }
1765 }
1688 else repeat |= x;
1766 else repeat |= x;
1689 if (revcount >= capacity) {
1767 if (revcount >= capacity) {
1690 PyErr_Format(PyExc_OverflowError,
1768 PyErr_Format(PyExc_OverflowError,
1691 "bitset size (%d) > capacity (%d)",
1769 "bitset size (%d) > capacity (%d)",
1692 revcount, capacity);
1770 revcount, capacity);
1693 goto bail;
1771 goto bail;
1694 }
1772 }
1695 revs[revcount++] = (int)val;
1773 revs[revcount++] = (int)val;
1696 duplicate:;
1774 duplicate:;
1697 }
1775 }
1698
1776
1699 if (revcount == 0) {
1777 if (revcount == 0) {
1700 ret = PyList_New(0);
1778 ret = PyList_New(0);
1701 goto done;
1779 goto done;
1702 }
1780 }
1703 if (revcount == 1) {
1781 if (revcount == 1) {
1704 PyObject *obj;
1782 PyObject *obj;
1705 ret = PyList_New(1);
1783 ret = PyList_New(1);
1706 if (ret == NULL)
1784 if (ret == NULL)
1707 goto bail;
1785 goto bail;
1708 obj = PyInt_FromLong(revs[0]);
1786 obj = PyInt_FromLong(revs[0]);
1709 if (obj == NULL)
1787 if (obj == NULL)
1710 goto bail;
1788 goto bail;
1711 PyList_SET_ITEM(ret, 0, obj);
1789 PyList_SET_ITEM(ret, 0, obj);
1712 goto done;
1790 goto done;
1713 }
1791 }
1714
1792
1715 ret = find_gca_candidates(self, revs, revcount);
1793 ret = find_gca_candidates(self, revs, revcount);
1716 if (ret == NULL)
1794 if (ret == NULL)
1717 goto bail;
1795 goto bail;
1718
1796
1719 done:
1797 done:
1720 free(revs);
1798 free(revs);
1721 return ret;
1799 return ret;
1722
1800
1723 bail:
1801 bail:
1724 free(revs);
1802 free(revs);
1725 Py_XDECREF(ret);
1803 Py_XDECREF(ret);
1726 return NULL;
1804 return NULL;
1727 }
1805 }
1728
1806
1729 /*
1807 /*
1730 * Invalidate any trie entries introduced by added revs.
1808 * Invalidate any trie entries introduced by added revs.
1731 */
1809 */
1732 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1810 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1733 {
1811 {
1734 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1812 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1735
1813
1736 for (i = start; i < len; i++) {
1814 for (i = start; i < len; i++) {
1737 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1815 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1738 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1816 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1739
1817
1740 nt_insert(self, PyString_AS_STRING(node), -1);
1818 nt_insert(self, PyString_AS_STRING(node), -1);
1741 }
1819 }
1742
1820
1743 if (start == 0)
1821 if (start == 0)
1744 Py_CLEAR(self->added);
1822 Py_CLEAR(self->added);
1745 }
1823 }
1746
1824
1747 /*
1825 /*
1748 * Delete a numeric range of revs, which must be at the end of the
1826 * Delete a numeric range of revs, which must be at the end of the
1749 * range, but exclude the sentinel nullid entry.
1827 * range, but exclude the sentinel nullid entry.
1750 */
1828 */
1751 static int index_slice_del(indexObject *self, PyObject *item)
1829 static int index_slice_del(indexObject *self, PyObject *item)
1752 {
1830 {
1753 Py_ssize_t start, stop, step, slicelength;
1831 Py_ssize_t start, stop, step, slicelength;
1754 Py_ssize_t length = index_length(self);
1832 Py_ssize_t length = index_length(self);
1755 int ret = 0;
1833 int ret = 0;
1756
1834
1757 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1835 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1758 &start, &stop, &step, &slicelength) < 0)
1836 &start, &stop, &step, &slicelength) < 0)
1759 return -1;
1837 return -1;
1760
1838
1761 if (slicelength <= 0)
1839 if (slicelength <= 0)
1762 return 0;
1840 return 0;
1763
1841
1764 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1842 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1765 stop = start;
1843 stop = start;
1766
1844
1767 if (step < 0) {
1845 if (step < 0) {
1768 stop = start + 1;
1846 stop = start + 1;
1769 start = stop + step*(slicelength - 1) - 1;
1847 start = stop + step*(slicelength - 1) - 1;
1770 step = -step;
1848 step = -step;
1771 }
1849 }
1772
1850
1773 if (step != 1) {
1851 if (step != 1) {
1774 PyErr_SetString(PyExc_ValueError,
1852 PyErr_SetString(PyExc_ValueError,
1775 "revlog index delete requires step size of 1");
1853 "revlog index delete requires step size of 1");
1776 return -1;
1854 return -1;
1777 }
1855 }
1778
1856
1779 if (stop != length - 1) {
1857 if (stop != length - 1) {
1780 PyErr_SetString(PyExc_IndexError,
1858 PyErr_SetString(PyExc_IndexError,
1781 "revlog index deletion indices are invalid");
1859 "revlog index deletion indices are invalid");
1782 return -1;
1860 return -1;
1783 }
1861 }
1784
1862
1785 if (start < self->length - 1) {
1863 if (start < self->length - 1) {
1786 if (self->nt) {
1864 if (self->nt) {
1787 Py_ssize_t i;
1865 Py_ssize_t i;
1788
1866
1789 for (i = start + 1; i < self->length - 1; i++) {
1867 for (i = start + 1; i < self->length - 1; i++) {
1790 const char *node = index_node(self, i);
1868 const char *node = index_node(self, i);
1791
1869
1792 if (node)
1870 if (node)
1793 nt_insert(self, node, -1);
1871 nt_insert(self, node, -1);
1794 }
1872 }
1795 if (self->added)
1873 if (self->added)
1796 nt_invalidate_added(self, 0);
1874 nt_invalidate_added(self, 0);
1797 if (self->ntrev > start)
1875 if (self->ntrev > start)
1798 self->ntrev = (int)start;
1876 self->ntrev = (int)start;
1799 }
1877 }
1800 self->length = start + 1;
1878 self->length = start + 1;
1801 if (start < self->raw_length) {
1879 if (start < self->raw_length) {
1802 if (self->cache) {
1880 if (self->cache) {
1803 Py_ssize_t i;
1881 Py_ssize_t i;
1804 for (i = start; i < self->raw_length; i++)
1882 for (i = start; i < self->raw_length; i++)
1805 Py_CLEAR(self->cache[i]);
1883 Py_CLEAR(self->cache[i]);
1806 }
1884 }
1807 self->raw_length = start;
1885 self->raw_length = start;
1808 }
1886 }
1809 goto done;
1887 goto done;
1810 }
1888 }
1811
1889
1812 if (self->nt) {
1890 if (self->nt) {
1813 nt_invalidate_added(self, start - self->length + 1);
1891 nt_invalidate_added(self, start - self->length + 1);
1814 if (self->ntrev > start)
1892 if (self->ntrev > start)
1815 self->ntrev = (int)start;
1893 self->ntrev = (int)start;
1816 }
1894 }
1817 if (self->added)
1895 if (self->added)
1818 ret = PyList_SetSlice(self->added, start - self->length + 1,
1896 ret = PyList_SetSlice(self->added, start - self->length + 1,
1819 PyList_GET_SIZE(self->added), NULL);
1897 PyList_GET_SIZE(self->added), NULL);
1820 done:
1898 done:
1821 Py_CLEAR(self->headrevs);
1899 Py_CLEAR(self->headrevs);
1822 return ret;
1900 return ret;
1823 }
1901 }
1824
1902
1825 /*
1903 /*
1826 * Supported ops:
1904 * Supported ops:
1827 *
1905 *
1828 * slice deletion
1906 * slice deletion
1829 * string assignment (extend node->rev mapping)
1907 * string assignment (extend node->rev mapping)
1830 * string deletion (shrink node->rev mapping)
1908 * string deletion (shrink node->rev mapping)
1831 */
1909 */
1832 static int index_assign_subscript(indexObject *self, PyObject *item,
1910 static int index_assign_subscript(indexObject *self, PyObject *item,
1833 PyObject *value)
1911 PyObject *value)
1834 {
1912 {
1835 char *node;
1913 char *node;
1836 Py_ssize_t nodelen;
1914 Py_ssize_t nodelen;
1837 long rev;
1915 long rev;
1838
1916
1839 if (PySlice_Check(item) && value == NULL)
1917 if (PySlice_Check(item) && value == NULL)
1840 return index_slice_del(self, item);
1918 return index_slice_del(self, item);
1841
1919
1842 if (node_check(item, &node, &nodelen) == -1)
1920 if (node_check(item, &node, &nodelen) == -1)
1843 return -1;
1921 return -1;
1844
1922
1845 if (value == NULL)
1923 if (value == NULL)
1846 return self->nt ? nt_insert(self, node, -1) : 0;
1924 return self->nt ? nt_insert(self, node, -1) : 0;
1847 rev = PyInt_AsLong(value);
1925 rev = PyInt_AsLong(value);
1848 if (rev > INT_MAX || rev < 0) {
1926 if (rev > INT_MAX || rev < 0) {
1849 if (!PyErr_Occurred())
1927 if (!PyErr_Occurred())
1850 PyErr_SetString(PyExc_ValueError, "rev out of range");
1928 PyErr_SetString(PyExc_ValueError, "rev out of range");
1851 return -1;
1929 return -1;
1852 }
1930 }
1853 return nt_insert(self, node, (int)rev);
1931 return nt_insert(self, node, (int)rev);
1854 }
1932 }
1855
1933
1856 /*
1934 /*
1857 * Find all RevlogNG entries in an index that has inline data. Update
1935 * Find all RevlogNG entries in an index that has inline data. Update
1858 * the optional "offsets" table with those entries.
1936 * the optional "offsets" table with those entries.
1859 */
1937 */
1860 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
1938 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
1861 {
1939 {
1862 const char *data = PyString_AS_STRING(self->data);
1940 const char *data = PyString_AS_STRING(self->data);
1863 Py_ssize_t pos = 0;
1941 Py_ssize_t pos = 0;
1864 Py_ssize_t end = PyString_GET_SIZE(self->data);
1942 Py_ssize_t end = PyString_GET_SIZE(self->data);
1865 long incr = v1_hdrsize;
1943 long incr = v1_hdrsize;
1866 Py_ssize_t len = 0;
1944 Py_ssize_t len = 0;
1867
1945
1868 while (pos + v1_hdrsize <= end && pos >= 0) {
1946 while (pos + v1_hdrsize <= end && pos >= 0) {
1869 uint32_t comp_len;
1947 uint32_t comp_len;
1870 /* 3rd element of header is length of compressed inline data */
1948 /* 3rd element of header is length of compressed inline data */
1871 comp_len = getbe32(data + pos + 8);
1949 comp_len = getbe32(data + pos + 8);
1872 incr = v1_hdrsize + comp_len;
1950 incr = v1_hdrsize + comp_len;
1873 if (offsets)
1951 if (offsets)
1874 offsets[len] = data + pos;
1952 offsets[len] = data + pos;
1875 len++;
1953 len++;
1876 pos += incr;
1954 pos += incr;
1877 }
1955 }
1878
1956
1879 if (pos != end) {
1957 if (pos != end) {
1880 if (!PyErr_Occurred())
1958 if (!PyErr_Occurred())
1881 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1959 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1882 return -1;
1960 return -1;
1883 }
1961 }
1884
1962
1885 return len;
1963 return len;
1886 }
1964 }
1887
1965
1888 static int index_init(indexObject *self, PyObject *args)
1966 static int index_init(indexObject *self, PyObject *args)
1889 {
1967 {
1890 PyObject *data_obj, *inlined_obj;
1968 PyObject *data_obj, *inlined_obj;
1891 Py_ssize_t size;
1969 Py_ssize_t size;
1892
1970
1893 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1971 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1894 self->raw_length = 0;
1972 self->raw_length = 0;
1895 self->added = NULL;
1973 self->added = NULL;
1896 self->cache = NULL;
1974 self->cache = NULL;
1897 self->data = NULL;
1975 self->data = NULL;
1898 self->headrevs = NULL;
1976 self->headrevs = NULL;
1977 self->filteredrevs = Py_None;
1978 Py_INCREF(Py_None);
1899 self->nt = NULL;
1979 self->nt = NULL;
1900 self->offsets = NULL;
1980 self->offsets = NULL;
1901
1981
1902 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1982 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1903 return -1;
1983 return -1;
1904 if (!PyString_Check(data_obj)) {
1984 if (!PyString_Check(data_obj)) {
1905 PyErr_SetString(PyExc_TypeError, "data is not a string");
1985 PyErr_SetString(PyExc_TypeError, "data is not a string");
1906 return -1;
1986 return -1;
1907 }
1987 }
1908 size = PyString_GET_SIZE(data_obj);
1988 size = PyString_GET_SIZE(data_obj);
1909
1989
1910 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1990 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1911 self->data = data_obj;
1991 self->data = data_obj;
1912
1992
1913 self->ntlength = self->ntcapacity = 0;
1993 self->ntlength = self->ntcapacity = 0;
1914 self->ntdepth = self->ntsplits = 0;
1994 self->ntdepth = self->ntsplits = 0;
1915 self->ntlookups = self->ntmisses = 0;
1995 self->ntlookups = self->ntmisses = 0;
1916 self->ntrev = -1;
1996 self->ntrev = -1;
1917 Py_INCREF(self->data);
1997 Py_INCREF(self->data);
1918
1998
1919 if (self->inlined) {
1999 if (self->inlined) {
1920 Py_ssize_t len = inline_scan(self, NULL);
2000 Py_ssize_t len = inline_scan(self, NULL);
1921 if (len == -1)
2001 if (len == -1)
1922 goto bail;
2002 goto bail;
1923 self->raw_length = len;
2003 self->raw_length = len;
1924 self->length = len + 1;
2004 self->length = len + 1;
1925 } else {
2005 } else {
1926 if (size % v1_hdrsize) {
2006 if (size % v1_hdrsize) {
1927 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2007 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1928 goto bail;
2008 goto bail;
1929 }
2009 }
1930 self->raw_length = size / v1_hdrsize;
2010 self->raw_length = size / v1_hdrsize;
1931 self->length = self->raw_length + 1;
2011 self->length = self->raw_length + 1;
1932 }
2012 }
1933
2013
1934 return 0;
2014 return 0;
1935 bail:
2015 bail:
1936 return -1;
2016 return -1;
1937 }
2017 }
1938
2018
1939 static PyObject *index_nodemap(indexObject *self)
2019 static PyObject *index_nodemap(indexObject *self)
1940 {
2020 {
1941 Py_INCREF(self);
2021 Py_INCREF(self);
1942 return (PyObject *)self;
2022 return (PyObject *)self;
1943 }
2023 }
1944
2024
1945 static void index_dealloc(indexObject *self)
2025 static void index_dealloc(indexObject *self)
1946 {
2026 {
1947 _index_clearcaches(self);
2027 _index_clearcaches(self);
2028 Py_XDECREF(self->filteredrevs);
1948 Py_XDECREF(self->data);
2029 Py_XDECREF(self->data);
1949 Py_XDECREF(self->added);
2030 Py_XDECREF(self->added);
1950 PyObject_Del(self);
2031 PyObject_Del(self);
1951 }
2032 }
1952
2033
1953 static PySequenceMethods index_sequence_methods = {
2034 static PySequenceMethods index_sequence_methods = {
1954 (lenfunc)index_length, /* sq_length */
2035 (lenfunc)index_length, /* sq_length */
1955 0, /* sq_concat */
2036 0, /* sq_concat */
1956 0, /* sq_repeat */
2037 0, /* sq_repeat */
1957 (ssizeargfunc)index_get, /* sq_item */
2038 (ssizeargfunc)index_get, /* sq_item */
1958 0, /* sq_slice */
2039 0, /* sq_slice */
1959 0, /* sq_ass_item */
2040 0, /* sq_ass_item */
1960 0, /* sq_ass_slice */
2041 0, /* sq_ass_slice */
1961 (objobjproc)index_contains, /* sq_contains */
2042 (objobjproc)index_contains, /* sq_contains */
1962 };
2043 };
1963
2044
1964 static PyMappingMethods index_mapping_methods = {
2045 static PyMappingMethods index_mapping_methods = {
1965 (lenfunc)index_length, /* mp_length */
2046 (lenfunc)index_length, /* mp_length */
1966 (binaryfunc)index_getitem, /* mp_subscript */
2047 (binaryfunc)index_getitem, /* mp_subscript */
1967 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2048 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1968 };
2049 };
1969
2050
1970 static PyMethodDef index_methods[] = {
2051 static PyMethodDef index_methods[] = {
1971 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2052 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1972 "return the gca set of the given revs"},
2053 "return the gca set of the given revs"},
1973 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2054 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1974 METH_VARARGS,
2055 METH_VARARGS,
1975 "return the heads of the common ancestors of the given revs"},
2056 "return the heads of the common ancestors of the given revs"},
1976 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2057 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1977 "clear the index caches"},
2058 "clear the index caches"},
1978 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2059 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1979 "get an index entry"},
2060 "get an index entry"},
1980 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
2061 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
1981 "get head revisions"},
2062 "get head revisions"},
1982 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2063 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1983 "insert an index entry"},
2064 "insert an index entry"},
1984 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2065 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1985 "match a potentially ambiguous node ID"},
2066 "match a potentially ambiguous node ID"},
1986 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2067 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1987 "stats for the index"},
2068 "stats for the index"},
1988 {NULL} /* Sentinel */
2069 {NULL} /* Sentinel */
1989 };
2070 };
1990
2071
1991 static PyGetSetDef index_getset[] = {
2072 static PyGetSetDef index_getset[] = {
1992 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2073 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1993 {NULL} /* Sentinel */
2074 {NULL} /* Sentinel */
1994 };
2075 };
1995
2076
1996 static PyTypeObject indexType = {
2077 static PyTypeObject indexType = {
1997 PyObject_HEAD_INIT(NULL)
2078 PyObject_HEAD_INIT(NULL)
1998 0, /* ob_size */
2079 0, /* ob_size */
1999 "parsers.index", /* tp_name */
2080 "parsers.index", /* tp_name */
2000 sizeof(indexObject), /* tp_basicsize */
2081 sizeof(indexObject), /* tp_basicsize */
2001 0, /* tp_itemsize */
2082 0, /* tp_itemsize */
2002 (destructor)index_dealloc, /* tp_dealloc */
2083 (destructor)index_dealloc, /* tp_dealloc */
2003 0, /* tp_print */
2084 0, /* tp_print */
2004 0, /* tp_getattr */
2085 0, /* tp_getattr */
2005 0, /* tp_setattr */
2086 0, /* tp_setattr */
2006 0, /* tp_compare */
2087 0, /* tp_compare */
2007 0, /* tp_repr */
2088 0, /* tp_repr */
2008 0, /* tp_as_number */
2089 0, /* tp_as_number */
2009 &index_sequence_methods, /* tp_as_sequence */
2090 &index_sequence_methods, /* tp_as_sequence */
2010 &index_mapping_methods, /* tp_as_mapping */
2091 &index_mapping_methods, /* tp_as_mapping */
2011 0, /* tp_hash */
2092 0, /* tp_hash */
2012 0, /* tp_call */
2093 0, /* tp_call */
2013 0, /* tp_str */
2094 0, /* tp_str */
2014 0, /* tp_getattro */
2095 0, /* tp_getattro */
2015 0, /* tp_setattro */
2096 0, /* tp_setattro */
2016 0, /* tp_as_buffer */
2097 0, /* tp_as_buffer */
2017 Py_TPFLAGS_DEFAULT, /* tp_flags */
2098 Py_TPFLAGS_DEFAULT, /* tp_flags */
2018 "revlog index", /* tp_doc */
2099 "revlog index", /* tp_doc */
2019 0, /* tp_traverse */
2100 0, /* tp_traverse */
2020 0, /* tp_clear */
2101 0, /* tp_clear */
2021 0, /* tp_richcompare */
2102 0, /* tp_richcompare */
2022 0, /* tp_weaklistoffset */
2103 0, /* tp_weaklistoffset */
2023 0, /* tp_iter */
2104 0, /* tp_iter */
2024 0, /* tp_iternext */
2105 0, /* tp_iternext */
2025 index_methods, /* tp_methods */
2106 index_methods, /* tp_methods */
2026 0, /* tp_members */
2107 0, /* tp_members */
2027 index_getset, /* tp_getset */
2108 index_getset, /* tp_getset */
2028 0, /* tp_base */
2109 0, /* tp_base */
2029 0, /* tp_dict */
2110 0, /* tp_dict */
2030 0, /* tp_descr_get */
2111 0, /* tp_descr_get */
2031 0, /* tp_descr_set */
2112 0, /* tp_descr_set */
2032 0, /* tp_dictoffset */
2113 0, /* tp_dictoffset */
2033 (initproc)index_init, /* tp_init */
2114 (initproc)index_init, /* tp_init */
2034 0, /* tp_alloc */
2115 0, /* tp_alloc */
2035 };
2116 };
2036
2117
2037 /*
2118 /*
2038 * returns a tuple of the form (index, index, cache) with elements as
2119 * returns a tuple of the form (index, index, cache) with elements as
2039 * follows:
2120 * follows:
2040 *
2121 *
2041 * index: an index object that lazily parses RevlogNG records
2122 * index: an index object that lazily parses RevlogNG records
2042 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2123 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2043 *
2124 *
2044 * added complications are for backwards compatibility
2125 * added complications are for backwards compatibility
2045 */
2126 */
2046 static PyObject *parse_index2(PyObject *self, PyObject *args)
2127 static PyObject *parse_index2(PyObject *self, PyObject *args)
2047 {
2128 {
2048 PyObject *tuple = NULL, *cache = NULL;
2129 PyObject *tuple = NULL, *cache = NULL;
2049 indexObject *idx;
2130 indexObject *idx;
2050 int ret;
2131 int ret;
2051
2132
2052 idx = PyObject_New(indexObject, &indexType);
2133 idx = PyObject_New(indexObject, &indexType);
2053 if (idx == NULL)
2134 if (idx == NULL)
2054 goto bail;
2135 goto bail;
2055
2136
2056 ret = index_init(idx, args);
2137 ret = index_init(idx, args);
2057 if (ret == -1)
2138 if (ret == -1)
2058 goto bail;
2139 goto bail;
2059
2140
2060 if (idx->inlined) {
2141 if (idx->inlined) {
2061 cache = Py_BuildValue("iO", 0, idx->data);
2142 cache = Py_BuildValue("iO", 0, idx->data);
2062 if (cache == NULL)
2143 if (cache == NULL)
2063 goto bail;
2144 goto bail;
2064 } else {
2145 } else {
2065 cache = Py_None;
2146 cache = Py_None;
2066 Py_INCREF(cache);
2147 Py_INCREF(cache);
2067 }
2148 }
2068
2149
2069 tuple = Py_BuildValue("NN", idx, cache);
2150 tuple = Py_BuildValue("NN", idx, cache);
2070 if (!tuple)
2151 if (!tuple)
2071 goto bail;
2152 goto bail;
2072 return tuple;
2153 return tuple;
2073
2154
2074 bail:
2155 bail:
2075 Py_XDECREF(idx);
2156 Py_XDECREF(idx);
2076 Py_XDECREF(cache);
2157 Py_XDECREF(cache);
2077 Py_XDECREF(tuple);
2158 Py_XDECREF(tuple);
2078 return NULL;
2159 return NULL;
2079 }
2160 }
2080
2161
2081 static char parsers_doc[] = "Efficient content parsing.";
2162 static char parsers_doc[] = "Efficient content parsing.";
2082
2163
2083 PyObject *encodedir(PyObject *self, PyObject *args);
2164 PyObject *encodedir(PyObject *self, PyObject *args);
2084 PyObject *pathencode(PyObject *self, PyObject *args);
2165 PyObject *pathencode(PyObject *self, PyObject *args);
2085 PyObject *lowerencode(PyObject *self, PyObject *args);
2166 PyObject *lowerencode(PyObject *self, PyObject *args);
2086
2167
2087 static PyMethodDef methods[] = {
2168 static PyMethodDef methods[] = {
2088 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2169 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2089 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2170 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2090 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2171 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2091 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2172 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2092 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2173 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2093 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2174 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2094 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2175 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2095 {NULL, NULL}
2176 {NULL, NULL}
2096 };
2177 };
2097
2178
2098 void dirs_module_init(PyObject *mod);
2179 void dirs_module_init(PyObject *mod);
2099
2180
2100 static void module_init(PyObject *mod)
2181 static void module_init(PyObject *mod)
2101 {
2182 {
2102 /* This module constant has two purposes. First, it lets us unit test
2183 /* This module constant has two purposes. First, it lets us unit test
2103 * the ImportError raised without hard-coding any error text. This
2184 * the ImportError raised without hard-coding any error text. This
2104 * means we can change the text in the future without breaking tests,
2185 * means we can change the text in the future without breaking tests,
2105 * even across changesets without a recompile. Second, its presence
2186 * even across changesets without a recompile. Second, its presence
2106 * can be used to determine whether the version-checking logic is
2187 * can be used to determine whether the version-checking logic is
2107 * present, which also helps in testing across changesets without a
2188 * present, which also helps in testing across changesets without a
2108 * recompile. Note that this means the pure-Python version of parsers
2189 * recompile. Note that this means the pure-Python version of parsers
2109 * should not have this module constant. */
2190 * should not have this module constant. */
2110 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2191 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2111
2192
2112 dirs_module_init(mod);
2193 dirs_module_init(mod);
2113
2194
2114 indexType.tp_new = PyType_GenericNew;
2195 indexType.tp_new = PyType_GenericNew;
2115 if (PyType_Ready(&indexType) < 0 ||
2196 if (PyType_Ready(&indexType) < 0 ||
2116 PyType_Ready(&dirstateTupleType) < 0)
2197 PyType_Ready(&dirstateTupleType) < 0)
2117 return;
2198 return;
2118 Py_INCREF(&indexType);
2199 Py_INCREF(&indexType);
2119 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2200 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2120 Py_INCREF(&dirstateTupleType);
2201 Py_INCREF(&dirstateTupleType);
2121 PyModule_AddObject(mod, "dirstatetuple",
2202 PyModule_AddObject(mod, "dirstatetuple",
2122 (PyObject *)&dirstateTupleType);
2203 (PyObject *)&dirstateTupleType);
2123
2204
2124 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2205 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2125 -1, -1, -1, -1, nullid, 20);
2206 -1, -1, -1, -1, nullid, 20);
2126 if (nullentry)
2207 if (nullentry)
2127 PyObject_GC_UnTrack(nullentry);
2208 PyObject_GC_UnTrack(nullentry);
2128 }
2209 }
2129
2210
2130 static int check_python_version(void)
2211 static int check_python_version(void)
2131 {
2212 {
2132 PyObject *sys = PyImport_ImportModule("sys");
2213 PyObject *sys = PyImport_ImportModule("sys");
2133 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
2214 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
2134 /* sys.hexversion is a 32-bit number by default, so the -1 case
2215 /* sys.hexversion is a 32-bit number by default, so the -1 case
2135 * should only occur in unusual circumstances (e.g. if sys.hexversion
2216 * should only occur in unusual circumstances (e.g. if sys.hexversion
2136 * is manually set to an invalid value). */
2217 * is manually set to an invalid value). */
2137 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2218 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2138 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2219 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2139 "modules were compiled with Python " PY_VERSION ", but "
2220 "modules were compiled with Python " PY_VERSION ", but "
2140 "Mercurial is currently using Python with sys.hexversion=%ld: "
2221 "Mercurial is currently using Python with sys.hexversion=%ld: "
2141 "Python %s\n at: %s", versionerrortext, hexversion,
2222 "Python %s\n at: %s", versionerrortext, hexversion,
2142 Py_GetVersion(), Py_GetProgramFullPath());
2223 Py_GetVersion(), Py_GetProgramFullPath());
2143 return -1;
2224 return -1;
2144 }
2225 }
2145 return 0;
2226 return 0;
2146 }
2227 }
2147
2228
2148 #ifdef IS_PY3K
2229 #ifdef IS_PY3K
2149 static struct PyModuleDef parsers_module = {
2230 static struct PyModuleDef parsers_module = {
2150 PyModuleDef_HEAD_INIT,
2231 PyModuleDef_HEAD_INIT,
2151 "parsers",
2232 "parsers",
2152 parsers_doc,
2233 parsers_doc,
2153 -1,
2234 -1,
2154 methods
2235 methods
2155 };
2236 };
2156
2237
2157 PyMODINIT_FUNC PyInit_parsers(void)
2238 PyMODINIT_FUNC PyInit_parsers(void)
2158 {
2239 {
2159 PyObject *mod;
2240 PyObject *mod;
2160
2241
2161 if (check_python_version() == -1)
2242 if (check_python_version() == -1)
2162 return;
2243 return;
2163 mod = PyModule_Create(&parsers_module);
2244 mod = PyModule_Create(&parsers_module);
2164 module_init(mod);
2245 module_init(mod);
2165 return mod;
2246 return mod;
2166 }
2247 }
2167 #else
2248 #else
2168 PyMODINIT_FUNC initparsers(void)
2249 PyMODINIT_FUNC initparsers(void)
2169 {
2250 {
2170 PyObject *mod;
2251 PyObject *mod;
2171
2252
2172 if (check_python_version() == -1)
2253 if (check_python_version() == -1)
2173 return;
2254 return;
2174 mod = Py_InitModule3("parsers", methods, parsers_doc);
2255 mod = Py_InitModule3("parsers", methods, parsers_doc);
2175 module_init(mod);
2256 module_init(mod);
2176 }
2257 }
2177 #endif
2258 #endif
General Comments 0
You need to be logged in to leave comments. Login now