Mercurial > public > mercurial-scm > hg
annotate mercurial/revlog.py @ 224:ccbcc4d76f81
fix bad assumption about uniqueness of file versions
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
fix bad assumption about uniqueness of file versions
Mercurial had assumed that a given file hash could show up in only one
changeset, and thus that the mapping from file revision to changeset
was 1-to-1. But if two people perform the same edit with the same
parents, we can get an identical hash in different changesets.
So we've got to loosen up our uniqueness checks in addgroup and in
verify.
manifest hash: 5462003241e7d071ffa1741b87a59f646c9988ed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFCoMDkywK+sNU5EO8RAg9PAJ9YWSknfFBoeYve/+Z5DDGGvytDkwCgoMwj
kT01PcjNzGPr1/Oe5WRvulE=
=HC4t
-----END PGP SIGNATURE-----
author | mpm@selenic.com |
---|---|
date | Fri, 03 Jun 2005 12:43:16 -0800 |
parents | 2bfe525ef6ca |
children | 4f802588cdfb 4f802588cdfb afe895fcc0d0 |
rev | line source |
---|---|
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
1 # revlog.py - storage back-end for mercurial |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
2 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
3 # This provides efficient delta storage with O(1) retrieve and append |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
4 # and O(changes) merge between branches |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
5 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
6 # Copyright 2005 Matt Mackall <mpm@selenic.com> |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
7 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
8 # This software may be used and distributed according to the terms |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
9 # of the GNU General Public License, incorporated herein by reference. |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
10 |
208 | 11 import zlib, struct, sha, binascii, heapq |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
12 from mercurial import mdiff |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
13 |
36
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
14 def hex(node): return binascii.hexlify(node) |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
15 def bin(node): return binascii.unhexlify(node) |
83 | 16 def short(node): return hex(node[:4]) |
36
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
17 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
18 def compress(text): |
112 | 19 if not text: return text |
20 if len(text) < 44: | |
21 if text[0] == '\0': return text | |
22 return 'u' + text | |
23 bin = zlib.compress(text) | |
24 if len(bin) > len(text): | |
25 if text[0] == '\0': return text | |
26 return 'u' + text | |
27 return bin | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
28 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
29 def decompress(bin): |
112 | 30 if not bin: return bin |
31 t = bin[0] | |
32 if t == '\0': return bin | |
33 if t == 'x': return zlib.decompress(bin) | |
34 if t == 'u': return bin[1:] | |
35 raise "unknown compression type %s" % t | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
36 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
37 def hash(text, p1, p2): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
38 l = [p1, p2] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
39 l.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
40 return sha.sha(l[0] + l[1] + text).digest() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
41 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
42 nullid = "\0" * 20 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
43 indexformat = ">4l20s20s20s" |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
44 |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
45 class lazyparser: |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
46 def __init__(self, data): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
47 self.data = data |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
48 self.s = struct.calcsize(indexformat) |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
49 self.l = len(data)/self.s |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
50 self.index = [None] * self.l |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
51 self.map = {nullid: -1} |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
52 |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
53 def load(self, pos): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
54 block = pos / 1000 |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
55 i = block * 1000 |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
56 end = min(self.l, i + 1000) |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
57 while i < end: |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
58 d = self.data[i * self.s: (i + 1) * self.s] |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
59 e = struct.unpack(indexformat, d) |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
60 self.index[i] = e |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
61 self.map[e[6]] = i |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
62 i += 1 |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
63 |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
64 class lazyindex: |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
65 def __init__(self, parser): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
66 self.p = parser |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
67 def __len__(self): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
68 return len(self.p.index) |
115 | 69 def load(self, pos): |
70 self.p.load(pos) | |
71 return self.p.index[pos] | |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
72 def __getitem__(self, pos): |
115 | 73 return self.p.index[pos] or self.load(pos) |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
74 def append(self, e): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
75 self.p.index.append(e) |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
76 |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
77 class lazymap: |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
78 def __init__(self, parser): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
79 self.p = parser |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
80 def load(self, key): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
81 n = self.p.data.find(key) |
86
1b945e8ba67b
Friendlier exceptions for unknown node errors
mpm@selenic.com
parents:
84
diff
changeset
|
82 if n < 0: raise KeyError("node " + hex(key)) |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
83 pos = n / self.p.s |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
84 self.p.load(pos) |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
85 def __contains__(self, key): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
86 try: |
77 | 87 self[key] |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
88 return True |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
89 except KeyError: |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
90 return False |
97 | 91 def __iter__(self): |
92 for i in xrange(self.p.l): | |
93 try: | |
94 yield self.p.index[i][6] | |
95 except: | |
96 self.p.load(i) | |
97 yield self.p.index[i][6] | |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
98 def __getitem__(self, key): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
99 try: |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
100 return self.p.map[key] |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
101 except KeyError: |
86
1b945e8ba67b
Friendlier exceptions for unknown node errors
mpm@selenic.com
parents:
84
diff
changeset
|
102 try: |
1b945e8ba67b
Friendlier exceptions for unknown node errors
mpm@selenic.com
parents:
84
diff
changeset
|
103 self.load(key) |
1b945e8ba67b
Friendlier exceptions for unknown node errors
mpm@selenic.com
parents:
84
diff
changeset
|
104 return self.p.map[key] |
1b945e8ba67b
Friendlier exceptions for unknown node errors
mpm@selenic.com
parents:
84
diff
changeset
|
105 except KeyError: |
1b945e8ba67b
Friendlier exceptions for unknown node errors
mpm@selenic.com
parents:
84
diff
changeset
|
106 raise KeyError("node " + hex(key)) |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
107 def __setitem__(self, key, val): |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
108 self.p.map[key] = val |
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
109 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
110 class revlog: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
111 def __init__(self, opener, indexfile, datafile): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
112 self.indexfile = indexfile |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
113 self.datafile = datafile |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
114 self.opener = opener |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
115 self.cache = None |
116
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
116 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
117 try: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
118 i = self.opener(self.indexfile).read() |
73 | 119 except IOError: |
76
d993ebd69d28
Add lazy{parser,index,map} to speed up processing of index files
mpm@selenic.com
parents:
73
diff
changeset
|
120 i = "" |
116
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
121 |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
122 if len(i) > 10000: |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
123 # big index, let's parse it on demand |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
124 parser = lazyparser(i) |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
125 self.index = lazyindex(parser) |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
126 self.nodemap = lazymap(parser) |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
127 else: |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
128 s = struct.calcsize(indexformat) |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
129 l = len(i) / s |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
130 self.index = [None] * l |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
131 m = [None] * l |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
132 |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
133 n = 0 |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
134 for f in xrange(0, len(i), s): |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
135 # offset, size, base, linkrev, p1, p2, nodeid |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
136 e = struct.unpack(indexformat, i[f:f + s]) |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
137 m[n] = (e[6], n) |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
138 self.index[n] = e |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
139 n += 1 |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
140 |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
141 self.nodemap = dict(m) |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
142 self.nodemap[nullid] = -1 |
e484cd5ec282
Only use lazy indexing for big indices and avoid the overhead of the
mpm@selenic.com
parents:
115
diff
changeset
|
143 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
144 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
145 def tip(self): return self.node(len(self.index) - 1) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
146 def count(self): return len(self.index) |
26 | 147 def node(self, rev): return (rev < 0) and nullid or self.index[rev][6] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
148 def rev(self, node): return self.nodemap[node] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
149 def linkrev(self, node): return self.index[self.nodemap[node]][3] |
2 | 150 def parents(self, node): |
151 if node == nullid: return (nullid, nullid) | |
152 return self.index[self.nodemap[node]][4:6] | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
153 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
154 def start(self, rev): return self.index[rev][0] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
155 def length(self, rev): return self.index[rev][1] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
156 def end(self, rev): return self.start(rev) + self.length(rev) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
157 def base(self, rev): return self.index[rev][2] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
158 |
221 | 159 def heads(self): |
160 p = {} | |
161 h = [] | |
162 for r in range(self.count() - 1, 0, -1): | |
163 n = self.node(r) | |
164 if n not in p: | |
165 h.append(n) | |
166 for pn in self.parents(n): | |
167 p[pn] = 1 | |
168 return h | |
169 | |
36
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
170 def lookup(self, id): |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
171 try: |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
172 rev = int(id) |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
173 return self.node(rev) |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
174 except ValueError: |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
175 c = [] |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
176 for n in self.nodemap: |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
177 if id in hex(n): |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
178 c.append(n) |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
179 if len(c) > 1: raise KeyError("Ambiguous identifier") |
67 | 180 if len(c) < 1: raise KeyError("No match found") |
36
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
181 return c[0] |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
182 |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
183 return None |
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
184 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
185 def diff(self, a, b): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
186 return mdiff.textdiff(a, b) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
187 |
73 | 188 def patches(self, t, pl): |
189 return mdiff.patches(t, pl) | |
190 | |
119
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
191 def delta(self, node): |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
192 r = self.rev(node) |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
193 b = self.base(r) |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
194 if r == b: |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
195 return self.diff(self.revision(self.node(r - 1)), |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
196 self.revision(node)) |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
197 else: |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
198 f = self.opener(self.datafile) |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
199 f.seek(self.start(r)) |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
200 data = f.read(self.length(r)) |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
201 return decompress(data) |
c7a66f9752a4
Add code to retrieve or construct a revlog delta
mpm@selenic.com
parents:
117
diff
changeset
|
202 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
203 def revision(self, node): |
36
da28286bf6b7
Add smart node lookup by substring or by rev number
mpm@selenic.com
parents:
26
diff
changeset
|
204 if node == nullid: return "" |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
205 if self.cache and self.cache[0] == node: return self.cache[2] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
206 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
207 text = None |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
208 rev = self.rev(node) |
117 | 209 start, length, base, link, p1, p2, node = self.index[rev] |
210 end = start + length | |
211 if base != rev: start = self.start(base) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
212 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
213 if self.cache and self.cache[1] >= base and self.cache[1] < rev: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
214 base = self.cache[1] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
215 start = self.start(base + 1) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
216 text = self.cache[2] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
217 last = 0 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
218 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
219 f = self.opener(self.datafile) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
220 f.seek(start) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
221 data = f.read(end - start) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
222 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
223 if not text: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
224 last = self.length(base) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
225 text = decompress(data[:last]) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
226 |
71
47c9a869adee
Add mdiff.patches to speed up applying thousands of patches to the manifest
mpm@selenic.com
parents:
67
diff
changeset
|
227 bins = [] |
64 | 228 for r in xrange(base + 1, rev + 1): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
229 s = self.length(r) |
71
47c9a869adee
Add mdiff.patches to speed up applying thousands of patches to the manifest
mpm@selenic.com
parents:
67
diff
changeset
|
230 bins.append(decompress(data[last:last + s])) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
231 last = last + s |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
232 |
71
47c9a869adee
Add mdiff.patches to speed up applying thousands of patches to the manifest
mpm@selenic.com
parents:
67
diff
changeset
|
233 text = mdiff.patches(text, bins) |
47c9a869adee
Add mdiff.patches to speed up applying thousands of patches to the manifest
mpm@selenic.com
parents:
67
diff
changeset
|
234 |
26 | 235 if node != hash(text, p1, p2): |
98 | 236 raise IOError("integrity check failed on %s:%d" |
237 % (self.datafile, rev)) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
238 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
239 self.cache = (node, rev, text) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
240 return text |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
241 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
242 def addrevision(self, text, transaction, link, p1=None, p2=None): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
243 if text is None: text = "" |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
244 if p1 is None: p1 = self.tip() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
245 if p2 is None: p2 = nullid |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
246 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
247 node = hash(text, p1, p2) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
248 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
249 n = self.count() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
250 t = n - 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
251 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
252 if n: |
64 | 253 base = self.base(t) |
254 start = self.start(base) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
255 end = self.end(t) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
256 prev = self.revision(self.tip()) |
98 | 257 d = self.diff(prev, text) |
258 data = compress(d) | |
64 | 259 dist = end - start + len(data) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
260 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
261 # full versions are inserted when the needed deltas |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
262 # become comparable to the uncompressed text |
64 | 263 if not n or dist > len(text) * 2: |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
264 data = compress(text) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
265 base = n |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
266 else: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
267 base = self.base(t) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
268 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
269 offset = 0 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
270 if t >= 0: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
271 offset = self.end(t) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
272 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
273 e = (offset, len(data), base, link, p1, p2, node) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
274 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
275 self.index.append(e) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
276 self.nodemap[node] = n |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
277 entry = struct.pack(indexformat, *e) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
278 |
26 | 279 transaction.add(self.datafile, e[0]) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
280 self.opener(self.datafile, "a").write(data) |
41 | 281 transaction.add(self.indexfile, n * len(entry)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
282 self.opener(self.indexfile, "a").write(entry) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
283 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
284 self.cache = (node, n, text) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
285 return node |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
286 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
287 def ancestor(self, a, b): |
147 | 288 # calculate the distance of every node from root |
289 dist = {nullid: 0} | |
290 for i in xrange(self.count()): | |
291 n = self.node(i) | |
292 p1, p2 = self.parents(n) | |
293 dist[n] = max(dist[p1], dist[p2]) + 1 | |
294 | |
295 # traverse ancestors in order of decreasing distance from root | |
296 def ancestors(node): | |
297 # we store negative distances because heap returns smallest member | |
298 h = [(-dist[node], node)] | |
299 seen = {} | |
300 earliest = self.count() | |
301 while h: | |
302 d, n = heapq.heappop(h) | |
303 r = self.rev(n) | |
304 if n not in seen: | |
305 seen[n] = 1 | |
306 yield (-d, n) | |
307 for p in self.parents(n): | |
308 heapq.heappush(h, (-dist[p], p)) | |
45
f2b2d5daec30
Fix recursion depth trouble with ancestor algorithm
mpm@selenic.com
parents:
41
diff
changeset
|
309 |
147 | 310 x = ancestors(a) |
311 y = ancestors(b) | |
312 lx = x.next() | |
313 ly = y.next() | |
45
f2b2d5daec30
Fix recursion depth trouble with ancestor algorithm
mpm@selenic.com
parents:
41
diff
changeset
|
314 |
147 | 315 # increment each ancestor list until it is closer to root than |
316 # the other, or they match | |
317 while 1: | |
318 if lx == ly: | |
319 return lx[1] | |
320 elif lx < ly: | |
321 ly = y.next() | |
322 elif lx > ly: | |
323 lx = x.next() | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
324 |
46 | 325 def group(self, linkmap): |
326 # given a list of changeset revs, return a set of deltas and | |
94 | 327 # metadata corresponding to nodes. the first delta is |
46 | 328 # parent(nodes[0]) -> nodes[0] the receiver is guaranteed to |
329 # have this parent as it has all history before these | |
330 # changesets. parent is parent[0] | |
331 | |
332 revs = [] | |
333 needed = {} | |
334 | |
335 # find file nodes/revs that match changeset revs | |
336 for i in xrange(0, self.count()): | |
337 if self.index[i][3] in linkmap: | |
338 revs.append(i) | |
339 needed[i] = 1 | |
340 | |
341 # if we don't have any revisions touched by these changesets, bail | |
192 | 342 if not revs: |
343 yield struct.pack(">l", 0) | |
344 return | |
46 | 345 |
346 # add the parent of the first rev | |
347 p = self.parents(self.node(revs[0]))[0] | |
348 revs.insert(0, self.rev(p)) | |
349 | |
350 # for each delta that isn't contiguous in the log, we need to | |
351 # reconstruct the base, reconstruct the result, and then | |
352 # calculate the delta. We also need to do this where we've | |
353 # stored a full version and not a delta | |
354 for i in xrange(0, len(revs) - 1): | |
355 a, b = revs[i], revs[i + 1] | |
356 if a + 1 != b or self.base(b) == b: | |
357 for j in xrange(self.base(a), a + 1): | |
358 needed[j] = 1 | |
359 for j in xrange(self.base(b), b + 1): | |
360 needed[j] = 1 | |
361 | |
362 # calculate spans to retrieve from datafile | |
363 needed = needed.keys() | |
364 needed.sort() | |
365 spans = [] | |
192 | 366 oo = -1 |
367 ol = 0 | |
46 | 368 for n in needed: |
369 if n < 0: continue | |
370 o = self.start(n) | |
371 l = self.length(n) | |
192 | 372 if oo + ol == o: # can we merge with the previous? |
373 nl = spans[-1][2] | |
374 nl.append((n, l)) | |
375 ol += l | |
376 spans[-1] = (oo, ol, nl) | |
46 | 377 else: |
192 | 378 oo = o |
379 ol = l | |
380 spans.append((oo, ol, [(n, l)])) | |
46 | 381 |
382 # read spans in, divide up chunks | |
383 chunks = {} | |
192 | 384 for span in spans: |
46 | 385 # we reopen the file for each span to make http happy for now |
386 f = self.opener(self.datafile) | |
387 f.seek(span[0]) | |
388 data = f.read(span[1]) | |
389 | |
390 # divide up the span | |
391 pos = 0 | |
392 for r, l in span[2]: | |
192 | 393 chunks[r] = decompress(data[pos: pos + l]) |
46 | 394 pos += l |
395 | |
396 # helper to reconstruct intermediate versions | |
397 def construct(text, base, rev): | |
192 | 398 bins = [chunks[r] for r in xrange(base + 1, rev + 1)] |
71
47c9a869adee
Add mdiff.patches to speed up applying thousands of patches to the manifest
mpm@selenic.com
parents:
67
diff
changeset
|
399 return mdiff.patches(text, bins) |
46 | 400 |
401 # build deltas | |
402 deltas = [] | |
71
47c9a869adee
Add mdiff.patches to speed up applying thousands of patches to the manifest
mpm@selenic.com
parents:
67
diff
changeset
|
403 for d in xrange(0, len(revs) - 1): |
46 | 404 a, b = revs[d], revs[d + 1] |
405 n = self.node(b) | |
192 | 406 |
407 # do we need to construct a new delta? | |
46 | 408 if a + 1 != b or self.base(b) == b: |
409 if a >= 0: | |
410 base = self.base(a) | |
192 | 411 ta = chunks[self.base(a)] |
46 | 412 ta = construct(ta, base, a) |
413 else: | |
414 ta = "" | |
415 | |
416 base = self.base(b) | |
417 if a > base: | |
418 base = a | |
419 tb = ta | |
420 else: | |
192 | 421 tb = chunks[self.base(b)] |
46 | 422 tb = construct(tb, base, b) |
423 d = self.diff(ta, tb) | |
424 else: | |
192 | 425 d = chunks[b] |
46 | 426 |
427 p = self.parents(n) | |
428 meta = n + p[0] + p[1] + linkmap[self.linkrev(n)] | |
429 l = struct.pack(">l", len(meta) + len(d) + 4) | |
192 | 430 yield l |
431 yield meta | |
432 yield d | |
46 | 433 |
192 | 434 yield struct.pack(">l", 0) |
435 | |
224
ccbcc4d76f81
fix bad assumption about uniqueness of file versions
mpm@selenic.com
parents:
221
diff
changeset
|
436 def addgroup(self, revs, linkmapper, transaction, unique = 0): |
46 | 437 # given a set of deltas, add them to the revision log. the |
438 # first delta is against its parent, which should be in our | |
439 # log, the rest are against the previous delta. | |
440 | |
441 # track the base of the current delta log | |
442 r = self.count() | |
443 t = r - 1 | |
192 | 444 node = nullid |
46 | 445 |
446 base = prev = -1 | |
447 start = end = 0 | |
448 if r: | |
449 start = self.start(self.base(t)) | |
450 end = self.end(t) | |
451 measure = self.length(self.base(t)) | |
452 base = self.base(t) | |
453 prev = self.tip() | |
454 | |
455 transaction.add(self.datafile, end) | |
456 transaction.add(self.indexfile, r * struct.calcsize(indexformat)) | |
457 dfh = self.opener(self.datafile, "a") | |
458 ifh = self.opener(self.indexfile, "a") | |
459 | |
460 # loop through our set of deltas | |
192 | 461 chain = None |
462 for chunk in revs: | |
463 node, p1, p2, cs = struct.unpack("20s20s20s20s", chunk[:80]) | |
94 | 464 link = linkmapper(cs) |
77 | 465 if node in self.nodemap: |
224
ccbcc4d76f81
fix bad assumption about uniqueness of file versions
mpm@selenic.com
parents:
221
diff
changeset
|
466 # this can happen if two branches make the same change |
ccbcc4d76f81
fix bad assumption about uniqueness of file versions
mpm@selenic.com
parents:
221
diff
changeset
|
467 if unique: |
ccbcc4d76f81
fix bad assumption about uniqueness of file versions
mpm@selenic.com
parents:
221
diff
changeset
|
468 raise "already have %s" % hex(node[:4]) |
ccbcc4d76f81
fix bad assumption about uniqueness of file versions
mpm@selenic.com
parents:
221
diff
changeset
|
469 continue |
192 | 470 delta = chunk[80:] |
471 | |
472 if not chain: | |
473 # retrieve the parent revision of the delta chain | |
474 chain = p1 | |
475 if not chain in self.nodemap: | |
476 raise "unknown base %s" % short(chain[:4]) | |
46 | 477 |
478 # full versions are inserted when the needed deltas become | |
479 # comparable to the uncompressed text or when the previous | |
480 # version is not the one we have a delta against. We use | |
481 # the size of the previous full rev as a proxy for the | |
482 # current size. | |
483 | |
484 if chain == prev: | |
485 cdelta = compress(delta) | |
486 | |
487 if chain != prev or (end - start + len(cdelta)) > measure * 2: | |
488 # flush our writes here so we can read it in revision | |
489 dfh.flush() | |
490 ifh.flush() | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
491 text = self.revision(chain) |
73 | 492 text = self.patches(text, [delta]) |
46 | 493 chk = self.addrevision(text, transaction, link, p1, p2) |
494 if chk != node: | |
495 raise "consistency error adding group" | |
496 measure = len(text) | |
497 else: | |
498 e = (end, len(cdelta), self.base(t), link, p1, p2, node) | |
499 self.index.append(e) | |
500 self.nodemap[node] = r | |
501 dfh.write(cdelta) | |
502 ifh.write(struct.pack(indexformat, *e)) | |
503 | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
504 t, r, chain, prev = r, r + 1, node, node |
46 | 505 start = self.start(self.base(t)) |
506 end = self.end(t) | |
507 | |
508 dfh.close() | |
509 ifh.close() | |
510 return node |