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