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