##// END OF EJS Templates
hg-core: Explain offset override of first revision...
Antoine cezar -
r46165:f38adf8b default
parent child Browse files
Show More
@@ -1,330 +1,331 b''
1 use byteorder::{BigEndian, ByteOrder};
1 use byteorder::{BigEndian, ByteOrder};
2
2
3 use crate::revlog::{Revision, NULL_REVISION};
3 use crate::revlog::{Revision, NULL_REVISION};
4
4
5 pub const INDEX_ENTRY_SIZE: usize = 64;
5 pub const INDEX_ENTRY_SIZE: usize = 64;
6
6
7 /// A Revlog index
7 /// A Revlog index
8 #[derive(Debug)]
8 #[derive(Debug)]
9 pub struct Index<'a> {
9 pub struct Index<'a> {
10 bytes: &'a [u8],
10 bytes: &'a [u8],
11 /// Offsets of starts of index blocks.
11 /// Offsets of starts of index blocks.
12 /// Only needed when the index is interleaved with data.
12 /// Only needed when the index is interleaved with data.
13 offsets: Option<Vec<usize>>,
13 offsets: Option<Vec<usize>>,
14 }
14 }
15
15
16 impl<'a> Index<'a> {
16 impl<'a> Index<'a> {
17 /// Create an index from bytes.
17 /// Create an index from bytes.
18 /// Calculate the start of each entry when is_inline is true.
18 /// Calculate the start of each entry when is_inline is true.
19 pub fn new(bytes: &'a [u8], is_inline: bool) -> Self {
19 pub fn new(bytes: &'a [u8], is_inline: bool) -> Self {
20 if is_inline {
20 if is_inline {
21 let mut offset: usize = 0;
21 let mut offset: usize = 0;
22 let mut offsets = Vec::new();
22 let mut offsets = Vec::new();
23
23
24 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
24 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
25 offsets.push(offset);
25 offsets.push(offset);
26 let end = offset + INDEX_ENTRY_SIZE;
26 let end = offset + INDEX_ENTRY_SIZE;
27 let entry = IndexEntry {
27 let entry = IndexEntry {
28 bytes: &bytes[offset..end],
28 bytes: &bytes[offset..end],
29 offset_override: None,
29 offset_override: None,
30 };
30 };
31
31
32 offset += INDEX_ENTRY_SIZE + entry.compressed_len();
32 offset += INDEX_ENTRY_SIZE + entry.compressed_len();
33 }
33 }
34
34
35 Self {
35 Self {
36 bytes,
36 bytes,
37 offsets: Some(offsets),
37 offsets: Some(offsets),
38 }
38 }
39 } else {
39 } else {
40 Self {
40 Self {
41 bytes,
41 bytes,
42 offsets: None,
42 offsets: None,
43 }
43 }
44 }
44 }
45 }
45 }
46
46
47 /// Return number of entries of the revlog index.
47 /// Return number of entries of the revlog index.
48 pub fn len(&self) -> usize {
48 pub fn len(&self) -> usize {
49 if let Some(offsets) = &self.offsets {
49 if let Some(offsets) = &self.offsets {
50 offsets.len()
50 offsets.len()
51 } else {
51 } else {
52 self.bytes.len() / INDEX_ENTRY_SIZE
52 self.bytes.len() / INDEX_ENTRY_SIZE
53 }
53 }
54 }
54 }
55
55
56 /// Returns `true` if the `Index` has zero `entries`.
56 /// Returns `true` if the `Index` has zero `entries`.
57 pub fn is_empty(&self) -> bool {
57 pub fn is_empty(&self) -> bool {
58 self.len() == 0
58 self.len() == 0
59 }
59 }
60
60
61 /// Return the index entry corresponding to the given revision if it
61 /// Return the index entry corresponding to the given revision if it
62 /// exists.
62 /// exists.
63 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
63 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
64 if rev == NULL_REVISION {
64 if rev == NULL_REVISION {
65 return None;
65 return None;
66 }
66 }
67 if let Some(offsets) = &self.offsets {
67 if let Some(offsets) = &self.offsets {
68 self.get_entry_inline(rev, offsets)
68 self.get_entry_inline(rev, offsets)
69 } else {
69 } else {
70 self.get_entry_separated(rev)
70 self.get_entry_separated(rev)
71 }
71 }
72 }
72 }
73
73
74 fn get_entry_inline(
74 fn get_entry_inline(
75 &self,
75 &self,
76 rev: Revision,
76 rev: Revision,
77 offsets: &[usize],
77 offsets: &[usize],
78 ) -> Option<IndexEntry> {
78 ) -> Option<IndexEntry> {
79 let start = *offsets.get(rev as usize)?;
79 let start = *offsets.get(rev as usize)?;
80 let end = start.checked_add(INDEX_ENTRY_SIZE)?;
80 let end = start.checked_add(INDEX_ENTRY_SIZE)?;
81 let bytes = &self.bytes[start..end];
81 let bytes = &self.bytes[start..end];
82
82
83 // See IndexEntry for an explanation of this override.
83 // See IndexEntry for an explanation of this override.
84 let offset_override = Some(end);
84 let offset_override = Some(end);
85
85
86 Some(IndexEntry {
86 Some(IndexEntry {
87 bytes,
87 bytes,
88 offset_override,
88 offset_override,
89 })
89 })
90 }
90 }
91
91
92 fn get_entry_separated(&self, rev: Revision) -> Option<IndexEntry> {
92 fn get_entry_separated(&self, rev: Revision) -> Option<IndexEntry> {
93 let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE;
93 let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE;
94 if rev as usize >= max_rev {
94 if rev as usize >= max_rev {
95 return None;
95 return None;
96 }
96 }
97 let start = rev as usize * INDEX_ENTRY_SIZE;
97 let start = rev as usize * INDEX_ENTRY_SIZE;
98 let end = start + INDEX_ENTRY_SIZE;
98 let end = start + INDEX_ENTRY_SIZE;
99 let bytes = &self.bytes[start..end];
99 let bytes = &self.bytes[start..end];
100
100
101 // See IndexEntry for an explanation of this override.
101 // Override the offset of the first revision as its bytes are used
102 // for the index's metadata (saving space because it is always 0)
102 let offset_override = match rev {
103 let offset_override = match rev {
103 0 => Some(0),
104 0 => Some(0),
104 _ => None,
105 _ => None,
105 };
106 };
106
107
107 Some(IndexEntry {
108 Some(IndexEntry {
108 bytes,
109 bytes,
109 offset_override,
110 offset_override,
110 })
111 })
111 }
112 }
112 }
113 }
113
114
114 #[derive(Debug)]
115 #[derive(Debug)]
115 pub struct IndexEntry<'a> {
116 pub struct IndexEntry<'a> {
116 bytes: &'a [u8],
117 bytes: &'a [u8],
117 /// Allows to override the offset value of the entry.
118 /// Allows to override the offset value of the entry.
118 ///
119 ///
119 /// For interleaved index and data, the offset stored in the index
120 /// For interleaved index and data, the offset stored in the index
120 /// corresponds to the separated data offset.
121 /// corresponds to the separated data offset.
121 /// It has to be overridden with the actual offset in the interleaved
122 /// It has to be overridden with the actual offset in the interleaved
122 /// index which is just after the index block.
123 /// index which is just after the index block.
123 ///
124 ///
124 /// For separated index and data, the offset stored in the first index
125 /// For separated index and data, the offset stored in the first index
125 /// entry is mixed with the index headers.
126 /// entry is mixed with the index headers.
126 /// It has to be overridden with 0.
127 /// It has to be overridden with 0.
127 offset_override: Option<usize>,
128 offset_override: Option<usize>,
128 }
129 }
129
130
130 impl<'a> IndexEntry<'a> {
131 impl<'a> IndexEntry<'a> {
131 /// Return the offset of the data if not overridden by offset_override.
132 /// Return the offset of the data if not overridden by offset_override.
132 pub fn offset(&self) -> usize {
133 pub fn offset(&self) -> usize {
133 if let Some(offset_override) = self.offset_override {
134 if let Some(offset_override) = self.offset_override {
134 offset_override
135 offset_override
135 } else {
136 } else {
136 let mut bytes = [0; 8];
137 let mut bytes = [0; 8];
137 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
138 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
138 BigEndian::read_u64(&bytes[..]) as usize
139 BigEndian::read_u64(&bytes[..]) as usize
139 }
140 }
140 }
141 }
141
142
142 /// Return the compressed length of the data.
143 /// Return the compressed length of the data.
143 pub fn compressed_len(&self) -> usize {
144 pub fn compressed_len(&self) -> usize {
144 BigEndian::read_u32(&self.bytes[8..=11]) as usize
145 BigEndian::read_u32(&self.bytes[8..=11]) as usize
145 }
146 }
146
147
147 /// Return the uncompressed length of the data.
148 /// Return the uncompressed length of the data.
148 pub fn uncompressed_len(&self) -> usize {
149 pub fn uncompressed_len(&self) -> usize {
149 BigEndian::read_u32(&self.bytes[12..=15]) as usize
150 BigEndian::read_u32(&self.bytes[12..=15]) as usize
150 }
151 }
151
152
152 /// Return the revision upon which the data has been derived.
153 /// Return the revision upon which the data has been derived.
153 pub fn base_revision(&self) -> Revision {
154 pub fn base_revision(&self) -> Revision {
154 // TODO Maybe return an Option when base_revision == rev?
155 // TODO Maybe return an Option when base_revision == rev?
155 // Requires to add rev to IndexEntry
156 // Requires to add rev to IndexEntry
156
157
157 BigEndian::read_i32(&self.bytes[16..])
158 BigEndian::read_i32(&self.bytes[16..])
158 }
159 }
159
160
160 pub fn p1(&self) -> Revision {
161 pub fn p1(&self) -> Revision {
161 BigEndian::read_i32(&self.bytes[24..])
162 BigEndian::read_i32(&self.bytes[24..])
162 }
163 }
163
164
164 pub fn p2(&self) -> Revision {
165 pub fn p2(&self) -> Revision {
165 BigEndian::read_i32(&self.bytes[28..])
166 BigEndian::read_i32(&self.bytes[28..])
166 }
167 }
167
168
168 /// Return the hash of revision's full text.
169 /// Return the hash of revision's full text.
169 ///
170 ///
170 /// Currently, SHA-1 is used and only the first 20 bytes of this field
171 /// Currently, SHA-1 is used and only the first 20 bytes of this field
171 /// are used.
172 /// are used.
172 pub fn hash(&self) -> &[u8] {
173 pub fn hash(&self) -> &[u8] {
173 &self.bytes[32..52]
174 &self.bytes[32..52]
174 }
175 }
175 }
176 }
176
177
177 #[cfg(test)]
178 #[cfg(test)]
178 mod tests {
179 mod tests {
179 use super::*;
180 use super::*;
180
181
181 #[cfg(test)]
182 #[cfg(test)]
182 #[derive(Debug, Copy, Clone)]
183 #[derive(Debug, Copy, Clone)]
183 pub struct IndexEntryBuilder {
184 pub struct IndexEntryBuilder {
184 is_first: bool,
185 is_first: bool,
185 is_inline: bool,
186 is_inline: bool,
186 is_general_delta: bool,
187 is_general_delta: bool,
187 version: u16,
188 version: u16,
188 offset: usize,
189 offset: usize,
189 compressed_len: usize,
190 compressed_len: usize,
190 uncompressed_len: usize,
191 uncompressed_len: usize,
191 base_revision: Revision,
192 base_revision: Revision,
192 }
193 }
193
194
194 #[cfg(test)]
195 #[cfg(test)]
195 impl IndexEntryBuilder {
196 impl IndexEntryBuilder {
196 pub fn new() -> Self {
197 pub fn new() -> Self {
197 Self {
198 Self {
198 is_first: false,
199 is_first: false,
199 is_inline: false,
200 is_inline: false,
200 is_general_delta: true,
201 is_general_delta: true,
201 version: 2,
202 version: 2,
202 offset: 0,
203 offset: 0,
203 compressed_len: 0,
204 compressed_len: 0,
204 uncompressed_len: 0,
205 uncompressed_len: 0,
205 base_revision: 0,
206 base_revision: 0,
206 }
207 }
207 }
208 }
208
209
209 pub fn is_first(&mut self, value: bool) -> &mut Self {
210 pub fn is_first(&mut self, value: bool) -> &mut Self {
210 self.is_first = value;
211 self.is_first = value;
211 self
212 self
212 }
213 }
213
214
214 pub fn with_inline(&mut self, value: bool) -> &mut Self {
215 pub fn with_inline(&mut self, value: bool) -> &mut Self {
215 self.is_inline = value;
216 self.is_inline = value;
216 self
217 self
217 }
218 }
218
219
219 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
220 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
220 self.is_general_delta = value;
221 self.is_general_delta = value;
221 self
222 self
222 }
223 }
223
224
224 pub fn with_version(&mut self, value: u16) -> &mut Self {
225 pub fn with_version(&mut self, value: u16) -> &mut Self {
225 self.version = value;
226 self.version = value;
226 self
227 self
227 }
228 }
228
229
229 pub fn with_offset(&mut self, value: usize) -> &mut Self {
230 pub fn with_offset(&mut self, value: usize) -> &mut Self {
230 self.offset = value;
231 self.offset = value;
231 self
232 self
232 }
233 }
233
234
234 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
235 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
235 self.compressed_len = value;
236 self.compressed_len = value;
236 self
237 self
237 }
238 }
238
239
239 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
240 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
240 self.uncompressed_len = value;
241 self.uncompressed_len = value;
241 self
242 self
242 }
243 }
243
244
244 pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
245 pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
245 self.base_revision = value;
246 self.base_revision = value;
246 self
247 self
247 }
248 }
248
249
249 pub fn build(&self) -> Vec<u8> {
250 pub fn build(&self) -> Vec<u8> {
250 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
251 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
251 if self.is_first {
252 if self.is_first {
252 bytes.extend(&match (self.is_general_delta, self.is_inline) {
253 bytes.extend(&match (self.is_general_delta, self.is_inline) {
253 (false, false) => [0u8, 0],
254 (false, false) => [0u8, 0],
254 (false, true) => [0u8, 1],
255 (false, true) => [0u8, 1],
255 (true, false) => [0u8, 2],
256 (true, false) => [0u8, 2],
256 (true, true) => [0u8, 3],
257 (true, true) => [0u8, 3],
257 });
258 });
258 bytes.extend(&self.version.to_be_bytes());
259 bytes.extend(&self.version.to_be_bytes());
259 // Remaining offset bytes.
260 // Remaining offset bytes.
260 bytes.extend(&[0u8; 2]);
261 bytes.extend(&[0u8; 2]);
261 } else {
262 } else {
262 // Offset is only 6 bytes will usize is 8.
263 // Offset is only 6 bytes will usize is 8.
263 bytes.extend(&self.offset.to_be_bytes()[2..]);
264 bytes.extend(&self.offset.to_be_bytes()[2..]);
264 }
265 }
265 bytes.extend(&[0u8; 2]); // Revision flags.
266 bytes.extend(&[0u8; 2]); // Revision flags.
266 bytes.extend(&self.compressed_len.to_be_bytes()[4..]);
267 bytes.extend(&self.compressed_len.to_be_bytes()[4..]);
267 bytes.extend(&self.uncompressed_len.to_be_bytes()[4..]);
268 bytes.extend(&self.uncompressed_len.to_be_bytes()[4..]);
268 bytes.extend(&self.base_revision.to_be_bytes());
269 bytes.extend(&self.base_revision.to_be_bytes());
269 bytes
270 bytes
270 }
271 }
271 }
272 }
272
273
273 #[test]
274 #[test]
274 fn test_offset() {
275 fn test_offset() {
275 let bytes = IndexEntryBuilder::new().with_offset(1).build();
276 let bytes = IndexEntryBuilder::new().with_offset(1).build();
276 let entry = IndexEntry {
277 let entry = IndexEntry {
277 bytes: &bytes,
278 bytes: &bytes,
278 offset_override: None,
279 offset_override: None,
279 };
280 };
280
281
281 assert_eq!(entry.offset(), 1)
282 assert_eq!(entry.offset(), 1)
282 }
283 }
283
284
284 #[test]
285 #[test]
285 fn test_with_overridden_offset() {
286 fn test_with_overridden_offset() {
286 let bytes = IndexEntryBuilder::new().with_offset(1).build();
287 let bytes = IndexEntryBuilder::new().with_offset(1).build();
287 let entry = IndexEntry {
288 let entry = IndexEntry {
288 bytes: &bytes,
289 bytes: &bytes,
289 offset_override: Some(2),
290 offset_override: Some(2),
290 };
291 };
291
292
292 assert_eq!(entry.offset(), 2)
293 assert_eq!(entry.offset(), 2)
293 }
294 }
294
295
295 #[test]
296 #[test]
296 fn test_compressed_len() {
297 fn test_compressed_len() {
297 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
298 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
298 let entry = IndexEntry {
299 let entry = IndexEntry {
299 bytes: &bytes,
300 bytes: &bytes,
300 offset_override: None,
301 offset_override: None,
301 };
302 };
302
303
303 assert_eq!(entry.compressed_len(), 1)
304 assert_eq!(entry.compressed_len(), 1)
304 }
305 }
305
306
306 #[test]
307 #[test]
307 fn test_uncompressed_len() {
308 fn test_uncompressed_len() {
308 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
309 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
309 let entry = IndexEntry {
310 let entry = IndexEntry {
310 bytes: &bytes,
311 bytes: &bytes,
311 offset_override: None,
312 offset_override: None,
312 };
313 };
313
314
314 assert_eq!(entry.uncompressed_len(), 1)
315 assert_eq!(entry.uncompressed_len(), 1)
315 }
316 }
316
317
317 #[test]
318 #[test]
318 fn test_base_revision() {
319 fn test_base_revision() {
319 let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
320 let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
320 let entry = IndexEntry {
321 let entry = IndexEntry {
321 bytes: &bytes,
322 bytes: &bytes,
322 offset_override: None,
323 offset_override: None,
323 };
324 };
324
325
325 assert_eq!(entry.base_revision(), 1)
326 assert_eq!(entry.base_revision(), 1)
326 }
327 }
327 }
328 }
328
329
329 #[cfg(test)]
330 #[cfg(test)]
330 pub use tests::IndexEntryBuilder;
331 pub use tests::IndexEntryBuilder;
General Comments 0
You need to be logged in to leave comments. Login now