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: