290 return int(q & 0xFFFF) |
290 return int(q & 0xFFFF) |
291 |
291 |
292 def offset_type(offset, type): |
292 def offset_type(offset, type): |
293 return long(long(offset) << 16 | type) |
293 return long(long(offset) << 16 | type) |
294 |
294 |
|
295 class revlogoldio(object): |
|
296 def __init__(self): |
|
297 self.chunkcache = None |
|
298 |
|
299 def parseindex(self, fp, st, inline): |
|
300 s = struct.calcsize(indexformatv0) |
|
301 index = [] |
|
302 nodemap = {nullid: nullrev} |
|
303 n = 0 |
|
304 leftover = None |
|
305 while True: |
|
306 if st: |
|
307 data = fp.read(65536) |
|
308 else: |
|
309 # hack for httprangereader, it doesn't do partial reads well |
|
310 data = fp.read() |
|
311 if not data: |
|
312 break |
|
313 if leftover: |
|
314 data = leftover + data |
|
315 leftover = None |
|
316 off = 0 |
|
317 l = len(data) |
|
318 while off < l: |
|
319 if l - off < s: |
|
320 leftover = data[off:] |
|
321 break |
|
322 cur = data[off:off + s] |
|
323 off += s |
|
324 e = struct.unpack(indexformatv0, cur) |
|
325 index.append(e) |
|
326 nodemap[e[-1]] = n |
|
327 n += 1 |
|
328 if not st: |
|
329 break |
|
330 |
|
331 return index, nodemap |
|
332 |
|
333 class revlogio(object): |
|
334 def __init__(self): |
|
335 self.chunkcache = None |
|
336 |
|
337 def parseindex(self, fp, st, inline): |
|
338 if (lazyparser.safe_to_use and not inline and |
|
339 st and st.st_size > 10000): |
|
340 # big index, let's parse it on demand |
|
341 parser = lazyparser(fp, st.st_size, indexformatng, ngshaoffset) |
|
342 index = lazyindex(parser) |
|
343 nodemap = lazymap(parser) |
|
344 e = list(index[0]) |
|
345 type = gettype(e[0]) |
|
346 e[0] = offset_type(0, type) |
|
347 index[0] = e |
|
348 return index, nodemap |
|
349 |
|
350 s = struct.calcsize(indexformatng) |
|
351 index = [] |
|
352 nodemap = {nullid: nullrev} |
|
353 n = 0 |
|
354 leftover = None |
|
355 while True: |
|
356 if st: |
|
357 data = fp.read(65536) |
|
358 else: |
|
359 # hack for httprangereader, it doesn't do partial reads well |
|
360 data = fp.read() |
|
361 if not data: |
|
362 break |
|
363 if n == 0 and inline: |
|
364 # cache the first chunk |
|
365 self.chunkcache = (0, data) |
|
366 if leftover: |
|
367 data = leftover + data |
|
368 leftover = None |
|
369 off = 0 |
|
370 l = len(data) |
|
371 while off < l: |
|
372 if l - off < s: |
|
373 leftover = data[off:] |
|
374 break |
|
375 cur = data[off:off + s] |
|
376 off += s |
|
377 e = struct.unpack(indexformatng, cur) |
|
378 index.append(e) |
|
379 nodemap[e[-1]] = n |
|
380 n += 1 |
|
381 if inline: |
|
382 if e[1] < 0: |
|
383 break |
|
384 off += e[1] |
|
385 if off > l: |
|
386 # some things don't seek well, just read it |
|
387 fp.read(off - l) |
|
388 break |
|
389 if not st: |
|
390 break |
|
391 |
|
392 e = list(index[0]) |
|
393 type = gettype(e[0]) |
|
394 e[0] = offset_type(0, type) |
|
395 index[0] = e |
|
396 |
|
397 return index, nodemap |
|
398 |
295 class revlog(object): |
399 class revlog(object): |
296 """ |
400 """ |
297 the underlying revision storage object |
401 the underlying revision storage object |
298 |
402 |
299 A revlog consists of two parts, an index and the revision data. |
403 A revlog consists of two parts, an index and the revision data. |
328 self.datafile = indexfile[:-2] + ".d" |
432 self.datafile = indexfile[:-2] + ".d" |
329 self.opener = opener |
433 self.opener = opener |
330 |
434 |
331 self.indexstat = None |
435 self.indexstat = None |
332 self.cache = None |
436 self.cache = None |
333 self.chunkcache = None |
|
334 self.defversion = REVLOG_DEFAULT_VERSION |
437 self.defversion = REVLOG_DEFAULT_VERSION |
335 if hasattr(opener, "defversion"): |
438 if hasattr(opener, "defversion"): |
336 self.defversion = opener.defversion |
439 self.defversion = opener.defversion |
337 if self.defversion & REVLOGNG: |
440 if self.defversion & REVLOGNG: |
338 self.defversion |= REVLOGNGINLINEDATA |
441 self.defversion |= REVLOGNGINLINEDATA |
378 raise RevlogError(_("index %s unknown format %d") |
481 raise RevlogError(_("index %s unknown format %d") |
379 % (self.indexfile, fmt)) |
482 % (self.indexfile, fmt)) |
380 self.version = v |
483 self.version = v |
381 self.nodemap = {nullid: nullrev} |
484 self.nodemap = {nullid: nullrev} |
382 self.index = [] |
485 self.index = [] |
|
486 self._io = revlogio() |
383 self.indexformat = indexformatng |
487 self.indexformat = indexformatng |
384 if self.version == REVLOGV0: |
488 if self.version == REVLOGV0: |
|
489 self._io = revlogoldio() |
385 self.indexformat = indexformatv0 |
490 self.indexformat = indexformatv0 |
386 if i: |
491 if i: |
387 self._parseindex(f, st) |
492 self.index, self.nodemap = self._io.parseindex(f, st, self._inline()) |
388 |
|
389 def _parseindex(self, fp, st): |
|
390 shaoffset = ngshaoffset |
|
391 if self.version == REVLOGV0: |
|
392 shaoffset = v0shaoffset |
|
393 |
|
394 if (lazyparser.safe_to_use and not self._inline() and |
|
395 st and st.st_size > 10000): |
|
396 # big index, let's parse it on demand |
|
397 parser = lazyparser(fp, st.st_size, self.indexformat, shaoffset) |
|
398 self.index = lazyindex(parser) |
|
399 self.nodemap = lazymap(parser) |
|
400 if self.version != REVLOGV0: |
|
401 e = list(self.index[0]) |
|
402 type = gettype(e[0]) |
|
403 e[0] = offset_type(0, type) |
|
404 self.index[0] = e |
|
405 return |
|
406 |
|
407 s = struct.calcsize(self.indexformat) |
|
408 self.index = [] |
|
409 self.nodemap = {nullid: nullrev} |
|
410 inline = self._inline() |
|
411 n = 0 |
|
412 leftover = None |
|
413 while True: |
|
414 if st: |
|
415 data = fp.read(65536) |
|
416 else: |
|
417 # hack for httprangereader, it doesn't do partial reads well |
|
418 data = fp.read() |
|
419 if not data: |
|
420 break |
|
421 if n == 0 and self._inline(): |
|
422 # cache the first chunk |
|
423 self.chunkcache = (0, data) |
|
424 if leftover: |
|
425 data = leftover + data |
|
426 leftover = None |
|
427 off = 0 |
|
428 l = len(data) |
|
429 while off < l: |
|
430 if l - off < s: |
|
431 leftover = data[off:] |
|
432 break |
|
433 cur = data[off:off + s] |
|
434 off += s |
|
435 e = struct.unpack(self.indexformat, cur) |
|
436 self.index.append(e) |
|
437 self.nodemap[e[-1]] = n |
|
438 n += 1 |
|
439 if inline: |
|
440 if e[1] < 0: |
|
441 break |
|
442 off += e[1] |
|
443 if off > l: |
|
444 # some things don't seek well, just read it |
|
445 fp.read(off - l) |
|
446 break |
|
447 if not st: |
|
448 break |
|
449 |
|
450 if self.version != REVLOGV0: |
|
451 e = list(self.index[0]) |
|
452 type = gettype(e[0]) |
|
453 e[0] = offset_type(0, type) |
|
454 self.index[0] = e |
|
455 |
493 |
456 def _loadindex(self, start, end): |
494 def _loadindex(self, start, end): |
457 """load a block of indexes all at once from the lazy parser""" |
495 """load a block of indexes all at once from the lazy parser""" |
458 if isinstance(self.index, lazyindex): |
496 if isinstance(self.index, lazyindex): |
459 self.index.p.loadindex(start, end) |
497 self.index.p.loadindex(start, end) |
856 if inline: |
894 if inline: |
857 df = self.opener(self.indexfile) |
895 df = self.opener(self.indexfile) |
858 else: |
896 else: |
859 df = self.opener(self.datafile) |
897 df = self.opener(self.datafile) |
860 df.seek(start) |
898 df.seek(start) |
861 self.chunkcache = (start, df.read(cache_length)) |
899 self._io.chunkcache = (start, df.read(cache_length)) |
862 |
900 |
863 if not self.chunkcache: |
901 if not self._io.chunkcache: |
864 loadcache(df) |
902 loadcache(df) |
865 |
903 |
866 cache_start = self.chunkcache[0] |
904 cache_start = self._io.chunkcache[0] |
867 cache_end = cache_start + len(self.chunkcache[1]) |
905 cache_end = cache_start + len(self._io.chunkcache[1]) |
868 if start >= cache_start and end <= cache_end: |
906 if start >= cache_start and end <= cache_end: |
869 # it is cached |
907 # it is cached |
870 offset = start - cache_start |
908 offset = start - cache_start |
871 else: |
909 else: |
872 loadcache(df) |
910 loadcache(df) |
875 #def checkchunk(): |
913 #def checkchunk(): |
876 # df = self.opener(self.datafile) |
914 # df = self.opener(self.datafile) |
877 # df.seek(start) |
915 # df.seek(start) |
878 # return df.read(length) |
916 # return df.read(length) |
879 #assert s == checkchunk() |
917 #assert s == checkchunk() |
880 return decompress(self.chunkcache[1][offset:offset + length]) |
918 return decompress(self._io.chunkcache[1][offset:offset + length]) |
881 |
919 |
882 def delta(self, node): |
920 def delta(self, node): |
883 """return or calculate a delta between a node and its predecessor""" |
921 """return or calculate a delta between a node and its predecessor""" |
884 r = self.rev(node) |
922 r = self.rev(node) |
885 return self.revdiff(r - 1, r) |
923 return self.revdiff(r - 1, r) |
978 # if we don't call rename, the temp file will never replace the |
1016 # if we don't call rename, the temp file will never replace the |
979 # real index |
1017 # real index |
980 fp.rename() |
1018 fp.rename() |
981 |
1019 |
982 tr.replace(self.indexfile, trindex * calc) |
1020 tr.replace(self.indexfile, trindex * calc) |
983 self.chunkcache = None |
1021 self._io.chunkcache = None |
984 |
1022 |
985 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None): |
1023 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None): |
986 """add a revision to the log |
1024 """add a revision to the log |
987 |
1025 |
988 text - the revision data to add |
1026 text - the revision data to add |
1251 indexf = self.opener(self.indexfile, "a") |
1289 indexf = self.opener(self.indexfile, "a") |
1252 indexf.truncate(end) |
1290 indexf.truncate(end) |
1253 |
1291 |
1254 # then reset internal state in memory to forget those revisions |
1292 # then reset internal state in memory to forget those revisions |
1255 self.cache = None |
1293 self.cache = None |
1256 self.chunkcache = None |
1294 self._io.chunkcache = None |
1257 for x in xrange(rev, self.count()): |
1295 for x in xrange(rev, self.count()): |
1258 del self.nodemap[self.node(x)] |
1296 del self.nodemap[self.node(x)] |
1259 |
1297 |
1260 del self.index[rev:] |
1298 del self.index[rev:] |
1261 |
1299 |