Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/revlog.py @ 1584:b3e94785ab69
merge with crew
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Sun, 11 Dec 2005 15:38:42 -0800 |
parents | 59b3639df0a9 |
children | 14d1f1868bf6 11d12bd6e1dc |
comparison
equal
deleted
inserted
replaced
1583:32a4e6802864 | 1584:b3e94785ab69 |
---|---|
29 s.update(text) | 29 s.update(text) |
30 return s.digest() | 30 return s.digest() |
31 | 31 |
32 def compress(text): | 32 def compress(text): |
33 """ generate a possibly-compressed representation of text """ | 33 """ generate a possibly-compressed representation of text """ |
34 if not text: return text | 34 if not text: return ("", text) |
35 if len(text) < 44: | 35 if len(text) < 44: |
36 if text[0] == '\0': return text | 36 if text[0] == '\0': return ("", text) |
37 return 'u' + text | 37 return ('u', text) |
38 bin = zlib.compress(text) | 38 bin = zlib.compress(text) |
39 if len(bin) > len(text): | 39 if len(bin) > len(text): |
40 if text[0] == '\0': return text | 40 if text[0] == '\0': return ("", text) |
41 return 'u' + text | 41 return ('u', text) |
42 return bin | 42 return ("", bin) |
43 | 43 |
44 def decompress(bin): | 44 def decompress(bin): |
45 """ decompress the given input """ | 45 """ decompress the given input """ |
46 if not bin: return bin | 46 if not bin: return bin |
47 t = bin[0] | 47 t = bin[0] |
50 if t == 'u': return bin[1:] | 50 if t == 'u': return bin[1:] |
51 raise RevlogError(_("unknown compression type %s") % t) | 51 raise RevlogError(_("unknown compression type %s") % t) |
52 | 52 |
53 indexformat = ">4l20s20s20s" | 53 indexformat = ">4l20s20s20s" |
54 | 54 |
55 class lazyparser: | 55 class lazyparser(object): |
56 """ | 56 """ |
57 this class avoids the need to parse the entirety of large indices | 57 this class avoids the need to parse the entirety of large indices |
58 | 58 |
59 By default we parse and load 1000 entries at a time. | 59 By default we parse and load 1000 entries at a time. |
60 | 60 |
69 self.index = [None] * self.l | 69 self.index = [None] * self.l |
70 self.map = {nullid: -1} | 70 self.map = {nullid: -1} |
71 self.all = 0 | 71 self.all = 0 |
72 self.revlog = revlog | 72 self.revlog = revlog |
73 | 73 |
74 def trunc(self, pos): | |
75 self.l = pos/self.s | |
76 | |
74 def load(self, pos=None): | 77 def load(self, pos=None): |
75 if self.all: return | 78 if self.all: return |
76 if pos is not None: | 79 if pos is not None: |
77 block = pos / 1000 | 80 block = pos / 1000 |
78 i = block * 1000 | 81 i = block * 1000 |
89 e = struct.unpack(indexformat, d) | 92 e = struct.unpack(indexformat, d) |
90 self.index[i] = e | 93 self.index[i] = e |
91 self.map[e[6]] = i | 94 self.map[e[6]] = i |
92 i += 1 | 95 i += 1 |
93 | 96 |
94 class lazyindex: | 97 class lazyindex(object): |
95 """a lazy version of the index array""" | 98 """a lazy version of the index array""" |
96 def __init__(self, parser): | 99 def __init__(self, parser): |
97 self.p = parser | 100 self.p = parser |
98 def __len__(self): | 101 def __len__(self): |
99 return len(self.p.index) | 102 return len(self.p.index) |
102 pos += len(self.p.index) | 105 pos += len(self.p.index) |
103 self.p.load(pos) | 106 self.p.load(pos) |
104 return self.p.index[pos] | 107 return self.p.index[pos] |
105 def __getitem__(self, pos): | 108 def __getitem__(self, pos): |
106 return self.p.index[pos] or self.load(pos) | 109 return self.p.index[pos] or self.load(pos) |
110 def __delitem__(self, pos): | |
111 del self.p.index[pos] | |
107 def append(self, e): | 112 def append(self, e): |
108 self.p.index.append(e) | 113 self.p.index.append(e) |
109 | 114 def trunc(self, pos): |
110 class lazymap: | 115 self.p.trunc(pos) |
116 | |
117 class lazymap(object): | |
111 """a lazy version of the node map""" | 118 """a lazy version of the node map""" |
112 def __init__(self, parser): | 119 def __init__(self, parser): |
113 self.p = parser | 120 self.p = parser |
114 def load(self, key): | 121 def load(self, key): |
115 if self.p.all: return | 122 if self.p.all: return |
138 return self.p.map[key] | 145 return self.p.map[key] |
139 except KeyError: | 146 except KeyError: |
140 raise KeyError("node " + hex(key)) | 147 raise KeyError("node " + hex(key)) |
141 def __setitem__(self, key, val): | 148 def __setitem__(self, key, val): |
142 self.p.map[key] = val | 149 self.p.map[key] = val |
150 def __delitem__(self, key): | |
151 del self.p.map[key] | |
143 | 152 |
144 class RevlogError(Exception): pass | 153 class RevlogError(Exception): pass |
145 | 154 |
146 class revlog: | 155 class revlog(object): |
147 """ | 156 """ |
148 the underlying revision storage object | 157 the underlying revision storage object |
149 | 158 |
150 A revlog consists of two parts, an index and the revision data. | 159 A revlog consists of two parts, an index and the revision data. |
151 | 160 |
398 assert orderedout | 407 assert orderedout |
399 assert roots | 408 assert roots |
400 assert heads | 409 assert heads |
401 return (orderedout, roots, heads) | 410 return (orderedout, roots, heads) |
402 | 411 |
403 def heads(self, stop=None): | 412 def heads(self, start=None): |
404 """return the list of all nodes that have no children""" | 413 """return the list of all nodes that have no children |
405 p = {} | 414 |
406 h = [] | 415 if start is specified, only heads that are descendants of |
407 stoprev = 0 | 416 start will be returned |
408 if stop and stop in self.nodemap: | 417 |
409 stoprev = self.rev(stop) | 418 """ |
410 | 419 if start is None: |
411 for r in range(self.count() - 1, -1, -1): | 420 start = nullid |
421 reachable = {start: 1} | |
422 heads = {start: 1} | |
423 startrev = self.rev(start) | |
424 | |
425 for r in xrange(startrev + 1, self.count()): | |
412 n = self.node(r) | 426 n = self.node(r) |
413 if n not in p: | |
414 h.append(n) | |
415 if n == stop: | |
416 break | |
417 if r < stoprev: | |
418 break | |
419 for pn in self.parents(n): | 427 for pn in self.parents(n): |
420 p[pn] = 1 | 428 if pn in reachable: |
421 return h | 429 reachable[n] = 1 |
430 heads[n] = 1 | |
431 if pn in heads: | |
432 del heads[pn] | |
433 return heads.keys() | |
422 | 434 |
423 def children(self, node): | 435 def children(self, node): |
424 """find the children of a given node""" | 436 """find the children of a given node""" |
425 c = [] | 437 c = [] |
426 p = self.rev(node) | 438 p = self.rev(node) |
541 base = self.base(t) | 553 base = self.base(t) |
542 start = self.start(base) | 554 start = self.start(base) |
543 end = self.end(t) | 555 end = self.end(t) |
544 if not d: | 556 if not d: |
545 prev = self.revision(self.tip()) | 557 prev = self.revision(self.tip()) |
546 d = self.diff(prev, text) | 558 d = self.diff(prev, str(text)) |
547 data = compress(d) | 559 data = compress(d) |
548 dist = end - start + len(data) | 560 l = len(data[1]) + len(data[0]) |
561 dist = end - start + l | |
549 | 562 |
550 # full versions are inserted when the needed deltas | 563 # full versions are inserted when the needed deltas |
551 # become comparable to the uncompressed text | 564 # become comparable to the uncompressed text |
552 if not n or dist > len(text) * 2: | 565 if not n or dist > len(text) * 2: |
553 data = compress(text) | 566 data = compress(text) |
567 l = len(data[1]) + len(data[0]) | |
554 base = n | 568 base = n |
555 else: | 569 else: |
556 base = self.base(t) | 570 base = self.base(t) |
557 | 571 |
558 offset = 0 | 572 offset = 0 |
559 if t >= 0: | 573 if t >= 0: |
560 offset = self.end(t) | 574 offset = self.end(t) |
561 | 575 |
562 e = (offset, len(data), base, link, p1, p2, node) | 576 e = (offset, l, base, link, p1, p2, node) |
563 | 577 |
564 self.index.append(e) | 578 self.index.append(e) |
565 self.nodemap[node] = n | 579 self.nodemap[node] = n |
566 entry = struct.pack(indexformat, *e) | 580 entry = struct.pack(indexformat, *e) |
567 | 581 |
568 transaction.add(self.datafile, e[0]) | 582 transaction.add(self.datafile, e[0]) |
569 self.opener(self.datafile, "a").write(data) | 583 f = self.opener(self.datafile, "a") |
584 if data[0]: | |
585 f.write(data[0]) | |
586 f.write(data[1]) | |
570 transaction.add(self.indexfile, n * len(entry)) | 587 transaction.add(self.indexfile, n * len(entry)) |
571 self.opener(self.indexfile, "a").write(entry) | 588 self.opener(self.indexfile, "a").write(entry) |
572 | 589 |
573 self.cache = (node, n, text) | 590 self.cache = (node, n, text) |
574 return node | 591 return node |
782 # raise RevlogError(_("already have %s") % hex(node[:4])) | 799 # raise RevlogError(_("already have %s") % hex(node[:4])) |
783 chain = node | 800 chain = node |
784 continue | 801 continue |
785 delta = chunk[80:] | 802 delta = chunk[80:] |
786 | 803 |
804 for p in (p1, p2): | |
805 if not p in self.nodemap: | |
806 raise RevlogError(_("unknown parent %s") % short(p1)) | |
807 | |
787 if not chain: | 808 if not chain: |
788 # retrieve the parent revision of the delta chain | 809 # retrieve the parent revision of the delta chain |
789 chain = p1 | 810 chain = p1 |
790 if not chain in self.nodemap: | 811 if not chain in self.nodemap: |
791 raise RevlogError(_("unknown base %s") % short(chain[:4])) | 812 raise RevlogError(_("unknown base %s") % short(chain[:4])) |
795 # version is not the one we have a delta against. We use | 816 # version is not the one we have a delta against. We use |
796 # the size of the previous full rev as a proxy for the | 817 # the size of the previous full rev as a proxy for the |
797 # current size. | 818 # current size. |
798 | 819 |
799 if chain == prev: | 820 if chain == prev: |
800 cdelta = compress(delta) | 821 tempd = compress(delta) |
822 cdelta = tempd[0] + tempd[1] | |
801 | 823 |
802 if chain != prev or (end - start + len(cdelta)) > measure * 2: | 824 if chain != prev or (end - start + len(cdelta)) > measure * 2: |
803 # flush our writes here so we can read it in revision | 825 # flush our writes here so we can read it in revision |
804 dfh.flush() | 826 dfh.flush() |
805 ifh.flush() | 827 ifh.flush() |
822 | 844 |
823 dfh.close() | 845 dfh.close() |
824 ifh.close() | 846 ifh.close() |
825 return node | 847 return node |
826 | 848 |
849 def strip(self, rev, minlink): | |
850 if self.count() == 0 or rev >= self.count(): | |
851 return | |
852 | |
853 # When stripping away a revision, we need to make sure it | |
854 # does not actually belong to an older changeset. | |
855 # The minlink parameter defines the oldest revision | |
856 # we're allowed to strip away. | |
857 while minlink > self.index[rev][3]: | |
858 rev += 1 | |
859 if rev >= self.count(): | |
860 return | |
861 | |
862 # first truncate the files on disk | |
863 end = self.start(rev) | |
864 self.opener(self.datafile, "a").truncate(end) | |
865 end = rev * struct.calcsize(indexformat) | |
866 self.opener(self.indexfile, "a").truncate(end) | |
867 | |
868 # then reset internal state in memory to forget those revisions | |
869 self.cache = None | |
870 for p in self.index[rev:]: | |
871 del self.nodemap[p[6]] | |
872 del self.index[rev:] | |
873 | |
874 # truncating the lazyindex also truncates the lazymap. | |
875 if isinstance(self.index, lazyindex): | |
876 self.index.trunc(end) | |
877 | |
878 | |
827 def checksize(self): | 879 def checksize(self): |
828 expected = 0 | 880 expected = 0 |
829 if self.count(): | 881 if self.count(): |
830 expected = self.end(self.count() - 1) | 882 expected = self.end(self.count() - 1) |
831 try: | 883 try: |