Show More
@@ -84,6 +84,7 b' pub struct Index {' | |||||
84 | /// Offsets of starts of index blocks. |
|
84 | /// Offsets of starts of index blocks. | |
85 | /// Only needed when the index is interleaved with data. |
|
85 | /// Only needed when the index is interleaved with data. | |
86 | offsets: Option<Vec<usize>>, |
|
86 | offsets: Option<Vec<usize>>, | |
|
87 | uses_generaldelta: bool, | |||
87 | } |
|
88 | } | |
88 |
|
89 | |||
89 | impl Index { |
|
90 | impl Index { | |
@@ -100,6 +101,11 b' impl Index {' | |||||
100 | return Err(HgError::corrupted("unsupported revlog version")); |
|
101 | return Err(HgError::corrupted("unsupported revlog version")); | |
101 | } |
|
102 | } | |
102 |
|
103 | |||
|
104 | // This is only correct because we know version is REVLOGV1. | |||
|
105 | // In v2 we always use generaldelta, while in v0 we never use | |||
|
106 | // generaldelta. Similar for [is_inline] (it's only used in v1). | |||
|
107 | let uses_generaldelta = header.format_flags().uses_generaldelta(); | |||
|
108 | ||||
103 | if header.format_flags().is_inline() { |
|
109 | if header.format_flags().is_inline() { | |
104 | let mut offset: usize = 0; |
|
110 | let mut offset: usize = 0; | |
105 | let mut offsets = Vec::new(); |
|
111 | let mut offsets = Vec::new(); | |
@@ -119,6 +125,7 b' impl Index {' | |||||
119 | Ok(Self { |
|
125 | Ok(Self { | |
120 | bytes, |
|
126 | bytes, | |
121 | offsets: Some(offsets), |
|
127 | offsets: Some(offsets), | |
|
128 | uses_generaldelta, | |||
122 | }) |
|
129 | }) | |
123 | } else { |
|
130 | } else { | |
124 | Err(HgError::corrupted("unexpected inline revlog length") |
|
131 | Err(HgError::corrupted("unexpected inline revlog length") | |
@@ -128,10 +135,15 b' impl Index {' | |||||
128 | Ok(Self { |
|
135 | Ok(Self { | |
129 | bytes, |
|
136 | bytes, | |
130 | offsets: None, |
|
137 | offsets: None, | |
|
138 | uses_generaldelta, | |||
131 | }) |
|
139 | }) | |
132 | } |
|
140 | } | |
133 | } |
|
141 | } | |
134 |
|
142 | |||
|
143 | pub fn uses_generaldelta(&self) -> bool { | |||
|
144 | self.uses_generaldelta | |||
|
145 | } | |||
|
146 | ||||
135 | /// Value of the inline flag. |
|
147 | /// Value of the inline flag. | |
136 | pub fn is_inline(&self) -> bool { |
|
148 | pub fn is_inline(&self) -> bool { | |
137 | self.offsets.is_some() |
|
149 | self.offsets.is_some() | |
@@ -259,7 +271,7 b" impl<'a> IndexEntry<'a> {" | |||||
259 | } |
|
271 | } | |
260 |
|
272 | |||
261 | /// Return the revision upon which the data has been derived. |
|
273 | /// Return the revision upon which the data has been derived. | |
262 | pub fn base_revision(&self) -> Revision { |
|
274 | pub fn base_revision_or_base_of_delta_chain(&self) -> Revision { | |
263 | // TODO Maybe return an Option when base_revision == rev? |
|
275 | // TODO Maybe return an Option when base_revision == rev? | |
264 | // Requires to add rev to IndexEntry |
|
276 | // Requires to add rev to IndexEntry | |
265 |
|
277 | |||
@@ -297,7 +309,7 b' mod tests {' | |||||
297 | offset: usize, |
|
309 | offset: usize, | |
298 | compressed_len: usize, |
|
310 | compressed_len: usize, | |
299 | uncompressed_len: usize, |
|
311 | uncompressed_len: usize, | |
300 | base_revision: Revision, |
|
312 | base_revision_or_base_of_delta_chain: Revision, | |
301 | } |
|
313 | } | |
302 |
|
314 | |||
303 | #[cfg(test)] |
|
315 | #[cfg(test)] | |
@@ -311,7 +323,7 b' mod tests {' | |||||
311 | offset: 0, |
|
323 | offset: 0, | |
312 | compressed_len: 0, |
|
324 | compressed_len: 0, | |
313 | uncompressed_len: 0, |
|
325 | uncompressed_len: 0, | |
314 | base_revision: 0, |
|
326 | base_revision_or_base_of_delta_chain: 0, | |
315 | } |
|
327 | } | |
316 | } |
|
328 | } | |
317 |
|
329 | |||
@@ -350,8 +362,11 b' mod tests {' | |||||
350 | self |
|
362 | self | |
351 | } |
|
363 | } | |
352 |
|
364 | |||
353 | pub fn with_base_revision(&mut self, value: Revision) -> &mut Self { |
|
365 | pub fn with_base_revision_or_base_of_delta_chain( | |
354 | self.base_revision = value; |
|
366 | &mut self, | |
|
367 | value: Revision, | |||
|
368 | ) -> &mut Self { | |||
|
369 | self.base_revision_or_base_of_delta_chain = value; | |||
355 | self |
|
370 | self | |
356 | } |
|
371 | } | |
357 |
|
372 | |||
@@ -374,7 +389,9 b' mod tests {' | |||||
374 | bytes.extend(&[0u8; 2]); // Revision flags. |
|
389 | bytes.extend(&[0u8; 2]); // Revision flags. | |
375 | bytes.extend(&(self.compressed_len as u32).to_be_bytes()); |
|
390 | bytes.extend(&(self.compressed_len as u32).to_be_bytes()); | |
376 | bytes.extend(&(self.uncompressed_len as u32).to_be_bytes()); |
|
391 | bytes.extend(&(self.uncompressed_len as u32).to_be_bytes()); | |
377 | bytes.extend(&self.base_revision.to_be_bytes()); |
|
392 | bytes.extend( | |
|
393 | &self.base_revision_or_base_of_delta_chain.to_be_bytes(), | |||
|
394 | ); | |||
378 | bytes |
|
395 | bytes | |
379 | } |
|
396 | } | |
380 | } |
|
397 | } | |
@@ -480,14 +497,16 b' mod tests {' | |||||
480 | } |
|
497 | } | |
481 |
|
498 | |||
482 | #[test] |
|
499 | #[test] | |
483 | fn test_base_revision() { |
|
500 | fn test_base_revision_or_base_of_delta_chain() { | |
484 |
let bytes = IndexEntryBuilder::new() |
|
501 | let bytes = IndexEntryBuilder::new() | |
|
502 | .with_base_revision_or_base_of_delta_chain(1) | |||
|
503 | .build(); | |||
485 | let entry = IndexEntry { |
|
504 | let entry = IndexEntry { | |
486 | bytes: &bytes, |
|
505 | bytes: &bytes, | |
487 | offset_override: None, |
|
506 | offset_override: None, | |
488 | }; |
|
507 | }; | |
489 |
|
508 | |||
490 | assert_eq!(entry.base_revision(), 1) |
|
509 | assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1) | |
491 | } |
|
510 | } | |
492 |
|
511 | |||
493 | #[test] |
|
512 | #[test] |
@@ -191,11 +191,20 b' impl Revlog {' | |||||
191 | // Todo return -> Cow |
|
191 | // Todo return -> Cow | |
192 | let mut entry = self.get_entry(rev)?; |
|
192 | let mut entry = self.get_entry(rev)?; | |
193 | let mut delta_chain = vec![]; |
|
193 | let mut delta_chain = vec![]; | |
194 | while let Some(base_rev) = entry.base_rev { |
|
194 | ||
|
195 | // The meaning of `base_rev_or_base_of_delta_chain` depends on | |||
|
196 | // generaldelta. See the doc on `ENTRY_DELTA_BASE` in | |||
|
197 | // `mercurial/revlogutils/constants.py` and the code in | |||
|
198 | // [_chaininfo] and in [index_deltachain]. | |||
|
199 | let uses_generaldelta = self.index.uses_generaldelta(); | |||
|
200 | while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain { | |||
|
201 | let base_rev = if uses_generaldelta { | |||
|
202 | base_rev | |||
|
203 | } else { | |||
|
204 | entry.rev - 1 | |||
|
205 | }; | |||
195 | delta_chain.push(entry); |
|
206 | delta_chain.push(entry); | |
196 | entry = self |
|
207 | entry = self.get_entry_internal(base_rev)?; | |
197 | .get_entry(base_rev) |
|
|||
198 | .map_err(|_| RevlogError::corrupted())?; |
|
|||
199 | } |
|
208 | } | |
200 |
|
209 | |||
201 | // TODO do not look twice in the index |
|
210 | // TODO do not look twice in the index | |
@@ -291,14 +300,26 b' impl Revlog {' | |||||
291 | bytes: data, |
|
300 | bytes: data, | |
292 | compressed_len: index_entry.compressed_len(), |
|
301 | compressed_len: index_entry.compressed_len(), | |
293 | uncompressed_len: index_entry.uncompressed_len(), |
|
302 | uncompressed_len: index_entry.uncompressed_len(), | |
294 |
base_rev: if index_entry |
|
303 | base_rev_or_base_of_delta_chain: if index_entry | |
|
304 | .base_revision_or_base_of_delta_chain() | |||
|
305 | == rev | |||
|
306 | { | |||
295 | None |
|
307 | None | |
296 | } else { |
|
308 | } else { | |
297 | Some(index_entry.base_revision()) |
|
309 | Some(index_entry.base_revision_or_base_of_delta_chain()) | |
298 | }, |
|
310 | }, | |
299 | }; |
|
311 | }; | |
300 | Ok(entry) |
|
312 | Ok(entry) | |
301 | } |
|
313 | } | |
|
314 | ||||
|
315 | /// when resolving internal references within revlog, any errors | |||
|
316 | /// should be reported as corruption, instead of e.g. "invalid revision" | |||
|
317 | fn get_entry_internal( | |||
|
318 | &self, | |||
|
319 | rev: Revision, | |||
|
320 | ) -> Result<RevlogEntry, RevlogError> { | |||
|
321 | return self.get_entry(rev).map_err(|_| RevlogError::corrupted()); | |||
|
322 | } | |||
302 | } |
|
323 | } | |
303 |
|
324 | |||
304 | /// The revlog entry's bytes and the necessary informations to extract |
|
325 | /// The revlog entry's bytes and the necessary informations to extract | |
@@ -309,7 +330,7 b" pub struct RevlogEntry<'a> {" | |||||
309 | bytes: &'a [u8], |
|
330 | bytes: &'a [u8], | |
310 | compressed_len: usize, |
|
331 | compressed_len: usize, | |
311 | uncompressed_len: usize, |
|
332 | uncompressed_len: usize, | |
312 | base_rev: Option<Revision>, |
|
333 | base_rev_or_base_of_delta_chain: Option<Revision>, | |
313 | } |
|
334 | } | |
314 |
|
335 | |||
315 | impl<'a> RevlogEntry<'a> { |
|
336 | impl<'a> RevlogEntry<'a> { | |
@@ -375,7 +396,7 b" impl<'a> RevlogEntry<'a> {" | |||||
375 | /// Tell if the entry is a snapshot or a delta |
|
396 | /// Tell if the entry is a snapshot or a delta | |
376 | /// (influences on decompression). |
|
397 | /// (influences on decompression). | |
377 | fn is_delta(&self) -> bool { |
|
398 | fn is_delta(&self) -> bool { | |
378 | self.base_rev.is_some() |
|
399 | self.base_rev_or_base_of_delta_chain.is_some() | |
379 | } |
|
400 | } | |
380 | } |
|
401 | } | |
381 |
|
402 |
@@ -1,4 +1,3 b'' | |||||
1 |
|
||||
2 |
|
|
1 | $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort" | |
3 |
|
2 | |||
4 | $ cat << EOF >> $HGRCPATH |
|
3 | $ cat << EOF >> $HGRCPATH | |
@@ -21,9 +20,27 b'' | |||||
21 | 1 0 prev |
|
20 | 1 0 prev | |
22 | 2 1 prev |
|
21 | 2 1 prev | |
23 |
|
22 | |||
24 |
rhg |
|
23 | rhg works on non-generaldelta revlogs: | |
25 |
|
24 | |||
26 |
$ $NO_FALLBACK hg cat f -r . |
|
25 | $ $NO_FALLBACK hg cat f -r . | |
27 | abort: corrupted revlog (rhg !) |
|
26 | 1 | |
28 | size=0, sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 (rhg !) |
|
27 | 2 | |
29 | size=58, sha256=0cf0386dd4813cc3b957ea790146627dfc0ec42ad3fcf47221b9842e4d5764c1 (no-rhg !) |
|
28 | 3 | |
|
29 | 4 | |||
|
30 | 5 | |||
|
31 | 6 | |||
|
32 | 7 | |||
|
33 | 8 | |||
|
34 | 9 | |||
|
35 | 10 | |||
|
36 | 11 | |||
|
37 | 12 | |||
|
38 | 13 | |||
|
39 | 14 | |||
|
40 | 15 | |||
|
41 | 16 | |||
|
42 | 17 | |||
|
43 | 18 | |||
|
44 | 19 | |||
|
45 | 20 | |||
|
46 | footer |
General Comments 0
You need to be logged in to leave comments.
Login now