##// END OF EJS Templates
rust-inner-revlog: drop some outdated comment
marmoute -
r52745:06549ab4 default
parent child Browse files
Show More
@@ -1,2035 +1,2031
1 use std::collections::{HashMap, HashSet};
1 use std::collections::{HashMap, HashSet};
2 use std::fmt::Debug;
2 use std::fmt::Debug;
3 use std::ops::Deref;
3 use std::ops::Deref;
4 use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
4 use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
5
5
6 use bitvec::prelude::*;
6 use bitvec::prelude::*;
7 use byteorder::{BigEndian, ByteOrder};
7 use byteorder::{BigEndian, ByteOrder};
8 use bytes_cast::{unaligned, BytesCast};
8 use bytes_cast::{unaligned, BytesCast};
9
9
10 use super::REVIDX_KNOWN_FLAGS;
10 use super::REVIDX_KNOWN_FLAGS;
11 use crate::errors::HgError;
11 use crate::errors::HgError;
12 use crate::node::{NODE_BYTES_LENGTH, NULL_NODE, STORED_NODE_ID_BYTES};
12 use crate::node::{NODE_BYTES_LENGTH, NULL_NODE, STORED_NODE_ID_BYTES};
13 use crate::revlog::node::Node;
13 use crate::revlog::node::Node;
14 use crate::revlog::{Revision, NULL_REVISION};
14 use crate::revlog::{Revision, NULL_REVISION};
15 use crate::{
15 use crate::{
16 dagops, BaseRevision, FastHashMap, Graph, GraphError, RevlogError,
16 dagops, BaseRevision, FastHashMap, Graph, GraphError, RevlogError,
17 RevlogIndex, UncheckedRevision,
17 RevlogIndex, UncheckedRevision,
18 };
18 };
19
19
20 pub const INDEX_ENTRY_SIZE: usize = 64;
20 pub const INDEX_ENTRY_SIZE: usize = 64;
21 pub const INDEX_HEADER_SIZE: usize = 4;
21 pub const INDEX_HEADER_SIZE: usize = 4;
22 pub const COMPRESSION_MODE_INLINE: u8 = 2;
22 pub const COMPRESSION_MODE_INLINE: u8 = 2;
23
23
24 #[derive(Debug)]
24 #[derive(Debug)]
25 pub struct IndexHeader {
25 pub struct IndexHeader {
26 pub(super) header_bytes: [u8; INDEX_HEADER_SIZE],
26 pub(super) header_bytes: [u8; INDEX_HEADER_SIZE],
27 }
27 }
28
28
29 #[derive(Copy, Clone)]
29 #[derive(Copy, Clone)]
30 pub struct IndexHeaderFlags {
30 pub struct IndexHeaderFlags {
31 flags: u16,
31 flags: u16,
32 }
32 }
33
33
34 /// Corresponds to the high bits of `_format_flags` in python
34 /// Corresponds to the high bits of `_format_flags` in python
35 impl IndexHeaderFlags {
35 impl IndexHeaderFlags {
36 /// Corresponds to FLAG_INLINE_DATA in python
36 /// Corresponds to FLAG_INLINE_DATA in python
37 pub fn is_inline(self) -> bool {
37 pub fn is_inline(self) -> bool {
38 self.flags & 1 != 0
38 self.flags & 1 != 0
39 }
39 }
40 /// Corresponds to FLAG_GENERALDELTA in python
40 /// Corresponds to FLAG_GENERALDELTA in python
41 pub fn uses_generaldelta(self) -> bool {
41 pub fn uses_generaldelta(self) -> bool {
42 self.flags & 2 != 0
42 self.flags & 2 != 0
43 }
43 }
44 }
44 }
45
45
46 /// Corresponds to the INDEX_HEADER structure,
46 /// Corresponds to the INDEX_HEADER structure,
47 /// which is parsed as a `header` variable in `_loadindex` in `revlog.py`
47 /// which is parsed as a `header` variable in `_loadindex` in `revlog.py`
48 impl IndexHeader {
48 impl IndexHeader {
49 fn format_flags(&self) -> IndexHeaderFlags {
49 fn format_flags(&self) -> IndexHeaderFlags {
50 // No "unknown flags" check here, unlike in python. Maybe there should
50 // No "unknown flags" check here, unlike in python. Maybe there should
51 // be.
51 // be.
52 IndexHeaderFlags {
52 IndexHeaderFlags {
53 flags: BigEndian::read_u16(&self.header_bytes[0..2]),
53 flags: BigEndian::read_u16(&self.header_bytes[0..2]),
54 }
54 }
55 }
55 }
56
56
57 /// The only revlog version currently supported by rhg.
57 /// The only revlog version currently supported by rhg.
58 const REVLOGV1: u16 = 1;
58 const REVLOGV1: u16 = 1;
59
59
60 /// Corresponds to `_format_version` in Python.
60 /// Corresponds to `_format_version` in Python.
61 fn format_version(&self) -> u16 {
61 fn format_version(&self) -> u16 {
62 BigEndian::read_u16(&self.header_bytes[2..4])
62 BigEndian::read_u16(&self.header_bytes[2..4])
63 }
63 }
64
64
65 pub fn parse(index_bytes: &[u8]) -> Result<Option<IndexHeader>, HgError> {
65 pub fn parse(index_bytes: &[u8]) -> Result<Option<IndexHeader>, HgError> {
66 if index_bytes.is_empty() {
66 if index_bytes.is_empty() {
67 return Ok(None);
67 return Ok(None);
68 }
68 }
69 if index_bytes.len() < 4 {
69 if index_bytes.len() < 4 {
70 return Err(HgError::corrupted(
70 return Err(HgError::corrupted(
71 "corrupted revlog: can't read the index format header",
71 "corrupted revlog: can't read the index format header",
72 ));
72 ));
73 }
73 }
74 Ok(Some(IndexHeader {
74 Ok(Some(IndexHeader {
75 header_bytes: {
75 header_bytes: {
76 let bytes: [u8; 4] =
76 let bytes: [u8; 4] =
77 index_bytes[0..4].try_into().expect("impossible");
77 index_bytes[0..4].try_into().expect("impossible");
78 bytes
78 bytes
79 },
79 },
80 }))
80 }))
81 }
81 }
82 }
82 }
83
83
84 /// Abstracts the access to the index bytes since they can be spread between
84 /// Abstracts the access to the index bytes since they can be spread between
85 /// the immutable (bytes) part and the mutable (added) part if any appends
85 /// the immutable (bytes) part and the mutable (added) part if any appends
86 /// happened. This makes it transparent for the callers.
86 /// happened. This makes it transparent for the callers.
87 struct IndexData {
87 struct IndexData {
88 /// Immutable bytes, most likely taken from disk
88 /// Immutable bytes, most likely taken from disk
89 bytes: Box<dyn Deref<Target = [u8]> + Send + Sync>,
89 bytes: Box<dyn Deref<Target = [u8]> + Send + Sync>,
90 /// Used when stripping index contents, keeps track of the start of the
90 /// Used when stripping index contents, keeps track of the start of the
91 /// first stripped revision, which is used to give a slice of the
91 /// first stripped revision, which is used to give a slice of the
92 /// `bytes` field.
92 /// `bytes` field.
93 truncation: Option<usize>,
93 truncation: Option<usize>,
94 /// Bytes that were added after reading the index
94 /// Bytes that were added after reading the index
95 added: Vec<u8>,
95 added: Vec<u8>,
96 first_entry: [u8; INDEX_ENTRY_SIZE],
96 first_entry: [u8; INDEX_ENTRY_SIZE],
97 }
97 }
98
98
99 impl IndexData {
99 impl IndexData {
100 pub fn new(bytes: Box<dyn Deref<Target = [u8]> + Send + Sync>) -> Self {
100 pub fn new(bytes: Box<dyn Deref<Target = [u8]> + Send + Sync>) -> Self {
101 let mut first_entry = [0; INDEX_ENTRY_SIZE];
101 let mut first_entry = [0; INDEX_ENTRY_SIZE];
102 if bytes.len() >= INDEX_ENTRY_SIZE {
102 if bytes.len() >= INDEX_ENTRY_SIZE {
103 first_entry[INDEX_HEADER_SIZE..]
103 first_entry[INDEX_HEADER_SIZE..]
104 .copy_from_slice(&bytes[INDEX_HEADER_SIZE..INDEX_ENTRY_SIZE])
104 .copy_from_slice(&bytes[INDEX_HEADER_SIZE..INDEX_ENTRY_SIZE])
105 }
105 }
106 Self {
106 Self {
107 bytes,
107 bytes,
108 truncation: None,
108 truncation: None,
109 added: vec![],
109 added: vec![],
110 first_entry,
110 first_entry,
111 }
111 }
112 }
112 }
113
113
114 pub fn len(&self) -> usize {
114 pub fn len(&self) -> usize {
115 match self.truncation {
115 match self.truncation {
116 Some(truncation) => truncation + self.added.len(),
116 Some(truncation) => truncation + self.added.len(),
117 None => self.bytes.len() + self.added.len(),
117 None => self.bytes.len() + self.added.len(),
118 }
118 }
119 }
119 }
120
120
121 fn remove(
121 fn remove(
122 &mut self,
122 &mut self,
123 rev: Revision,
123 rev: Revision,
124 offsets: Option<&[usize]>,
124 offsets: Option<&[usize]>,
125 ) -> Result<(), RevlogError> {
125 ) -> Result<(), RevlogError> {
126 let rev = rev.0 as usize;
126 let rev = rev.0 as usize;
127 let truncation = if let Some(offsets) = offsets {
127 let truncation = if let Some(offsets) = offsets {
128 offsets[rev]
128 offsets[rev]
129 } else {
129 } else {
130 rev * INDEX_ENTRY_SIZE
130 rev * INDEX_ENTRY_SIZE
131 };
131 };
132 if truncation < self.bytes.len() {
132 if truncation < self.bytes.len() {
133 self.truncation = Some(truncation);
133 self.truncation = Some(truncation);
134 self.added.clear();
134 self.added.clear();
135 } else {
135 } else {
136 self.added.truncate(truncation - self.bytes.len());
136 self.added.truncate(truncation - self.bytes.len());
137 }
137 }
138 Ok(())
138 Ok(())
139 }
139 }
140
140
141 fn is_new(&self) -> bool {
141 fn is_new(&self) -> bool {
142 self.bytes.is_empty()
142 self.bytes.is_empty()
143 }
143 }
144 }
144 }
145
145
146 impl std::ops::Index<std::ops::Range<usize>> for IndexData {
146 impl std::ops::Index<std::ops::Range<usize>> for IndexData {
147 type Output = [u8];
147 type Output = [u8];
148
148
149 fn index(&self, index: std::ops::Range<usize>) -> &Self::Output {
149 fn index(&self, index: std::ops::Range<usize>) -> &Self::Output {
150 let start = index.start;
150 let start = index.start;
151 let end = index.end;
151 let end = index.end;
152 let immutable_len = match self.truncation {
152 let immutable_len = match self.truncation {
153 Some(truncation) => truncation,
153 Some(truncation) => truncation,
154 None => self.bytes.len(),
154 None => self.bytes.len(),
155 };
155 };
156 if start < immutable_len {
156 if start < immutable_len {
157 if end > immutable_len {
157 if end > immutable_len {
158 panic!("index data cannot span existing and added ranges");
158 panic!("index data cannot span existing and added ranges");
159 }
159 }
160 &self.bytes[index]
160 &self.bytes[index]
161 } else {
161 } else {
162 &self.added[start - immutable_len..end - immutable_len]
162 &self.added[start - immutable_len..end - immutable_len]
163 }
163 }
164 }
164 }
165 }
165 }
166
166
167 #[derive(Debug, PartialEq, Eq)]
167 #[derive(Debug, PartialEq, Eq)]
168 pub struct RevisionDataParams {
168 pub struct RevisionDataParams {
169 pub flags: u16,
169 pub flags: u16,
170 pub data_offset: u64,
170 pub data_offset: u64,
171 pub data_compressed_length: i32,
171 pub data_compressed_length: i32,
172 pub data_uncompressed_length: i32,
172 pub data_uncompressed_length: i32,
173 pub data_delta_base: i32,
173 pub data_delta_base: i32,
174 pub link_rev: i32,
174 pub link_rev: i32,
175 pub parent_rev_1: i32,
175 pub parent_rev_1: i32,
176 pub parent_rev_2: i32,
176 pub parent_rev_2: i32,
177 pub node_id: [u8; NODE_BYTES_LENGTH],
177 pub node_id: [u8; NODE_BYTES_LENGTH],
178 pub _sidedata_offset: u64,
178 pub _sidedata_offset: u64,
179 pub _sidedata_compressed_length: i32,
179 pub _sidedata_compressed_length: i32,
180 pub data_compression_mode: u8,
180 pub data_compression_mode: u8,
181 pub _sidedata_compression_mode: u8,
181 pub _sidedata_compression_mode: u8,
182 pub _rank: i32,
182 pub _rank: i32,
183 }
183 }
184
184
185 impl Default for RevisionDataParams {
185 impl Default for RevisionDataParams {
186 fn default() -> Self {
186 fn default() -> Self {
187 Self {
187 Self {
188 flags: 0,
188 flags: 0,
189 data_offset: 0,
189 data_offset: 0,
190 data_compressed_length: 0,
190 data_compressed_length: 0,
191 data_uncompressed_length: 0,
191 data_uncompressed_length: 0,
192 data_delta_base: -1,
192 data_delta_base: -1,
193 link_rev: -1,
193 link_rev: -1,
194 parent_rev_1: -1,
194 parent_rev_1: -1,
195 parent_rev_2: -1,
195 parent_rev_2: -1,
196 node_id: [0; NODE_BYTES_LENGTH],
196 node_id: [0; NODE_BYTES_LENGTH],
197 _sidedata_offset: 0,
197 _sidedata_offset: 0,
198 _sidedata_compressed_length: 0,
198 _sidedata_compressed_length: 0,
199 data_compression_mode: COMPRESSION_MODE_INLINE,
199 data_compression_mode: COMPRESSION_MODE_INLINE,
200 _sidedata_compression_mode: COMPRESSION_MODE_INLINE,
200 _sidedata_compression_mode: COMPRESSION_MODE_INLINE,
201 _rank: -1,
201 _rank: -1,
202 }
202 }
203 }
203 }
204 }
204 }
205
205
206 #[derive(BytesCast)]
206 #[derive(BytesCast)]
207 #[repr(C)]
207 #[repr(C)]
208 pub struct RevisionDataV1 {
208 pub struct RevisionDataV1 {
209 data_offset_or_flags: unaligned::U64Be,
209 data_offset_or_flags: unaligned::U64Be,
210 data_compressed_length: unaligned::I32Be,
210 data_compressed_length: unaligned::I32Be,
211 data_uncompressed_length: unaligned::I32Be,
211 data_uncompressed_length: unaligned::I32Be,
212 data_delta_base: unaligned::I32Be,
212 data_delta_base: unaligned::I32Be,
213 link_rev: unaligned::I32Be,
213 link_rev: unaligned::I32Be,
214 parent_rev_1: unaligned::I32Be,
214 parent_rev_1: unaligned::I32Be,
215 parent_rev_2: unaligned::I32Be,
215 parent_rev_2: unaligned::I32Be,
216 node_id: [u8; STORED_NODE_ID_BYTES],
216 node_id: [u8; STORED_NODE_ID_BYTES],
217 }
217 }
218
218
219 fn _static_assert_size_of_revision_data_v1() {
219 fn _static_assert_size_of_revision_data_v1() {
220 let _ = std::mem::transmute::<RevisionDataV1, [u8; 64]>;
220 let _ = std::mem::transmute::<RevisionDataV1, [u8; 64]>;
221 }
221 }
222
222
223 impl RevisionDataParams {
223 impl RevisionDataParams {
224 pub fn validate(&self) -> Result<(), RevlogError> {
224 pub fn validate(&self) -> Result<(), RevlogError> {
225 if self.flags & !REVIDX_KNOWN_FLAGS != 0 {
225 if self.flags & !REVIDX_KNOWN_FLAGS != 0 {
226 return Err(RevlogError::corrupted(format!(
226 return Err(RevlogError::corrupted(format!(
227 "unknown revlog index flags: {}",
227 "unknown revlog index flags: {}",
228 self.flags
228 self.flags
229 )));
229 )));
230 }
230 }
231 if self.data_compression_mode != COMPRESSION_MODE_INLINE {
231 if self.data_compression_mode != COMPRESSION_MODE_INLINE {
232 return Err(RevlogError::corrupted(format!(
232 return Err(RevlogError::corrupted(format!(
233 "invalid data compression mode: {}",
233 "invalid data compression mode: {}",
234 self.data_compression_mode
234 self.data_compression_mode
235 )));
235 )));
236 }
236 }
237 // FIXME isn't this only for v2 or changelog v2?
237 // FIXME isn't this only for v2 or changelog v2?
238 if self._sidedata_compression_mode != COMPRESSION_MODE_INLINE {
238 if self._sidedata_compression_mode != COMPRESSION_MODE_INLINE {
239 return Err(RevlogError::corrupted(format!(
239 return Err(RevlogError::corrupted(format!(
240 "invalid sidedata compression mode: {}",
240 "invalid sidedata compression mode: {}",
241 self._sidedata_compression_mode
241 self._sidedata_compression_mode
242 )));
242 )));
243 }
243 }
244 Ok(())
244 Ok(())
245 }
245 }
246
246
247 pub fn into_v1(self) -> RevisionDataV1 {
247 pub fn into_v1(self) -> RevisionDataV1 {
248 let data_offset_or_flags = self.data_offset << 16 | self.flags as u64;
248 let data_offset_or_flags = self.data_offset << 16 | self.flags as u64;
249 let mut node_id = [0; STORED_NODE_ID_BYTES];
249 let mut node_id = [0; STORED_NODE_ID_BYTES];
250 node_id[..NODE_BYTES_LENGTH].copy_from_slice(&self.node_id);
250 node_id[..NODE_BYTES_LENGTH].copy_from_slice(&self.node_id);
251 RevisionDataV1 {
251 RevisionDataV1 {
252 data_offset_or_flags: data_offset_or_flags.into(),
252 data_offset_or_flags: data_offset_or_flags.into(),
253 data_compressed_length: self.data_compressed_length.into(),
253 data_compressed_length: self.data_compressed_length.into(),
254 data_uncompressed_length: self.data_uncompressed_length.into(),
254 data_uncompressed_length: self.data_uncompressed_length.into(),
255 data_delta_base: self.data_delta_base.into(),
255 data_delta_base: self.data_delta_base.into(),
256 link_rev: self.link_rev.into(),
256 link_rev: self.link_rev.into(),
257 parent_rev_1: self.parent_rev_1.into(),
257 parent_rev_1: self.parent_rev_1.into(),
258 parent_rev_2: self.parent_rev_2.into(),
258 parent_rev_2: self.parent_rev_2.into(),
259 node_id,
259 node_id,
260 }
260 }
261 }
261 }
262 }
262 }
263
263
264 /// A Revlog index
264 /// A Revlog index
265 pub struct Index {
265 pub struct Index {
266 bytes: IndexData,
266 bytes: IndexData,
267 /// Offsets of starts of index blocks.
267 /// Offsets of starts of index blocks.
268 /// Only needed when the index is interleaved with data.
268 /// Only needed when the index is interleaved with data.
269 offsets: RwLock<Option<Vec<usize>>>,
269 offsets: RwLock<Option<Vec<usize>>>,
270 uses_generaldelta: bool,
270 uses_generaldelta: bool,
271 is_inline: bool,
271 is_inline: bool,
272 /// Cache of (head_revisions, filtered_revisions)
272 /// Cache of (head_revisions, filtered_revisions)
273 ///
273 ///
274 /// The head revisions in this index, kept in sync. Should
274 /// The head revisions in this index, kept in sync. Should
275 /// be accessed via the [`Self::head_revs`] method.
275 /// be accessed via the [`Self::head_revs`] method.
276 /// The last filtered revisions in this index, used to make sure
276 /// The last filtered revisions in this index, used to make sure
277 /// we haven't changed filters when returning the cached `head_revs`.
277 /// we haven't changed filters when returning the cached `head_revs`.
278 head_revs: RwLock<(Vec<Revision>, HashSet<Revision>)>,
278 head_revs: RwLock<(Vec<Revision>, HashSet<Revision>)>,
279 }
279 }
280
280
281 impl Debug for Index {
281 impl Debug for Index {
282 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
282 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283 f.debug_struct("Index")
283 f.debug_struct("Index")
284 .field("offsets", &self.offsets)
284 .field("offsets", &self.offsets)
285 .field("uses_generaldelta", &self.uses_generaldelta)
285 .field("uses_generaldelta", &self.uses_generaldelta)
286 .finish()
286 .finish()
287 }
287 }
288 }
288 }
289
289
290 impl Graph for Index {
290 impl Graph for Index {
291 #[inline(always)]
291 #[inline(always)]
292 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
292 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
293 let err = || GraphError::ParentOutOfRange(rev);
293 let err = || GraphError::ParentOutOfRange(rev);
294 match self.get_entry(rev) {
294 match self.get_entry(rev) {
295 Some(entry) => {
295 Some(entry) => {
296 // The C implementation checks that the parents are valid
296 // The C implementation checks that the parents are valid
297 // before returning
297 // before returning
298 Ok([
298 Ok([
299 self.check_revision(entry.p1()).ok_or_else(err)?,
299 self.check_revision(entry.p1()).ok_or_else(err)?,
300 self.check_revision(entry.p2()).ok_or_else(err)?,
300 self.check_revision(entry.p2()).ok_or_else(err)?,
301 ])
301 ])
302 }
302 }
303 None => Ok([NULL_REVISION, NULL_REVISION]),
303 None => Ok([NULL_REVISION, NULL_REVISION]),
304 }
304 }
305 }
305 }
306 }
306 }
307
307
308 /// A cache suitable for find_snapshots
308 /// A cache suitable for find_snapshots
309 ///
309 ///
310 /// Logically equivalent to a mapping whose keys are [`BaseRevision`] and
310 /// Logically equivalent to a mapping whose keys are [`BaseRevision`] and
311 /// values sets of [`BaseRevision`]
311 /// values sets of [`BaseRevision`]
312 ///
312 ///
313 /// TODO the dubious part is insisting that errors must be RevlogError
313 /// TODO the dubious part is insisting that errors must be RevlogError
314 /// we would probably need to sprinkle some magic here, such as an associated
314 /// we would probably need to sprinkle some magic here, such as an associated
315 /// type that would be Into<RevlogError> but even that would not be
315 /// type that would be Into<RevlogError> but even that would not be
316 /// satisfactory, as errors potentially have nothing to do with the revlog.
316 /// satisfactory, as errors potentially have nothing to do with the revlog.
317 pub trait SnapshotsCache {
317 pub trait SnapshotsCache {
318 fn insert_for(
318 fn insert_for(
319 &mut self,
319 &mut self,
320 rev: BaseRevision,
320 rev: BaseRevision,
321 value: BaseRevision,
321 value: BaseRevision,
322 ) -> Result<(), RevlogError>;
322 ) -> Result<(), RevlogError>;
323 }
323 }
324
324
325 impl SnapshotsCache for FastHashMap<BaseRevision, HashSet<BaseRevision>> {
325 impl SnapshotsCache for FastHashMap<BaseRevision, HashSet<BaseRevision>> {
326 fn insert_for(
326 fn insert_for(
327 &mut self,
327 &mut self,
328 rev: BaseRevision,
328 rev: BaseRevision,
329 value: BaseRevision,
329 value: BaseRevision,
330 ) -> Result<(), RevlogError> {
330 ) -> Result<(), RevlogError> {
331 let all_values = self.entry(rev).or_default();
331 let all_values = self.entry(rev).or_default();
332 all_values.insert(value);
332 all_values.insert(value);
333 Ok(())
333 Ok(())
334 }
334 }
335 }
335 }
336
336
337 impl Index {
337 impl Index {
338 /// Create an index from bytes.
338 /// Create an index from bytes.
339 /// Calculate the start of each entry when is_inline is true.
339 /// Calculate the start of each entry when is_inline is true.
340 pub fn new(
340 pub fn new(
341 bytes: Box<dyn Deref<Target = [u8]> + Send + Sync>,
341 bytes: Box<dyn Deref<Target = [u8]> + Send + Sync>,
342 default_header: IndexHeader,
342 default_header: IndexHeader,
343 ) -> Result<Self, HgError> {
343 ) -> Result<Self, HgError> {
344 let header =
344 let header =
345 IndexHeader::parse(bytes.as_ref())?.unwrap_or(default_header);
345 IndexHeader::parse(bytes.as_ref())?.unwrap_or(default_header);
346
346
347 if header.format_version() != IndexHeader::REVLOGV1 {
347 if header.format_version() != IndexHeader::REVLOGV1 {
348 // A proper new version should have had a repo/store
348 // A proper new version should have had a repo/store
349 // requirement.
349 // requirement.
350 return Err(HgError::corrupted("unsupported revlog version"));
350 return Err(HgError::corrupted("unsupported revlog version"));
351 }
351 }
352
352
353 // This is only correct because we know version is REVLOGV1.
354 // In v2 we always use generaldelta, while in v0 we never use
355 // generaldelta. Similar for [is_inline] (it's only used in v1).
356 let uses_generaldelta = header.format_flags().uses_generaldelta();
353 let uses_generaldelta = header.format_flags().uses_generaldelta();
357
354
358 if header.format_flags().is_inline() {
355 if header.format_flags().is_inline() {
359 let mut offset: usize = 0;
356 let mut offset: usize = 0;
360 let mut offsets = Vec::new();
357 let mut offsets = Vec::new();
361
358
362 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
359 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
363 offsets.push(offset);
360 offsets.push(offset);
364 let end = offset + INDEX_ENTRY_SIZE;
361 let end = offset + INDEX_ENTRY_SIZE;
365 let entry = IndexEntry {
362 let entry = IndexEntry {
366 bytes: &bytes[offset..end],
363 bytes: &bytes[offset..end],
367 };
364 };
368
365
369 offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
366 offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
370 }
367 }
371
368
372 if offset == bytes.len() {
369 if offset == bytes.len() {
373 Ok(Self {
370 Ok(Self {
374 bytes: IndexData::new(bytes),
371 bytes: IndexData::new(bytes),
375 offsets: RwLock::new(Some(offsets)),
372 offsets: RwLock::new(Some(offsets)),
376 uses_generaldelta,
373 uses_generaldelta,
377 is_inline: true,
374 is_inline: true,
378 head_revs: RwLock::new((vec![], HashSet::new())),
375 head_revs: RwLock::new((vec![], HashSet::new())),
379 })
376 })
380 } else {
377 } else {
381 Err(HgError::corrupted("unexpected inline revlog length"))
378 Err(HgError::corrupted("unexpected inline revlog length"))
382 }
379 }
383 } else {
380 } else {
384 Ok(Self {
381 Ok(Self {
385 bytes: IndexData::new(bytes),
382 bytes: IndexData::new(bytes),
386 offsets: RwLock::new(None),
383 offsets: RwLock::new(None),
387 uses_generaldelta,
384 uses_generaldelta,
388 is_inline: false,
385 is_inline: false,
389 head_revs: RwLock::new((vec![], HashSet::new())),
386 head_revs: RwLock::new((vec![], HashSet::new())),
390 })
387 })
391 }
388 }
392 }
389 }
393
390
394 pub fn uses_generaldelta(&self) -> bool {
391 pub fn uses_generaldelta(&self) -> bool {
395 self.uses_generaldelta
392 self.uses_generaldelta
396 }
393 }
397
394
398 /// Value of the inline flag.
395 /// Value of the inline flag.
399 pub fn is_inline(&self) -> bool {
396 pub fn is_inline(&self) -> bool {
400 self.is_inline
397 self.is_inline
401 }
398 }
402
399
403 /// Return a slice of bytes if `revlog` is inline. Panic if not.
400 /// Return a slice of bytes if `revlog` is inline. Panic if not.
404 pub fn data(&self, start: usize, end: usize) -> &[u8] {
401 pub fn data(&self, start: usize, end: usize) -> &[u8] {
405 if !self.is_inline() {
402 if !self.is_inline() {
406 panic!("tried to access data in the index of a revlog that is not inline");
403 panic!("tried to access data in the index of a revlog that is not inline");
407 }
404 }
408 &self.bytes[start..end]
405 &self.bytes[start..end]
409 }
406 }
410
407
411 /// Return number of entries of the revlog index.
408 /// Return number of entries of the revlog index.
412 pub fn len(&self) -> usize {
409 pub fn len(&self) -> usize {
413 if self.is_inline() {
410 if self.is_inline() {
414 (*self.get_offsets())
411 (*self.get_offsets())
415 .as_ref()
412 .as_ref()
416 .expect("inline should have offsets")
413 .expect("inline should have offsets")
417 .len()
414 .len()
418 } else {
415 } else {
419 self.bytes.len() / INDEX_ENTRY_SIZE
416 self.bytes.len() / INDEX_ENTRY_SIZE
420 }
417 }
421 }
418 }
422
419
423 pub fn get_offsets(&self) -> RwLockReadGuard<Option<Vec<usize>>> {
420 pub fn get_offsets(&self) -> RwLockReadGuard<Option<Vec<usize>>> {
424 assert!(self.is_inline());
421 assert!(self.is_inline());
425 {
422 {
426 // Wrap in a block to drop the read guard
423 // Wrap in a block to drop the read guard
427 // TODO perf?
428 let mut offsets = self.offsets.write().unwrap();
424 let mut offsets = self.offsets.write().unwrap();
429 if offsets.is_none() {
425 if offsets.is_none() {
430 offsets.replace(inline_scan(&self.bytes.bytes).1);
426 offsets.replace(inline_scan(&self.bytes.bytes).1);
431 }
427 }
432 }
428 }
433 self.offsets.read().unwrap()
429 self.offsets.read().unwrap()
434 }
430 }
435
431
436 pub fn get_offsets_mut(&mut self) -> RwLockWriteGuard<Option<Vec<usize>>> {
432 pub fn get_offsets_mut(&mut self) -> RwLockWriteGuard<Option<Vec<usize>>> {
437 assert!(self.is_inline());
433 assert!(self.is_inline());
438 let mut offsets = self.offsets.write().unwrap();
434 let mut offsets = self.offsets.write().unwrap();
439 if offsets.is_none() {
435 if offsets.is_none() {
440 offsets.replace(inline_scan(&self.bytes.bytes).1);
436 offsets.replace(inline_scan(&self.bytes.bytes).1);
441 }
437 }
442 offsets
438 offsets
443 }
439 }
444
440
445 /// Returns `true` if the `Index` has zero `entries`.
441 /// Returns `true` if the `Index` has zero `entries`.
446 pub fn is_empty(&self) -> bool {
442 pub fn is_empty(&self) -> bool {
447 self.len() == 0
443 self.len() == 0
448 }
444 }
449
445
450 /// Return the index entry corresponding to the given revision or `None`
446 /// Return the index entry corresponding to the given revision or `None`
451 /// for [`NULL_REVISION`]
447 /// for [`NULL_REVISION`]
452 ///
448 ///
453 /// The specified revision being of the checked type, it always exists
449 /// The specified revision being of the checked type, it always exists
454 /// if it was validated by this index.
450 /// if it was validated by this index.
455 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
451 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
456 if rev == NULL_REVISION {
452 if rev == NULL_REVISION {
457 return None;
453 return None;
458 }
454 }
459 if rev.0 == 0 {
455 if rev.0 == 0 {
460 Some(IndexEntry {
456 Some(IndexEntry {
461 bytes: &self.bytes.first_entry[..],
457 bytes: &self.bytes.first_entry[..],
462 })
458 })
463 } else {
459 } else {
464 Some(if self.is_inline() {
460 Some(if self.is_inline() {
465 self.get_entry_inline(rev)
461 self.get_entry_inline(rev)
466 } else {
462 } else {
467 self.get_entry_separated(rev)
463 self.get_entry_separated(rev)
468 })
464 })
469 }
465 }
470 }
466 }
471
467
472 /// Return the binary content of the index entry for the given revision
468 /// Return the binary content of the index entry for the given revision
473 ///
469 ///
474 /// See [get_entry()](`Self::get_entry()`) for cases when `None` is
470 /// See [get_entry()](`Self::get_entry()`) for cases when `None` is
475 /// returned.
471 /// returned.
476 pub fn entry_binary(&self, rev: Revision) -> Option<&[u8]> {
472 pub fn entry_binary(&self, rev: Revision) -> Option<&[u8]> {
477 self.get_entry(rev).map(|e| {
473 self.get_entry(rev).map(|e| {
478 let bytes = e.as_bytes();
474 let bytes = e.as_bytes();
479 if rev.0 == 0 {
475 if rev.0 == 0 {
480 &bytes[4..]
476 &bytes[4..]
481 } else {
477 } else {
482 bytes
478 bytes
483 }
479 }
484 })
480 })
485 }
481 }
486
482
487 pub fn entry_as_params(
483 pub fn entry_as_params(
488 &self,
484 &self,
489 rev: UncheckedRevision,
485 rev: UncheckedRevision,
490 ) -> Option<RevisionDataParams> {
486 ) -> Option<RevisionDataParams> {
491 let rev = self.check_revision(rev)?;
487 let rev = self.check_revision(rev)?;
492 self.get_entry(rev).map(|e| RevisionDataParams {
488 self.get_entry(rev).map(|e| RevisionDataParams {
493 flags: e.flags(),
489 flags: e.flags(),
494 data_offset: if rev.0 == 0 && !self.bytes.is_new() {
490 data_offset: if rev.0 == 0 && !self.bytes.is_new() {
495 e.flags() as u64
491 e.flags() as u64
496 } else {
492 } else {
497 e.raw_offset()
493 e.raw_offset()
498 },
494 },
499 data_compressed_length: e
495 data_compressed_length: e
500 .compressed_len()
496 .compressed_len()
501 .try_into()
497 .try_into()
502 .unwrap_or_else(|_| {
498 .unwrap_or_else(|_| {
503 // Python's `unionrepo` sets the compressed length to be
499 // Python's `unionrepo` sets the compressed length to be
504 // `-1` (or `u32::MAX` if transmuted to `u32`) because it
500 // `-1` (or `u32::MAX` if transmuted to `u32`) because it
505 // cannot know the correct compressed length of a given
501 // cannot know the correct compressed length of a given
506 // revision. I'm not sure if this is true, but having this
502 // revision. I'm not sure if this is true, but having this
507 // edge case won't hurt other use cases, let's handle it.
503 // edge case won't hurt other use cases, let's handle it.
508 assert_eq!(e.compressed_len(), u32::MAX);
504 assert_eq!(e.compressed_len(), u32::MAX);
509 NULL_REVISION.0
505 NULL_REVISION.0
510 }),
506 }),
511 data_uncompressed_length: e.uncompressed_len(),
507 data_uncompressed_length: e.uncompressed_len(),
512 data_delta_base: e.base_revision_or_base_of_delta_chain().0,
508 data_delta_base: e.base_revision_or_base_of_delta_chain().0,
513 link_rev: e.link_revision().0,
509 link_rev: e.link_revision().0,
514 parent_rev_1: e.p1().0,
510 parent_rev_1: e.p1().0,
515 parent_rev_2: e.p2().0,
511 parent_rev_2: e.p2().0,
516 node_id: e.hash().as_bytes().try_into().unwrap(),
512 node_id: e.hash().as_bytes().try_into().unwrap(),
517 ..Default::default()
513 ..Default::default()
518 })
514 })
519 }
515 }
520
516
521 fn get_entry_inline(&self, rev: Revision) -> IndexEntry {
517 fn get_entry_inline(&self, rev: Revision) -> IndexEntry {
522 let offsets = &self.get_offsets();
518 let offsets = &self.get_offsets();
523 let offsets = offsets.as_ref().expect("inline should have offsets");
519 let offsets = offsets.as_ref().expect("inline should have offsets");
524 let start = offsets[rev.0 as usize];
520 let start = offsets[rev.0 as usize];
525 let end = start + INDEX_ENTRY_SIZE;
521 let end = start + INDEX_ENTRY_SIZE;
526 let bytes = &self.bytes[start..end];
522 let bytes = &self.bytes[start..end];
527
523
528 IndexEntry { bytes }
524 IndexEntry { bytes }
529 }
525 }
530
526
531 fn get_entry_separated(&self, rev: Revision) -> IndexEntry {
527 fn get_entry_separated(&self, rev: Revision) -> IndexEntry {
532 let start = rev.0 as usize * INDEX_ENTRY_SIZE;
528 let start = rev.0 as usize * INDEX_ENTRY_SIZE;
533 let end = start + INDEX_ENTRY_SIZE;
529 let end = start + INDEX_ENTRY_SIZE;
534 let bytes = &self.bytes[start..end];
530 let bytes = &self.bytes[start..end];
535
531
536 IndexEntry { bytes }
532 IndexEntry { bytes }
537 }
533 }
538
534
539 fn null_entry(&self) -> IndexEntry {
535 fn null_entry(&self) -> IndexEntry {
540 IndexEntry {
536 IndexEntry {
541 bytes: &[0; INDEX_ENTRY_SIZE],
537 bytes: &[0; INDEX_ENTRY_SIZE],
542 }
538 }
543 }
539 }
544
540
545 /// Return the head revisions of this index
541 /// Return the head revisions of this index
546 pub fn head_revs(&self) -> Result<Vec<Revision>, GraphError> {
542 pub fn head_revs(&self) -> Result<Vec<Revision>, GraphError> {
547 self.head_revs_filtered(&HashSet::new(), false)
543 self.head_revs_filtered(&HashSet::new(), false)
548 .map(|h| h.unwrap())
544 .map(|h| h.unwrap())
549 }
545 }
550
546
551 /// Python-specific shortcut to save on PyList creation
547 /// Python-specific shortcut to save on PyList creation
552 pub fn head_revs_shortcut(
548 pub fn head_revs_shortcut(
553 &self,
549 &self,
554 ) -> Result<Option<Vec<Revision>>, GraphError> {
550 ) -> Result<Option<Vec<Revision>>, GraphError> {
555 self.head_revs_filtered(&HashSet::new(), true)
551 self.head_revs_filtered(&HashSet::new(), true)
556 }
552 }
557
553
558 /// Return the heads removed and added by advancing from `begin` to `end`.
554 /// Return the heads removed and added by advancing from `begin` to `end`.
559 /// In revset language, we compute:
555 /// In revset language, we compute:
560 /// - `heads(:begin)-heads(:end)`
556 /// - `heads(:begin)-heads(:end)`
561 /// - `heads(:end)-heads(:begin)`
557 /// - `heads(:end)-heads(:begin)`
562 pub fn head_revs_diff(
558 pub fn head_revs_diff(
563 &self,
559 &self,
564 begin: Revision,
560 begin: Revision,
565 end: Revision,
561 end: Revision,
566 ) -> Result<(Vec<Revision>, Vec<Revision>), GraphError> {
562 ) -> Result<(Vec<Revision>, Vec<Revision>), GraphError> {
567 let mut heads_added = vec![];
563 let mut heads_added = vec![];
568 let mut heads_removed = vec![];
564 let mut heads_removed = vec![];
569
565
570 let mut acc = HashSet::new();
566 let mut acc = HashSet::new();
571 let Revision(begin) = begin;
567 let Revision(begin) = begin;
572 let Revision(end) = end;
568 let Revision(end) = end;
573 let mut i = end;
569 let mut i = end;
574
570
575 while i > begin {
571 while i > begin {
576 // acc invariant:
572 // acc invariant:
577 // `j` is in the set iff `j <= i` and it has children
573 // `j` is in the set iff `j <= i` and it has children
578 // among `i+1..end` (inclusive)
574 // among `i+1..end` (inclusive)
579 if !acc.remove(&i) {
575 if !acc.remove(&i) {
580 heads_added.push(Revision(i));
576 heads_added.push(Revision(i));
581 }
577 }
582 for Revision(parent) in self.parents(Revision(i))? {
578 for Revision(parent) in self.parents(Revision(i))? {
583 acc.insert(parent);
579 acc.insert(parent);
584 }
580 }
585 i -= 1;
581 i -= 1;
586 }
582 }
587
583
588 // At this point `acc` contains old revisions that gained new children.
584 // At this point `acc` contains old revisions that gained new children.
589 // We need to check if they had any children before. If not, those
585 // We need to check if they had any children before. If not, those
590 // revisions are the removed heads.
586 // revisions are the removed heads.
591 while !acc.is_empty() {
587 while !acc.is_empty() {
592 // acc invariant:
588 // acc invariant:
593 // `j` is in the set iff `j <= i` and it has children
589 // `j` is in the set iff `j <= i` and it has children
594 // among `begin+1..end`, but not among `i+1..begin` (inclusive)
590 // among `begin+1..end`, but not among `i+1..begin` (inclusive)
595
591
596 assert!(i >= -1); // yes, `-1` can also be a head if the repo is empty
592 assert!(i >= -1); // yes, `-1` can also be a head if the repo is empty
597 if acc.remove(&i) {
593 if acc.remove(&i) {
598 heads_removed.push(Revision(i));
594 heads_removed.push(Revision(i));
599 }
595 }
600 for Revision(parent) in self.parents(Revision(i))? {
596 for Revision(parent) in self.parents(Revision(i))? {
601 acc.remove(&parent);
597 acc.remove(&parent);
602 }
598 }
603 i -= 1;
599 i -= 1;
604 }
600 }
605
601
606 Ok((heads_removed, heads_added))
602 Ok((heads_removed, heads_added))
607 }
603 }
608
604
609 /// Return the head revisions of this index
605 /// Return the head revisions of this index
610 pub fn head_revs_filtered(
606 pub fn head_revs_filtered(
611 &self,
607 &self,
612 filtered_revs: &HashSet<Revision>,
608 filtered_revs: &HashSet<Revision>,
613 py_shortcut: bool,
609 py_shortcut: bool,
614 ) -> Result<Option<Vec<Revision>>, GraphError> {
610 ) -> Result<Option<Vec<Revision>>, GraphError> {
615 {
611 {
616 let guard = self
612 let guard = self
617 .head_revs
613 .head_revs
618 .read()
614 .read()
619 .expect("RwLock on Index.head_revs should not be poisoned");
615 .expect("RwLock on Index.head_revs should not be poisoned");
620 let self_head_revs = &guard.0;
616 let self_head_revs = &guard.0;
621 let self_filtered_revs = &guard.1;
617 let self_filtered_revs = &guard.1;
622 if !self_head_revs.is_empty()
618 if !self_head_revs.is_empty()
623 && filtered_revs == self_filtered_revs
619 && filtered_revs == self_filtered_revs
624 {
620 {
625 if py_shortcut {
621 if py_shortcut {
626 // Don't copy the revs since we've already cached them
622 // Don't copy the revs since we've already cached them
627 // on the Python side.
623 // on the Python side.
628 return Ok(None);
624 return Ok(None);
629 } else {
625 } else {
630 return Ok(Some(self_head_revs.to_owned()));
626 return Ok(Some(self_head_revs.to_owned()));
631 }
627 }
632 }
628 }
633 }
629 }
634
630
635 let as_vec = if self.is_empty() {
631 let as_vec = if self.is_empty() {
636 vec![NULL_REVISION]
632 vec![NULL_REVISION]
637 } else {
633 } else {
638 let mut not_heads = bitvec![0; self.len()];
634 let mut not_heads = bitvec![0; self.len()];
639 dagops::retain_heads_fast(
635 dagops::retain_heads_fast(
640 self,
636 self,
641 not_heads.as_mut_bitslice(),
637 not_heads.as_mut_bitslice(),
642 filtered_revs,
638 filtered_revs,
643 )?;
639 )?;
644 not_heads
640 not_heads
645 .into_iter()
641 .into_iter()
646 .enumerate()
642 .enumerate()
647 .filter_map(|(idx, is_not_head)| {
643 .filter_map(|(idx, is_not_head)| {
648 if is_not_head {
644 if is_not_head {
649 None
645 None
650 } else {
646 } else {
651 Some(Revision(idx as BaseRevision))
647 Some(Revision(idx as BaseRevision))
652 }
648 }
653 })
649 })
654 .collect()
650 .collect()
655 };
651 };
656 *self
652 *self
657 .head_revs
653 .head_revs
658 .write()
654 .write()
659 .expect("RwLock on Index.head_revs should not be poisoned") =
655 .expect("RwLock on Index.head_revs should not be poisoned") =
660 (as_vec.to_owned(), filtered_revs.to_owned());
656 (as_vec.to_owned(), filtered_revs.to_owned());
661 Ok(Some(as_vec))
657 Ok(Some(as_vec))
662 }
658 }
663
659
664 /// Obtain the delta chain for a revision.
660 /// Obtain the delta chain for a revision.
665 ///
661 ///
666 /// `stop_rev` specifies a revision to stop at. If not specified, we
662 /// `stop_rev` specifies a revision to stop at. If not specified, we
667 /// stop at the base of the chain.
663 /// stop at the base of the chain.
668 ///
664 ///
669 /// Returns a 2-tuple of (chain, stopped) where `chain` is a vec of
665 /// Returns a 2-tuple of (chain, stopped) where `chain` is a vec of
670 /// revs in ascending order and `stopped` is a bool indicating whether
666 /// revs in ascending order and `stopped` is a bool indicating whether
671 /// `stoprev` was hit.
667 /// `stoprev` was hit.
672 pub fn delta_chain(
668 pub fn delta_chain(
673 &self,
669 &self,
674 rev: Revision,
670 rev: Revision,
675 stop_rev: Option<Revision>,
671 stop_rev: Option<Revision>,
676 using_general_delta: Option<bool>,
672 using_general_delta: Option<bool>,
677 ) -> Result<(Vec<Revision>, bool), HgError> {
673 ) -> Result<(Vec<Revision>, bool), HgError> {
678 let mut current_rev = rev;
674 let mut current_rev = rev;
679 let mut entry = self.get_entry(rev).unwrap();
675 let mut entry = self.get_entry(rev).unwrap();
680 let mut chain = vec![];
676 let mut chain = vec![];
681 let using_general_delta =
677 let using_general_delta =
682 using_general_delta.unwrap_or_else(|| self.uses_generaldelta());
678 using_general_delta.unwrap_or_else(|| self.uses_generaldelta());
683 while current_rev.0 != entry.base_revision_or_base_of_delta_chain().0
679 while current_rev.0 != entry.base_revision_or_base_of_delta_chain().0
684 && stop_rev.map(|r| r != current_rev).unwrap_or(true)
680 && stop_rev.map(|r| r != current_rev).unwrap_or(true)
685 {
681 {
686 chain.push(current_rev);
682 chain.push(current_rev);
687 let new_rev = if using_general_delta {
683 let new_rev = if using_general_delta {
688 entry.base_revision_or_base_of_delta_chain()
684 entry.base_revision_or_base_of_delta_chain()
689 } else {
685 } else {
690 UncheckedRevision(current_rev.0 - 1)
686 UncheckedRevision(current_rev.0 - 1)
691 };
687 };
692 current_rev = self.check_revision(new_rev).ok_or_else(|| {
688 current_rev = self.check_revision(new_rev).ok_or_else(|| {
693 HgError::corrupted(format!("Revision {new_rev} out of range"))
689 HgError::corrupted(format!("Revision {new_rev} out of range"))
694 })?;
690 })?;
695 if current_rev.0 == NULL_REVISION.0 {
691 if current_rev.0 == NULL_REVISION.0 {
696 break;
692 break;
697 }
693 }
698 entry = self.get_entry(current_rev).unwrap()
694 entry = self.get_entry(current_rev).unwrap()
699 }
695 }
700
696
701 let stopped = if stop_rev.map(|r| current_rev == r).unwrap_or(false) {
697 let stopped = if stop_rev.map(|r| current_rev == r).unwrap_or(false) {
702 true
698 true
703 } else {
699 } else {
704 chain.push(current_rev);
700 chain.push(current_rev);
705 false
701 false
706 };
702 };
707 chain.reverse();
703 chain.reverse();
708 Ok((chain, stopped))
704 Ok((chain, stopped))
709 }
705 }
710
706
711 pub fn find_snapshots(
707 pub fn find_snapshots(
712 &self,
708 &self,
713 start_rev: UncheckedRevision,
709 start_rev: UncheckedRevision,
714 end_rev: UncheckedRevision,
710 end_rev: UncheckedRevision,
715 cache: &mut impl SnapshotsCache,
711 cache: &mut impl SnapshotsCache,
716 ) -> Result<(), RevlogError> {
712 ) -> Result<(), RevlogError> {
717 let mut start_rev = start_rev.0;
713 let mut start_rev = start_rev.0;
718 let mut end_rev = end_rev.0;
714 let mut end_rev = end_rev.0;
719 end_rev += 1;
715 end_rev += 1;
720 let len = self.len().try_into().unwrap();
716 let len = self.len().try_into().unwrap();
721 if end_rev > len {
717 if end_rev > len {
722 end_rev = len;
718 end_rev = len;
723 }
719 }
724 if start_rev < 0 {
720 if start_rev < 0 {
725 start_rev = 0;
721 start_rev = 0;
726 }
722 }
727 for rev in start_rev..end_rev {
723 for rev in start_rev..end_rev {
728 if !self.is_snapshot_unchecked(Revision(rev))? {
724 if !self.is_snapshot_unchecked(Revision(rev))? {
729 continue;
725 continue;
730 }
726 }
731 let mut base = self
727 let mut base = self
732 .get_entry(Revision(rev))
728 .get_entry(Revision(rev))
733 .unwrap()
729 .unwrap()
734 .base_revision_or_base_of_delta_chain();
730 .base_revision_or_base_of_delta_chain();
735 if base.0 == rev {
731 if base.0 == rev {
736 base = NULL_REVISION.into();
732 base = NULL_REVISION.into();
737 }
733 }
738 cache.insert_for(base.0, rev)?;
734 cache.insert_for(base.0, rev)?;
739 }
735 }
740 Ok(())
736 Ok(())
741 }
737 }
742
738
743 fn clear_head_revs(&self) {
739 fn clear_head_revs(&self) {
744 self.head_revs
740 self.head_revs
745 .write()
741 .write()
746 .expect("RwLock on Index.head_revs should not be poisoined")
742 .expect("RwLock on Index.head_revs should not be poisoined")
747 .0
743 .0
748 .clear()
744 .clear()
749 }
745 }
750
746
751 /// TODO move this to the trait probably, along with other things
747 /// TODO move this to the trait probably, along with other things
752 pub fn append(
748 pub fn append(
753 &mut self,
749 &mut self,
754 revision_data: RevisionDataParams,
750 revision_data: RevisionDataParams,
755 ) -> Result<(), RevlogError> {
751 ) -> Result<(), RevlogError> {
756 revision_data.validate()?;
752 revision_data.validate()?;
757 let entry_v1 = revision_data.into_v1();
753 let entry_v1 = revision_data.into_v1();
758 let entry_bytes = entry_v1.as_bytes();
754 let entry_bytes = entry_v1.as_bytes();
759 if self.bytes.len() == 0 {
755 if self.bytes.len() == 0 {
760 self.bytes.first_entry[INDEX_HEADER_SIZE..].copy_from_slice(
756 self.bytes.first_entry[INDEX_HEADER_SIZE..].copy_from_slice(
761 &entry_bytes[INDEX_HEADER_SIZE..INDEX_ENTRY_SIZE],
757 &entry_bytes[INDEX_HEADER_SIZE..INDEX_ENTRY_SIZE],
762 )
758 )
763 }
759 }
764 if self.is_inline() {
760 if self.is_inline() {
765 let new_offset = self.bytes.len();
761 let new_offset = self.bytes.len();
766 if let Some(offsets) = &mut *self.get_offsets_mut() {
762 if let Some(offsets) = &mut *self.get_offsets_mut() {
767 offsets.push(new_offset)
763 offsets.push(new_offset)
768 }
764 }
769 }
765 }
770 self.bytes.added.extend(entry_bytes);
766 self.bytes.added.extend(entry_bytes);
771 self.clear_head_revs();
767 self.clear_head_revs();
772 Ok(())
768 Ok(())
773 }
769 }
774
770
775 pub fn pack_header(&self, header: i32) -> [u8; 4] {
771 pub fn pack_header(&self, header: i32) -> [u8; 4] {
776 header.to_be_bytes()
772 header.to_be_bytes()
777 }
773 }
778
774
779 pub fn remove(&mut self, rev: Revision) -> Result<(), RevlogError> {
775 pub fn remove(&mut self, rev: Revision) -> Result<(), RevlogError> {
780 let offsets = if self.is_inline() {
776 let offsets = if self.is_inline() {
781 self.get_offsets().clone()
777 self.get_offsets().clone()
782 } else {
778 } else {
783 None
779 None
784 };
780 };
785 self.bytes.remove(rev, offsets.as_deref())?;
781 self.bytes.remove(rev, offsets.as_deref())?;
786 if self.is_inline() {
782 if self.is_inline() {
787 if let Some(offsets) = &mut *self.get_offsets_mut() {
783 if let Some(offsets) = &mut *self.get_offsets_mut() {
788 offsets.truncate(rev.0 as usize)
784 offsets.truncate(rev.0 as usize)
789 }
785 }
790 }
786 }
791 self.clear_head_revs();
787 self.clear_head_revs();
792 Ok(())
788 Ok(())
793 }
789 }
794
790
795 pub fn clear_caches(&self) {
791 pub fn clear_caches(&self) {
796 // We need to get the 'inline' value from Python at init and use this
792 // We need to get the 'inline' value from Python at init and use this
797 // instead of offsets to determine whether we're inline since we might
793 // instead of offsets to determine whether we're inline since we might
798 // clear caches. This implies re-populating the offsets on-demand.
794 // clear caches. This implies re-populating the offsets on-demand.
799 *self
795 *self
800 .offsets
796 .offsets
801 .write()
797 .write()
802 .expect("RwLock on Index.offsets should not be poisoed") = None;
798 .expect("RwLock on Index.offsets should not be poisoed") = None;
803 self.clear_head_revs();
799 self.clear_head_revs();
804 }
800 }
805
801
806 /// Unchecked version of `is_snapshot`.
802 /// Unchecked version of `is_snapshot`.
807 /// Assumes the caller checked that `rev` is within a valid revision range.
803 /// Assumes the caller checked that `rev` is within a valid revision range.
808 pub fn is_snapshot_unchecked(
804 pub fn is_snapshot_unchecked(
809 &self,
805 &self,
810 mut rev: Revision,
806 mut rev: Revision,
811 ) -> Result<bool, RevlogError> {
807 ) -> Result<bool, RevlogError> {
812 while rev.0 >= 0 {
808 while rev.0 >= 0 {
813 let entry = self.get_entry(rev).unwrap();
809 let entry = self.get_entry(rev).unwrap();
814 let mut base = entry.base_revision_or_base_of_delta_chain().0;
810 let mut base = entry.base_revision_or_base_of_delta_chain().0;
815 if base == rev.0 {
811 if base == rev.0 {
816 base = NULL_REVISION.0;
812 base = NULL_REVISION.0;
817 }
813 }
818 if base == NULL_REVISION.0 {
814 if base == NULL_REVISION.0 {
819 return Ok(true);
815 return Ok(true);
820 }
816 }
821 let [mut p1, mut p2] = self
817 let [mut p1, mut p2] = self
822 .parents(rev)
818 .parents(rev)
823 .map_err(|_| RevlogError::InvalidRevision)?;
819 .map_err(|_| RevlogError::InvalidRevision)?;
824 while let Some(p1_entry) = self.get_entry(p1) {
820 while let Some(p1_entry) = self.get_entry(p1) {
825 if p1_entry.compressed_len() != 0 || p1.0 == 0 {
821 if p1_entry.compressed_len() != 0 || p1.0 == 0 {
826 break;
822 break;
827 }
823 }
828 let parent_base =
824 let parent_base =
829 p1_entry.base_revision_or_base_of_delta_chain();
825 p1_entry.base_revision_or_base_of_delta_chain();
830 if parent_base.0 == p1.0 {
826 if parent_base.0 == p1.0 {
831 break;
827 break;
832 }
828 }
833 p1 = self
829 p1 = self
834 .check_revision(parent_base)
830 .check_revision(parent_base)
835 .ok_or(RevlogError::InvalidRevision)?;
831 .ok_or(RevlogError::InvalidRevision)?;
836 }
832 }
837 while let Some(p2_entry) = self.get_entry(p2) {
833 while let Some(p2_entry) = self.get_entry(p2) {
838 if p2_entry.compressed_len() != 0 || p2.0 == 0 {
834 if p2_entry.compressed_len() != 0 || p2.0 == 0 {
839 break;
835 break;
840 }
836 }
841 let parent_base =
837 let parent_base =
842 p2_entry.base_revision_or_base_of_delta_chain();
838 p2_entry.base_revision_or_base_of_delta_chain();
843 if parent_base.0 == p2.0 {
839 if parent_base.0 == p2.0 {
844 break;
840 break;
845 }
841 }
846 p2 = self
842 p2 = self
847 .check_revision(parent_base)
843 .check_revision(parent_base)
848 .ok_or(RevlogError::InvalidRevision)?;
844 .ok_or(RevlogError::InvalidRevision)?;
849 }
845 }
850 if base == p1.0 || base == p2.0 {
846 if base == p1.0 || base == p2.0 {
851 return Ok(false);
847 return Ok(false);
852 }
848 }
853 rev = self
849 rev = self
854 .check_revision(base.into())
850 .check_revision(base.into())
855 .ok_or(RevlogError::InvalidRevision)?;
851 .ok_or(RevlogError::InvalidRevision)?;
856 }
852 }
857 Ok(rev == NULL_REVISION)
853 Ok(rev == NULL_REVISION)
858 }
854 }
859
855
860 /// Return whether the given revision is a snapshot. Returns an error if
856 /// Return whether the given revision is a snapshot. Returns an error if
861 /// `rev` is not within a valid revision range.
857 /// `rev` is not within a valid revision range.
862 pub fn is_snapshot(
858 pub fn is_snapshot(
863 &self,
859 &self,
864 rev: UncheckedRevision,
860 rev: UncheckedRevision,
865 ) -> Result<bool, RevlogError> {
861 ) -> Result<bool, RevlogError> {
866 let rev = self
862 let rev = self
867 .check_revision(rev)
863 .check_revision(rev)
868 .ok_or_else(|| RevlogError::corrupted("test"))?;
864 .ok_or_else(|| RevlogError::corrupted("test"))?;
869 self.is_snapshot_unchecked(rev)
865 self.is_snapshot_unchecked(rev)
870 }
866 }
871
867
872 /// Slice revs to reduce the amount of unrelated data to be read from disk.
868 /// Slice revs to reduce the amount of unrelated data to be read from disk.
873 ///
869 ///
874 /// The index is sliced into groups that should be read in one time.
870 /// The index is sliced into groups that should be read in one time.
875 ///
871 ///
876 /// The initial chunk is sliced until the overall density
872 /// The initial chunk is sliced until the overall density
877 /// (payload/chunks-span ratio) is above `target_density`.
873 /// (payload/chunks-span ratio) is above `target_density`.
878 /// No gap smaller than `min_gap_size` is skipped.
874 /// No gap smaller than `min_gap_size` is skipped.
879 pub fn slice_chunk_to_density(
875 pub fn slice_chunk_to_density(
880 &self,
876 &self,
881 revs: &[Revision],
877 revs: &[Revision],
882 target_density: f64,
878 target_density: f64,
883 min_gap_size: usize,
879 min_gap_size: usize,
884 ) -> Vec<Vec<Revision>> {
880 ) -> Vec<Vec<Revision>> {
885 if revs.is_empty() {
881 if revs.is_empty() {
886 return vec![];
882 return vec![];
887 }
883 }
888 if revs.len() == 1 {
884 if revs.len() == 1 {
889 return vec![revs.to_owned()];
885 return vec![revs.to_owned()];
890 }
886 }
891 let delta_chain_span = self.segment_span(revs);
887 let delta_chain_span = self.segment_span(revs);
892 if delta_chain_span < min_gap_size {
888 if delta_chain_span < min_gap_size {
893 return vec![revs.to_owned()];
889 return vec![revs.to_owned()];
894 }
890 }
895 let entries: Vec<_> = revs
891 let entries: Vec<_> = revs
896 .iter()
892 .iter()
897 .map(|r| {
893 .map(|r| {
898 (*r, self.get_entry(*r).unwrap_or_else(|| self.null_entry()))
894 (*r, self.get_entry(*r).unwrap_or_else(|| self.null_entry()))
899 })
895 })
900 .collect();
896 .collect();
901
897
902 let mut read_data = delta_chain_span;
898 let mut read_data = delta_chain_span;
903 let chain_payload: u32 =
899 let chain_payload: u32 =
904 entries.iter().map(|(_r, e)| e.compressed_len()).sum();
900 entries.iter().map(|(_r, e)| e.compressed_len()).sum();
905 let mut density = if delta_chain_span > 0 {
901 let mut density = if delta_chain_span > 0 {
906 chain_payload as f64 / delta_chain_span as f64
902 chain_payload as f64 / delta_chain_span as f64
907 } else {
903 } else {
908 1.0
904 1.0
909 };
905 };
910
906
911 if density >= target_density {
907 if density >= target_density {
912 return vec![revs.to_owned()];
908 return vec![revs.to_owned()];
913 }
909 }
914
910
915 // Store the gaps in a heap to have them sorted by decreasing size
911 // Store the gaps in a heap to have them sorted by decreasing size
916 let mut gaps = Vec::new();
912 let mut gaps = Vec::new();
917 let mut previous_end = None;
913 let mut previous_end = None;
918
914
919 for (i, (_rev, entry)) in entries.iter().enumerate() {
915 for (i, (_rev, entry)) in entries.iter().enumerate() {
920 let start = entry.c_start() as usize;
916 let start = entry.c_start() as usize;
921 let length = entry.compressed_len();
917 let length = entry.compressed_len();
922
918
923 // Skip empty revisions to form larger holes
919 // Skip empty revisions to form larger holes
924 if length == 0 {
920 if length == 0 {
925 continue;
921 continue;
926 }
922 }
927
923
928 if let Some(end) = previous_end {
924 if let Some(end) = previous_end {
929 let gap_size = start - end;
925 let gap_size = start - end;
930 // Only consider holes that are large enough
926 // Only consider holes that are large enough
931 if gap_size > min_gap_size {
927 if gap_size > min_gap_size {
932 gaps.push((gap_size, i));
928 gaps.push((gap_size, i));
933 }
929 }
934 }
930 }
935 previous_end = Some(start + length as usize);
931 previous_end = Some(start + length as usize);
936 }
932 }
937 if gaps.is_empty() {
933 if gaps.is_empty() {
938 return vec![revs.to_owned()];
934 return vec![revs.to_owned()];
939 }
935 }
940 // sort the gaps to pop them from largest to small
936 // sort the gaps to pop them from largest to small
941 gaps.sort_unstable();
937 gaps.sort_unstable();
942
938
943 // Collect the indices of the largest holes until
939 // Collect the indices of the largest holes until
944 // the density is acceptable
940 // the density is acceptable
945 let mut selected = vec![];
941 let mut selected = vec![];
946 while let Some((gap_size, gap_id)) = gaps.pop() {
942 while let Some((gap_size, gap_id)) = gaps.pop() {
947 if density >= target_density {
943 if density >= target_density {
948 break;
944 break;
949 }
945 }
950 selected.push(gap_id);
946 selected.push(gap_id);
951
947
952 // The gap sizes are stored as negatives to be sorted decreasingly
948 // The gap sizes are stored as negatives to be sorted decreasingly
953 // by the heap
949 // by the heap
954 read_data -= gap_size;
950 read_data -= gap_size;
955 density = if read_data > 0 {
951 density = if read_data > 0 {
956 chain_payload as f64 / read_data as f64
952 chain_payload as f64 / read_data as f64
957 } else {
953 } else {
958 1.0
954 1.0
959 };
955 };
960 if density >= target_density {
956 if density >= target_density {
961 break;
957 break;
962 }
958 }
963 }
959 }
964 selected.sort_unstable();
960 selected.sort_unstable();
965 selected.push(revs.len());
961 selected.push(revs.len());
966
962
967 // Cut the revs at collected indices
963 // Cut the revs at collected indices
968 let mut previous_idx = 0;
964 let mut previous_idx = 0;
969 let mut chunks = vec![];
965 let mut chunks = vec![];
970 for idx in selected {
966 for idx in selected {
971 let chunk = self.trim_chunk(&entries, previous_idx, idx);
967 let chunk = self.trim_chunk(&entries, previous_idx, idx);
972 if !chunk.is_empty() {
968 if !chunk.is_empty() {
973 chunks.push(chunk.iter().map(|(rev, _entry)| *rev).collect());
969 chunks.push(chunk.iter().map(|(rev, _entry)| *rev).collect());
974 }
970 }
975 previous_idx = idx;
971 previous_idx = idx;
976 }
972 }
977 let chunk = self.trim_chunk(&entries, previous_idx, entries.len());
973 let chunk = self.trim_chunk(&entries, previous_idx, entries.len());
978 if !chunk.is_empty() {
974 if !chunk.is_empty() {
979 chunks.push(chunk.iter().map(|(rev, _entry)| *rev).collect());
975 chunks.push(chunk.iter().map(|(rev, _entry)| *rev).collect());
980 }
976 }
981
977
982 chunks
978 chunks
983 }
979 }
984
980
985 /// Get the byte span of a segment of sorted revisions.
981 /// Get the byte span of a segment of sorted revisions.
986 ///
982 ///
987 /// Occurrences of [`NULL_REVISION`] are ignored at the beginning of
983 /// Occurrences of [`NULL_REVISION`] are ignored at the beginning of
988 /// the `revs` segment.
984 /// the `revs` segment.
989 ///
985 ///
990 /// panics:
986 /// panics:
991 /// - if `revs` is empty or only made of `NULL_REVISION`
987 /// - if `revs` is empty or only made of `NULL_REVISION`
992 /// - if cannot retrieve entry for the last or first not null element of
988 /// - if cannot retrieve entry for the last or first not null element of
993 /// `revs`.
989 /// `revs`.
994 fn segment_span(&self, revs: &[Revision]) -> usize {
990 fn segment_span(&self, revs: &[Revision]) -> usize {
995 if revs.is_empty() {
991 if revs.is_empty() {
996 return 0;
992 return 0;
997 }
993 }
998 let last_entry = &self.get_entry(revs[revs.len() - 1]).unwrap();
994 let last_entry = &self.get_entry(revs[revs.len() - 1]).unwrap();
999 let end = last_entry.c_start() + last_entry.compressed_len() as u64;
995 let end = last_entry.c_start() + last_entry.compressed_len() as u64;
1000 let first_rev = revs.iter().find(|r| r.0 != NULL_REVISION.0).unwrap();
996 let first_rev = revs.iter().find(|r| r.0 != NULL_REVISION.0).unwrap();
1001 let start = if first_rev.0 == 0 {
997 let start = if first_rev.0 == 0 {
1002 0
998 0
1003 } else {
999 } else {
1004 self.get_entry(*first_rev).unwrap().c_start()
1000 self.get_entry(*first_rev).unwrap().c_start()
1005 };
1001 };
1006 (end - start) as usize
1002 (end - start) as usize
1007 }
1003 }
1008
1004
1009 /// Returns `&revs[startidx..endidx]` without empty trailing revs
1005 /// Returns `&revs[startidx..endidx]` without empty trailing revs
1010 fn trim_chunk<'a>(
1006 fn trim_chunk<'a>(
1011 &'a self,
1007 &'a self,
1012 revs: &'a [(Revision, IndexEntry)],
1008 revs: &'a [(Revision, IndexEntry)],
1013 start: usize,
1009 start: usize,
1014 mut end: usize,
1010 mut end: usize,
1015 ) -> &'a [(Revision, IndexEntry)] {
1011 ) -> &'a [(Revision, IndexEntry)] {
1016 // Trim empty revs at the end, except the very first rev of a chain
1012 // Trim empty revs at the end, except the very first rev of a chain
1017 let last_rev = revs[end - 1].0;
1013 let last_rev = revs[end - 1].0;
1018 if last_rev.0 < self.len() as BaseRevision {
1014 if last_rev.0 < self.len() as BaseRevision {
1019 while end > 1
1015 while end > 1
1020 && end > start
1016 && end > start
1021 && revs[end - 1].1.compressed_len() == 0
1017 && revs[end - 1].1.compressed_len() == 0
1022 {
1018 {
1023 end -= 1
1019 end -= 1
1024 }
1020 }
1025 }
1021 }
1026 &revs[start..end]
1022 &revs[start..end]
1027 }
1023 }
1028
1024
1029 /// Computes the set of revisions for each non-public phase from `roots`,
1025 /// Computes the set of revisions for each non-public phase from `roots`,
1030 /// which are the last known roots for each non-public phase.
1026 /// which are the last known roots for each non-public phase.
1031 pub fn compute_phases_map_sets(
1027 pub fn compute_phases_map_sets(
1032 &self,
1028 &self,
1033 roots: HashMap<Phase, Vec<Revision>>,
1029 roots: HashMap<Phase, Vec<Revision>>,
1034 ) -> Result<(usize, RootsPerPhase), GraphError> {
1030 ) -> Result<(usize, RootsPerPhase), GraphError> {
1035 let mut phases = vec![Phase::Public; self.len()];
1031 let mut phases = vec![Phase::Public; self.len()];
1036 let mut min_phase_rev = NULL_REVISION;
1032 let mut min_phase_rev = NULL_REVISION;
1037
1033
1038 for phase in Phase::non_public_phases() {
1034 for phase in Phase::non_public_phases() {
1039 if let Some(phase_roots) = roots.get(phase) {
1035 if let Some(phase_roots) = roots.get(phase) {
1040 let min_rev =
1036 let min_rev =
1041 self.add_roots_get_min(phase_roots, &mut phases, *phase);
1037 self.add_roots_get_min(phase_roots, &mut phases, *phase);
1042 if min_rev != NULL_REVISION
1038 if min_rev != NULL_REVISION
1043 && (min_phase_rev == NULL_REVISION
1039 && (min_phase_rev == NULL_REVISION
1044 || min_rev < min_phase_rev)
1040 || min_rev < min_phase_rev)
1045 {
1041 {
1046 min_phase_rev = min_rev;
1042 min_phase_rev = min_rev;
1047 }
1043 }
1048 } else {
1044 } else {
1049 continue;
1045 continue;
1050 };
1046 };
1051 }
1047 }
1052 let mut phase_sets: RootsPerPhase = Default::default();
1048 let mut phase_sets: RootsPerPhase = Default::default();
1053
1049
1054 if min_phase_rev == NULL_REVISION {
1050 if min_phase_rev == NULL_REVISION {
1055 min_phase_rev = Revision(self.len() as BaseRevision);
1051 min_phase_rev = Revision(self.len() as BaseRevision);
1056 }
1052 }
1057
1053
1058 for rev in min_phase_rev.0..self.len() as BaseRevision {
1054 for rev in min_phase_rev.0..self.len() as BaseRevision {
1059 let rev = Revision(rev);
1055 let rev = Revision(rev);
1060 let [p1, p2] = self.parents(rev)?;
1056 let [p1, p2] = self.parents(rev)?;
1061
1057
1062 if p1.0 >= 0 && phases[p1.0 as usize] > phases[rev.0 as usize] {
1058 if p1.0 >= 0 && phases[p1.0 as usize] > phases[rev.0 as usize] {
1063 phases[rev.0 as usize] = phases[p1.0 as usize];
1059 phases[rev.0 as usize] = phases[p1.0 as usize];
1064 }
1060 }
1065 if p2.0 >= 0 && phases[p2.0 as usize] > phases[rev.0 as usize] {
1061 if p2.0 >= 0 && phases[p2.0 as usize] > phases[rev.0 as usize] {
1066 phases[rev.0 as usize] = phases[p2.0 as usize];
1062 phases[rev.0 as usize] = phases[p2.0 as usize];
1067 }
1063 }
1068 let set = match phases[rev.0 as usize] {
1064 let set = match phases[rev.0 as usize] {
1069 Phase::Public => continue,
1065 Phase::Public => continue,
1070 phase => &mut phase_sets[phase as usize - 1],
1066 phase => &mut phase_sets[phase as usize - 1],
1071 };
1067 };
1072 set.push(rev);
1068 set.push(rev);
1073 }
1069 }
1074
1070
1075 Ok((self.len(), phase_sets))
1071 Ok((self.len(), phase_sets))
1076 }
1072 }
1077
1073
1078 fn add_roots_get_min(
1074 fn add_roots_get_min(
1079 &self,
1075 &self,
1080 phase_roots: &[Revision],
1076 phase_roots: &[Revision],
1081 phases: &mut [Phase],
1077 phases: &mut [Phase],
1082 phase: Phase,
1078 phase: Phase,
1083 ) -> Revision {
1079 ) -> Revision {
1084 let mut min_rev = NULL_REVISION;
1080 let mut min_rev = NULL_REVISION;
1085
1081
1086 for root in phase_roots {
1082 for root in phase_roots {
1087 phases[root.0 as usize] = phase;
1083 phases[root.0 as usize] = phase;
1088 if min_rev == NULL_REVISION || min_rev > *root {
1084 if min_rev == NULL_REVISION || min_rev > *root {
1089 min_rev = *root;
1085 min_rev = *root;
1090 }
1086 }
1091 }
1087 }
1092 min_rev
1088 min_rev
1093 }
1089 }
1094
1090
1095 /// Return `(heads(::(<roots> and <roots>::<heads>)))`
1091 /// Return `(heads(::(<roots> and <roots>::<heads>)))`
1096 /// If `include_path` is `true`, return `(<roots>::<heads>)`."""
1092 /// If `include_path` is `true`, return `(<roots>::<heads>)`."""
1097 ///
1093 ///
1098 /// `min_root` and `roots` are unchecked since they are just used as
1094 /// `min_root` and `roots` are unchecked since they are just used as
1099 /// a bound or for comparison and don't need to represent a valid revision.
1095 /// a bound or for comparison and don't need to represent a valid revision.
1100 /// In practice, the only invalid revision passed is the working directory
1096 /// In practice, the only invalid revision passed is the working directory
1101 /// revision ([`i32::MAX`]).
1097 /// revision ([`i32::MAX`]).
1102 pub fn reachable_roots(
1098 pub fn reachable_roots(
1103 &self,
1099 &self,
1104 min_root: UncheckedRevision,
1100 min_root: UncheckedRevision,
1105 mut heads: Vec<Revision>,
1101 mut heads: Vec<Revision>,
1106 roots: HashSet<UncheckedRevision>,
1102 roots: HashSet<UncheckedRevision>,
1107 include_path: bool,
1103 include_path: bool,
1108 ) -> Result<HashSet<Revision>, GraphError> {
1104 ) -> Result<HashSet<Revision>, GraphError> {
1109 if roots.is_empty() {
1105 if roots.is_empty() {
1110 return Ok(HashSet::new());
1106 return Ok(HashSet::new());
1111 }
1107 }
1112 let mut reachable = HashSet::new();
1108 let mut reachable = HashSet::new();
1113 let mut seen = HashMap::new();
1109 let mut seen = HashMap::new();
1114
1110
1115 while let Some(rev) = heads.pop() {
1111 while let Some(rev) = heads.pop() {
1116 if roots.contains(&rev.into()) {
1112 if roots.contains(&rev.into()) {
1117 reachable.insert(rev);
1113 reachable.insert(rev);
1118 if !include_path {
1114 if !include_path {
1119 continue;
1115 continue;
1120 }
1116 }
1121 }
1117 }
1122 let parents = self.parents(rev)?;
1118 let parents = self.parents(rev)?;
1123 seen.insert(rev, parents);
1119 seen.insert(rev, parents);
1124 for parent in parents {
1120 for parent in parents {
1125 if parent.0 >= min_root.0 && !seen.contains_key(&parent) {
1121 if parent.0 >= min_root.0 && !seen.contains_key(&parent) {
1126 heads.push(parent);
1122 heads.push(parent);
1127 }
1123 }
1128 }
1124 }
1129 }
1125 }
1130 if !include_path {
1126 if !include_path {
1131 return Ok(reachable);
1127 return Ok(reachable);
1132 }
1128 }
1133 let mut revs: Vec<_> = seen.keys().collect();
1129 let mut revs: Vec<_> = seen.keys().collect();
1134 revs.sort_unstable();
1130 revs.sort_unstable();
1135 for rev in revs {
1131 for rev in revs {
1136 for parent in seen[rev] {
1132 for parent in seen[rev] {
1137 if reachable.contains(&parent) {
1133 if reachable.contains(&parent) {
1138 reachable.insert(*rev);
1134 reachable.insert(*rev);
1139 }
1135 }
1140 }
1136 }
1141 }
1137 }
1142 Ok(reachable)
1138 Ok(reachable)
1143 }
1139 }
1144
1140
1145 /// Given a (possibly overlapping) set of revs, return all the
1141 /// Given a (possibly overlapping) set of revs, return all the
1146 /// common ancestors heads: `heads(::args[0] and ::a[1] and ...)`
1142 /// common ancestors heads: `heads(::args[0] and ::a[1] and ...)`
1147 pub fn common_ancestor_heads(
1143 pub fn common_ancestor_heads(
1148 &self,
1144 &self,
1149 revisions: &[Revision],
1145 revisions: &[Revision],
1150 ) -> Result<Vec<Revision>, GraphError> {
1146 ) -> Result<Vec<Revision>, GraphError> {
1151 // given that revisions is expected to be small, we find this shortcut
1147 // given that revisions is expected to be small, we find this shortcut
1152 // potentially acceptable, especially given that `hg-cpython` could
1148 // potentially acceptable, especially given that `hg-cpython` could
1153 // very much bypass this, constructing a vector of unique values from
1149 // very much bypass this, constructing a vector of unique values from
1154 // the onset.
1150 // the onset.
1155 let as_set: HashSet<Revision> = revisions.iter().copied().collect();
1151 let as_set: HashSet<Revision> = revisions.iter().copied().collect();
1156 // Besides deduplicating, the C version also implements the shortcut
1152 // Besides deduplicating, the C version also implements the shortcut
1157 // for `NULL_REVISION`:
1153 // for `NULL_REVISION`:
1158 if as_set.contains(&NULL_REVISION) {
1154 if as_set.contains(&NULL_REVISION) {
1159 return Ok(vec![]);
1155 return Ok(vec![]);
1160 }
1156 }
1161
1157
1162 let revisions: Vec<Revision> = as_set.into_iter().collect();
1158 let revisions: Vec<Revision> = as_set.into_iter().collect();
1163
1159
1164 if revisions.len() < 8 {
1160 if revisions.len() < 8 {
1165 self.find_gca_candidates::<u8>(&revisions)
1161 self.find_gca_candidates::<u8>(&revisions)
1166 } else if revisions.len() < 64 {
1162 } else if revisions.len() < 64 {
1167 self.find_gca_candidates::<u64>(&revisions)
1163 self.find_gca_candidates::<u64>(&revisions)
1168 } else {
1164 } else {
1169 self.find_gca_candidates::<NonStaticPoisonableBitSet>(&revisions)
1165 self.find_gca_candidates::<NonStaticPoisonableBitSet>(&revisions)
1170 }
1166 }
1171 }
1167 }
1172
1168
1173 pub fn ancestors(
1169 pub fn ancestors(
1174 &self,
1170 &self,
1175 revisions: &[Revision],
1171 revisions: &[Revision],
1176 ) -> Result<Vec<Revision>, GraphError> {
1172 ) -> Result<Vec<Revision>, GraphError> {
1177 self.find_deepest_revs(&self.common_ancestor_heads(revisions)?)
1173 self.find_deepest_revs(&self.common_ancestor_heads(revisions)?)
1178 }
1174 }
1179
1175
1180 /// Given a disjoint set of revs, return all candidates for the
1176 /// Given a disjoint set of revs, return all candidates for the
1181 /// greatest common ancestor. In revset notation, this is the set
1177 /// greatest common ancestor. In revset notation, this is the set
1182 /// `heads(::a and ::b and ...)`
1178 /// `heads(::a and ::b and ...)`
1183 fn find_gca_candidates<BS: PoisonableBitSet + Clone>(
1179 fn find_gca_candidates<BS: PoisonableBitSet + Clone>(
1184 &self,
1180 &self,
1185 revs: &[Revision],
1181 revs: &[Revision],
1186 ) -> Result<Vec<Revision>, GraphError> {
1182 ) -> Result<Vec<Revision>, GraphError> {
1187 if revs.is_empty() {
1183 if revs.is_empty() {
1188 return Ok(vec![]);
1184 return Ok(vec![]);
1189 }
1185 }
1190 let revcount = revs.len();
1186 let revcount = revs.len();
1191 let mut candidates = vec![];
1187 let mut candidates = vec![];
1192 let max_rev = revs.iter().max().unwrap();
1188 let max_rev = revs.iter().max().unwrap();
1193
1189
1194 let mut seen = BS::vec_of_empty(revs.len(), (max_rev.0 + 1) as usize);
1190 let mut seen = BS::vec_of_empty(revs.len(), (max_rev.0 + 1) as usize);
1195
1191
1196 for (idx, rev) in revs.iter().enumerate() {
1192 for (idx, rev) in revs.iter().enumerate() {
1197 seen[rev.0 as usize].add(idx);
1193 seen[rev.0 as usize].add(idx);
1198 }
1194 }
1199 let mut current_rev = *max_rev;
1195 let mut current_rev = *max_rev;
1200 // Number of revisions whose inspection in the main loop
1196 // Number of revisions whose inspection in the main loop
1201 // will give a result or trigger inspection of other revisions
1197 // will give a result or trigger inspection of other revisions
1202 let mut interesting = revcount;
1198 let mut interesting = revcount;
1203
1199
1204 // The algorithm works on a vector of bit sets, indexed by revision
1200 // The algorithm works on a vector of bit sets, indexed by revision
1205 // numbers and iterated on reverse order.
1201 // numbers and iterated on reverse order.
1206 // An entry in this vector is poisoned if and only if the corresponding
1202 // An entry in this vector is poisoned if and only if the corresponding
1207 // revision is a common, yet not maximal ancestor.
1203 // revision is a common, yet not maximal ancestor.
1208
1204
1209 // The principle of the algorithm is as follows:
1205 // The principle of the algorithm is as follows:
1210 // For a revision `r`, when entering the loop, `seen[r]` is either
1206 // For a revision `r`, when entering the loop, `seen[r]` is either
1211 // poisoned or the sub set of `revs` of which `r` is an ancestor.
1207 // poisoned or the sub set of `revs` of which `r` is an ancestor.
1212 // In this sub set is full, then `r` is a solution and its parents
1208 // In this sub set is full, then `r` is a solution and its parents
1213 // have to be poisoned.
1209 // have to be poisoned.
1214 //
1210 //
1215 // At each iteration, the bit sets of the parents are updated by
1211 // At each iteration, the bit sets of the parents are updated by
1216 // union with `seen[r]`.
1212 // union with `seen[r]`.
1217 // As we walk the index from the end, we are sure we have encountered
1213 // As we walk the index from the end, we are sure we have encountered
1218 // all children of `r` before `r`, hence we know that `seen[r]` is
1214 // all children of `r` before `r`, hence we know that `seen[r]` is
1219 // fully computed.
1215 // fully computed.
1220 //
1216 //
1221 // On top of that there are several optimizations that make reading
1217 // On top of that there are several optimizations that make reading
1222 // less obvious than the comment above:
1218 // less obvious than the comment above:
1223 // - The `interesting` counter allows to break early
1219 // - The `interesting` counter allows to break early
1224 // - The loop starts from `max(revs)`
1220 // - The loop starts from `max(revs)`
1225 // - Early return in case it is detected that one of the incoming revs
1221 // - Early return in case it is detected that one of the incoming revs
1226 // is a common ancestor of all of them.
1222 // is a common ancestor of all of them.
1227 while current_rev.0 >= 0 && interesting > 0 {
1223 while current_rev.0 >= 0 && interesting > 0 {
1228 let current_seen = seen[current_rev.0 as usize].clone();
1224 let current_seen = seen[current_rev.0 as usize].clone();
1229
1225
1230 if current_seen.is_empty() {
1226 if current_seen.is_empty() {
1231 current_rev = Revision(current_rev.0 - 1);
1227 current_rev = Revision(current_rev.0 - 1);
1232 continue;
1228 continue;
1233 }
1229 }
1234 let mut poison = current_seen.is_poisoned();
1230 let mut poison = current_seen.is_poisoned();
1235 if !poison {
1231 if !poison {
1236 interesting -= 1;
1232 interesting -= 1;
1237 if current_seen.is_full_range(revcount) {
1233 if current_seen.is_full_range(revcount) {
1238 candidates.push(current_rev);
1234 candidates.push(current_rev);
1239 poison = true;
1235 poison = true;
1240
1236
1241 // Being a common ancestor, if `current_rev` is among
1237 // Being a common ancestor, if `current_rev` is among
1242 // the input revisions, it is *the* answer.
1238 // the input revisions, it is *the* answer.
1243 for rev in revs {
1239 for rev in revs {
1244 if *rev == current_rev {
1240 if *rev == current_rev {
1245 return Ok(candidates);
1241 return Ok(candidates);
1246 }
1242 }
1247 }
1243 }
1248 }
1244 }
1249 }
1245 }
1250 for parent in self.parents(current_rev)? {
1246 for parent in self.parents(current_rev)? {
1251 if parent == NULL_REVISION {
1247 if parent == NULL_REVISION {
1252 continue;
1248 continue;
1253 }
1249 }
1254 let parent_seen = &mut seen[parent.0 as usize];
1250 let parent_seen = &mut seen[parent.0 as usize];
1255 if poison {
1251 if poison {
1256 // this block is logically equivalent to poisoning parent
1252 // this block is logically equivalent to poisoning parent
1257 // and counting it as non interesting if it
1253 // and counting it as non interesting if it
1258 // has been seen before (hence counted then as interesting)
1254 // has been seen before (hence counted then as interesting)
1259 if !parent_seen.is_empty() && !parent_seen.is_poisoned() {
1255 if !parent_seen.is_empty() && !parent_seen.is_poisoned() {
1260 interesting -= 1;
1256 interesting -= 1;
1261 }
1257 }
1262 parent_seen.poison();
1258 parent_seen.poison();
1263 } else {
1259 } else {
1264 if parent_seen.is_empty() {
1260 if parent_seen.is_empty() {
1265 interesting += 1;
1261 interesting += 1;
1266 }
1262 }
1267 parent_seen.union(&current_seen);
1263 parent_seen.union(&current_seen);
1268 }
1264 }
1269 }
1265 }
1270
1266
1271 current_rev = Revision(current_rev.0 - 1);
1267 current_rev = Revision(current_rev.0 - 1);
1272 }
1268 }
1273
1269
1274 Ok(candidates)
1270 Ok(candidates)
1275 }
1271 }
1276
1272
1277 /// Given a disjoint set of revs, return the subset with the longest path
1273 /// Given a disjoint set of revs, return the subset with the longest path
1278 /// to the root.
1274 /// to the root.
1279 fn find_deepest_revs(
1275 fn find_deepest_revs(
1280 &self,
1276 &self,
1281 revs: &[Revision],
1277 revs: &[Revision],
1282 ) -> Result<Vec<Revision>, GraphError> {
1278 ) -> Result<Vec<Revision>, GraphError> {
1283 // TODO replace this all with just comparing rank?
1279 // TODO replace this all with just comparing rank?
1284 // Also, the original implementations in C/Python are cryptic, not
1280 // Also, the original implementations in C/Python are cryptic, not
1285 // even sure we actually need this?
1281 // even sure we actually need this?
1286 if revs.len() <= 1 {
1282 if revs.len() <= 1 {
1287 return Ok(revs.to_owned());
1283 return Ok(revs.to_owned());
1288 }
1284 }
1289 let max_rev = revs.iter().max().unwrap().0;
1285 let max_rev = revs.iter().max().unwrap().0;
1290 let mut interesting = HashMap::new();
1286 let mut interesting = HashMap::new();
1291 let mut seen = vec![0; max_rev as usize + 1];
1287 let mut seen = vec![0; max_rev as usize + 1];
1292 let mut depth = vec![0; max_rev as usize + 1];
1288 let mut depth = vec![0; max_rev as usize + 1];
1293 let mut mapping = vec![];
1289 let mut mapping = vec![];
1294 let mut revs = revs.to_owned();
1290 let mut revs = revs.to_owned();
1295 revs.sort_unstable();
1291 revs.sort_unstable();
1296
1292
1297 for (idx, rev) in revs.iter().enumerate() {
1293 for (idx, rev) in revs.iter().enumerate() {
1298 depth[rev.0 as usize] = 1;
1294 depth[rev.0 as usize] = 1;
1299 let shift = 1 << idx;
1295 let shift = 1 << idx;
1300 seen[rev.0 as usize] = shift;
1296 seen[rev.0 as usize] = shift;
1301 interesting.insert(shift, 1);
1297 interesting.insert(shift, 1);
1302 mapping.push((shift, *rev));
1298 mapping.push((shift, *rev));
1303 }
1299 }
1304
1300
1305 let mut current_rev = Revision(max_rev);
1301 let mut current_rev = Revision(max_rev);
1306 while current_rev.0 >= 0 && interesting.len() > 1 {
1302 while current_rev.0 >= 0 && interesting.len() > 1 {
1307 let current_depth = depth[current_rev.0 as usize];
1303 let current_depth = depth[current_rev.0 as usize];
1308 if current_depth == 0 {
1304 if current_depth == 0 {
1309 current_rev = Revision(current_rev.0 - 1);
1305 current_rev = Revision(current_rev.0 - 1);
1310 continue;
1306 continue;
1311 }
1307 }
1312
1308
1313 let current_seen = seen[current_rev.0 as usize];
1309 let current_seen = seen[current_rev.0 as usize];
1314 for parent in self.parents(current_rev)? {
1310 for parent in self.parents(current_rev)? {
1315 if parent == NULL_REVISION {
1311 if parent == NULL_REVISION {
1316 continue;
1312 continue;
1317 }
1313 }
1318 let parent_seen = seen[parent.0 as usize];
1314 let parent_seen = seen[parent.0 as usize];
1319 let parent_depth = depth[parent.0 as usize];
1315 let parent_depth = depth[parent.0 as usize];
1320 if parent_depth <= current_depth {
1316 if parent_depth <= current_depth {
1321 depth[parent.0 as usize] = current_depth + 1;
1317 depth[parent.0 as usize] = current_depth + 1;
1322 if parent_seen != current_seen {
1318 if parent_seen != current_seen {
1323 *interesting.get_mut(&current_seen).unwrap() += 1;
1319 *interesting.get_mut(&current_seen).unwrap() += 1;
1324 seen[parent.0 as usize] = current_seen;
1320 seen[parent.0 as usize] = current_seen;
1325 if parent_seen != 0 {
1321 if parent_seen != 0 {
1326 let parent_interesting =
1322 let parent_interesting =
1327 interesting.get_mut(&parent_seen).unwrap();
1323 interesting.get_mut(&parent_seen).unwrap();
1328 *parent_interesting -= 1;
1324 *parent_interesting -= 1;
1329 if *parent_interesting == 0 {
1325 if *parent_interesting == 0 {
1330 interesting.remove(&parent_seen);
1326 interesting.remove(&parent_seen);
1331 }
1327 }
1332 }
1328 }
1333 }
1329 }
1334 } else if current_depth == parent_depth - 1 {
1330 } else if current_depth == parent_depth - 1 {
1335 let either_seen = parent_seen | current_seen;
1331 let either_seen = parent_seen | current_seen;
1336 if either_seen == parent_seen {
1332 if either_seen == parent_seen {
1337 continue;
1333 continue;
1338 }
1334 }
1339 seen[parent.0 as usize] = either_seen;
1335 seen[parent.0 as usize] = either_seen;
1340 interesting
1336 interesting
1341 .entry(either_seen)
1337 .entry(either_seen)
1342 .and_modify(|v| *v += 1)
1338 .and_modify(|v| *v += 1)
1343 .or_insert(1);
1339 .or_insert(1);
1344 *interesting.get_mut(&parent_seen).unwrap() -= 1;
1340 *interesting.get_mut(&parent_seen).unwrap() -= 1;
1345 if interesting[&parent_seen] == 0 {
1341 if interesting[&parent_seen] == 0 {
1346 interesting.remove(&parent_seen);
1342 interesting.remove(&parent_seen);
1347 }
1343 }
1348 }
1344 }
1349 }
1345 }
1350 *interesting.get_mut(&current_seen).unwrap() -= 1;
1346 *interesting.get_mut(&current_seen).unwrap() -= 1;
1351 if interesting[&current_seen] == 0 {
1347 if interesting[&current_seen] == 0 {
1352 interesting.remove(&current_seen);
1348 interesting.remove(&current_seen);
1353 }
1349 }
1354
1350
1355 current_rev = Revision(current_rev.0 - 1);
1351 current_rev = Revision(current_rev.0 - 1);
1356 }
1352 }
1357
1353
1358 if interesting.len() != 1 {
1354 if interesting.len() != 1 {
1359 return Ok(vec![]);
1355 return Ok(vec![]);
1360 }
1356 }
1361 let mask = interesting.keys().next().unwrap();
1357 let mask = interesting.keys().next().unwrap();
1362
1358
1363 Ok(mapping
1359 Ok(mapping
1364 .into_iter()
1360 .into_iter()
1365 .filter_map(|(shift, rev)| {
1361 .filter_map(|(shift, rev)| {
1366 if (mask & shift) != 0 {
1362 if (mask & shift) != 0 {
1367 return Some(rev);
1363 return Some(rev);
1368 }
1364 }
1369 None
1365 None
1370 })
1366 })
1371 .collect())
1367 .collect())
1372 }
1368 }
1373 }
1369 }
1374
1370
1375 /// The kind of functionality needed by find_gca_candidates
1371 /// The kind of functionality needed by find_gca_candidates
1376 ///
1372 ///
1377 /// This is a bit mask which can be declared to be "poisoned", which callers
1373 /// This is a bit mask which can be declared to be "poisoned", which callers
1378 /// interpret to break out of some loops.
1374 /// interpret to break out of some loops.
1379 ///
1375 ///
1380 /// The maximum capacity of the bit mask is up to the actual implementation
1376 /// The maximum capacity of the bit mask is up to the actual implementation
1381 trait PoisonableBitSet: Sized + PartialEq {
1377 trait PoisonableBitSet: Sized + PartialEq {
1382 /// Return a vector of exactly n elements, initialized to be empty.
1378 /// Return a vector of exactly n elements, initialized to be empty.
1383 ///
1379 ///
1384 /// Optimization can vastly depend on implementation. Those being `Copy`
1380 /// Optimization can vastly depend on implementation. Those being `Copy`
1385 /// and having constant capacity typically can have a very simple
1381 /// and having constant capacity typically can have a very simple
1386 /// implementation.
1382 /// implementation.
1387 fn vec_of_empty(sets_size: usize, vec_len: usize) -> Vec<Self>;
1383 fn vec_of_empty(sets_size: usize, vec_len: usize) -> Vec<Self>;
1388
1384
1389 /// The size of the bit mask in memory
1385 /// The size of the bit mask in memory
1390 #[allow(unused)]
1386 #[allow(unused)]
1391 fn size(&self) -> usize;
1387 fn size(&self) -> usize;
1392
1388
1393 /// The number of elements that can be represented in the set.
1389 /// The number of elements that can be represented in the set.
1394 ///
1390 ///
1395 /// Another way to put it is that it is the highest integer `C` such that
1391 /// Another way to put it is that it is the highest integer `C` such that
1396 /// the set is guaranteed to always be a subset of the integer range
1392 /// the set is guaranteed to always be a subset of the integer range
1397 /// `[0, C)`
1393 /// `[0, C)`
1398 #[allow(unused)]
1394 #[allow(unused)]
1399 fn capacity(&self) -> usize;
1395 fn capacity(&self) -> usize;
1400
1396
1401 /// Declare `n` to belong to the set
1397 /// Declare `n` to belong to the set
1402 fn add(&mut self, n: usize);
1398 fn add(&mut self, n: usize);
1403
1399
1404 /// Declare `n` not to belong to the set
1400 /// Declare `n` not to belong to the set
1405 #[allow(unused)]
1401 #[allow(unused)]
1406 fn discard(&mut self, n: usize);
1402 fn discard(&mut self, n: usize);
1407
1403
1408 /// Replace this bit set by its union with other
1404 /// Replace this bit set by its union with other
1409 fn union(&mut self, other: &Self);
1405 fn union(&mut self, other: &Self);
1410
1406
1411 /// Poison the bit set
1407 /// Poison the bit set
1412 ///
1408 ///
1413 /// Interpretation up to the caller
1409 /// Interpretation up to the caller
1414 fn poison(&mut self);
1410 fn poison(&mut self);
1415
1411
1416 /// Is the bit set poisoned?
1412 /// Is the bit set poisoned?
1417 ///
1413 ///
1418 /// Interpretation is up to the caller
1414 /// Interpretation is up to the caller
1419 fn is_poisoned(&self) -> bool;
1415 fn is_poisoned(&self) -> bool;
1420
1416
1421 /// Is the bit set empty?
1417 /// Is the bit set empty?
1422 fn is_empty(&self) -> bool;
1418 fn is_empty(&self) -> bool;
1423
1419
1424 /// return `true` if and only if the bit is the full range `[0, n)`
1420 /// return `true` if and only if the bit is the full range `[0, n)`
1425 /// of integers
1421 /// of integers
1426 fn is_full_range(&self, n: usize) -> bool;
1422 fn is_full_range(&self, n: usize) -> bool;
1427 }
1423 }
1428
1424
1429 const U64_POISON: u64 = 1 << 63;
1425 const U64_POISON: u64 = 1 << 63;
1430 const U8_POISON: u8 = 1 << 7;
1426 const U8_POISON: u8 = 1 << 7;
1431
1427
1432 impl PoisonableBitSet for u64 {
1428 impl PoisonableBitSet for u64 {
1433 fn vec_of_empty(_sets_size: usize, vec_len: usize) -> Vec<Self> {
1429 fn vec_of_empty(_sets_size: usize, vec_len: usize) -> Vec<Self> {
1434 vec![0u64; vec_len]
1430 vec![0u64; vec_len]
1435 }
1431 }
1436
1432
1437 fn size(&self) -> usize {
1433 fn size(&self) -> usize {
1438 8
1434 8
1439 }
1435 }
1440
1436
1441 fn capacity(&self) -> usize {
1437 fn capacity(&self) -> usize {
1442 63
1438 63
1443 }
1439 }
1444
1440
1445 fn add(&mut self, n: usize) {
1441 fn add(&mut self, n: usize) {
1446 (*self) |= 1u64 << n;
1442 (*self) |= 1u64 << n;
1447 }
1443 }
1448
1444
1449 fn discard(&mut self, n: usize) {
1445 fn discard(&mut self, n: usize) {
1450 (*self) &= u64::MAX - (1u64 << n);
1446 (*self) &= u64::MAX - (1u64 << n);
1451 }
1447 }
1452
1448
1453 fn union(&mut self, other: &Self) {
1449 fn union(&mut self, other: &Self) {
1454 if *self != *other {
1450 if *self != *other {
1455 (*self) |= *other;
1451 (*self) |= *other;
1456 }
1452 }
1457 }
1453 }
1458
1454
1459 fn is_full_range(&self, n: usize) -> bool {
1455 fn is_full_range(&self, n: usize) -> bool {
1460 *self + 1 == (1u64 << n)
1456 *self + 1 == (1u64 << n)
1461 }
1457 }
1462
1458
1463 fn is_empty(&self) -> bool {
1459 fn is_empty(&self) -> bool {
1464 *self == 0
1460 *self == 0
1465 }
1461 }
1466
1462
1467 fn poison(&mut self) {
1463 fn poison(&mut self) {
1468 *self = U64_POISON;
1464 *self = U64_POISON;
1469 }
1465 }
1470
1466
1471 fn is_poisoned(&self) -> bool {
1467 fn is_poisoned(&self) -> bool {
1472 // equality comparison would be tempting but would not resist
1468 // equality comparison would be tempting but would not resist
1473 // operations after poisoning (even if these should be bogus).
1469 // operations after poisoning (even if these should be bogus).
1474 *self >= U64_POISON
1470 *self >= U64_POISON
1475 }
1471 }
1476 }
1472 }
1477
1473
1478 impl PoisonableBitSet for u8 {
1474 impl PoisonableBitSet for u8 {
1479 fn vec_of_empty(_sets_size: usize, vec_len: usize) -> Vec<Self> {
1475 fn vec_of_empty(_sets_size: usize, vec_len: usize) -> Vec<Self> {
1480 vec![0; vec_len]
1476 vec![0; vec_len]
1481 }
1477 }
1482
1478
1483 fn size(&self) -> usize {
1479 fn size(&self) -> usize {
1484 1
1480 1
1485 }
1481 }
1486
1482
1487 fn capacity(&self) -> usize {
1483 fn capacity(&self) -> usize {
1488 7
1484 7
1489 }
1485 }
1490
1486
1491 fn add(&mut self, n: usize) {
1487 fn add(&mut self, n: usize) {
1492 (*self) |= 1 << n;
1488 (*self) |= 1 << n;
1493 }
1489 }
1494
1490
1495 fn discard(&mut self, n: usize) {
1491 fn discard(&mut self, n: usize) {
1496 (*self) &= u8::MAX - (1 << n);
1492 (*self) &= u8::MAX - (1 << n);
1497 }
1493 }
1498
1494
1499 fn union(&mut self, other: &Self) {
1495 fn union(&mut self, other: &Self) {
1500 if *self != *other {
1496 if *self != *other {
1501 (*self) |= *other;
1497 (*self) |= *other;
1502 }
1498 }
1503 }
1499 }
1504
1500
1505 fn is_full_range(&self, n: usize) -> bool {
1501 fn is_full_range(&self, n: usize) -> bool {
1506 *self + 1 == (1 << n)
1502 *self + 1 == (1 << n)
1507 }
1503 }
1508
1504
1509 fn is_empty(&self) -> bool {
1505 fn is_empty(&self) -> bool {
1510 *self == 0
1506 *self == 0
1511 }
1507 }
1512
1508
1513 fn poison(&mut self) {
1509 fn poison(&mut self) {
1514 *self = U8_POISON;
1510 *self = U8_POISON;
1515 }
1511 }
1516
1512
1517 fn is_poisoned(&self) -> bool {
1513 fn is_poisoned(&self) -> bool {
1518 // equality comparison would be tempting but would not resist
1514 // equality comparison would be tempting but would not resist
1519 // operations after poisoning (even if these should be bogus).
1515 // operations after poisoning (even if these should be bogus).
1520 *self >= U8_POISON
1516 *self >= U8_POISON
1521 }
1517 }
1522 }
1518 }
1523
1519
1524 /// A poisonable bit set whose capacity is not known at compile time but
1520 /// A poisonable bit set whose capacity is not known at compile time but
1525 /// is constant after initial construction
1521 /// is constant after initial construction
1526 ///
1522 ///
1527 /// This can be way further optimized if performance assessments (speed
1523 /// This can be way further optimized if performance assessments (speed
1528 /// and/or RAM) require it.
1524 /// and/or RAM) require it.
1529 /// As far as RAM is concerned, for large vectors of these, the main problem
1525 /// As far as RAM is concerned, for large vectors of these, the main problem
1530 /// would be the repetition of set_size in each item. We would need a trait
1526 /// would be the repetition of set_size in each item. We would need a trait
1531 /// to abstract over the idea of a vector of such bit sets to do better.
1527 /// to abstract over the idea of a vector of such bit sets to do better.
1532 #[derive(Clone, PartialEq)]
1528 #[derive(Clone, PartialEq)]
1533 struct NonStaticPoisonableBitSet {
1529 struct NonStaticPoisonableBitSet {
1534 set_size: usize,
1530 set_size: usize,
1535 bit_set: Vec<u64>,
1531 bit_set: Vec<u64>,
1536 }
1532 }
1537
1533
1538 /// Number of `u64` needed for a [`NonStaticPoisonableBitSet`] of given size
1534 /// Number of `u64` needed for a [`NonStaticPoisonableBitSet`] of given size
1539 fn non_static_poisonable_inner_len(set_size: usize) -> usize {
1535 fn non_static_poisonable_inner_len(set_size: usize) -> usize {
1540 1 + (set_size + 1) / 64
1536 1 + (set_size + 1) / 64
1541 }
1537 }
1542
1538
1543 impl NonStaticPoisonableBitSet {
1539 impl NonStaticPoisonableBitSet {
1544 /// The index of the sub-bit set for the given n, and the index inside
1540 /// The index of the sub-bit set for the given n, and the index inside
1545 /// the latter
1541 /// the latter
1546 fn index(&self, n: usize) -> (usize, usize) {
1542 fn index(&self, n: usize) -> (usize, usize) {
1547 (n / 64, n % 64)
1543 (n / 64, n % 64)
1548 }
1544 }
1549 }
1545 }
1550
1546
1551 /// Mock implementation to ensure that the trait makes sense
1547 /// Mock implementation to ensure that the trait makes sense
1552 impl PoisonableBitSet for NonStaticPoisonableBitSet {
1548 impl PoisonableBitSet for NonStaticPoisonableBitSet {
1553 fn vec_of_empty(set_size: usize, vec_len: usize) -> Vec<Self> {
1549 fn vec_of_empty(set_size: usize, vec_len: usize) -> Vec<Self> {
1554 let tmpl = Self {
1550 let tmpl = Self {
1555 set_size,
1551 set_size,
1556 bit_set: vec![0u64; non_static_poisonable_inner_len(set_size)],
1552 bit_set: vec![0u64; non_static_poisonable_inner_len(set_size)],
1557 };
1553 };
1558 vec![tmpl; vec_len]
1554 vec![tmpl; vec_len]
1559 }
1555 }
1560
1556
1561 fn size(&self) -> usize {
1557 fn size(&self) -> usize {
1562 8 + self.bit_set.len() * 8
1558 8 + self.bit_set.len() * 8
1563 }
1559 }
1564
1560
1565 fn capacity(&self) -> usize {
1561 fn capacity(&self) -> usize {
1566 self.set_size
1562 self.set_size
1567 }
1563 }
1568
1564
1569 fn add(&mut self, n: usize) {
1565 fn add(&mut self, n: usize) {
1570 let (sub_bs, bit_pos) = self.index(n);
1566 let (sub_bs, bit_pos) = self.index(n);
1571 self.bit_set[sub_bs] |= 1 << bit_pos
1567 self.bit_set[sub_bs] |= 1 << bit_pos
1572 }
1568 }
1573
1569
1574 fn discard(&mut self, n: usize) {
1570 fn discard(&mut self, n: usize) {
1575 let (sub_bs, bit_pos) = self.index(n);
1571 let (sub_bs, bit_pos) = self.index(n);
1576 self.bit_set[sub_bs] |= u64::MAX - (1 << bit_pos)
1572 self.bit_set[sub_bs] |= u64::MAX - (1 << bit_pos)
1577 }
1573 }
1578
1574
1579 fn union(&mut self, other: &Self) {
1575 fn union(&mut self, other: &Self) {
1580 assert!(
1576 assert!(
1581 self.set_size == other.set_size,
1577 self.set_size == other.set_size,
1582 "Binary operations on bit sets can only be done on same size"
1578 "Binary operations on bit sets can only be done on same size"
1583 );
1579 );
1584 for i in 0..self.bit_set.len() - 1 {
1580 for i in 0..self.bit_set.len() - 1 {
1585 self.bit_set[i] |= other.bit_set[i]
1581 self.bit_set[i] |= other.bit_set[i]
1586 }
1582 }
1587 }
1583 }
1588
1584
1589 fn is_full_range(&self, n: usize) -> bool {
1585 fn is_full_range(&self, n: usize) -> bool {
1590 let (sub_bs, bit_pos) = self.index(n);
1586 let (sub_bs, bit_pos) = self.index(n);
1591 self.bit_set[..sub_bs].iter().all(|bs| *bs == u64::MAX)
1587 self.bit_set[..sub_bs].iter().all(|bs| *bs == u64::MAX)
1592 && self.bit_set[sub_bs] == (1 << (bit_pos + 1)) - 1
1588 && self.bit_set[sub_bs] == (1 << (bit_pos + 1)) - 1
1593 }
1589 }
1594
1590
1595 fn is_empty(&self) -> bool {
1591 fn is_empty(&self) -> bool {
1596 self.bit_set.iter().all(|bs| *bs == 0u64)
1592 self.bit_set.iter().all(|bs| *bs == 0u64)
1597 }
1593 }
1598
1594
1599 fn poison(&mut self) {
1595 fn poison(&mut self) {
1600 let (sub_bs, bit_pos) = self.index(self.set_size);
1596 let (sub_bs, bit_pos) = self.index(self.set_size);
1601 self.bit_set[sub_bs] = 1 << bit_pos;
1597 self.bit_set[sub_bs] = 1 << bit_pos;
1602 }
1598 }
1603
1599
1604 fn is_poisoned(&self) -> bool {
1600 fn is_poisoned(&self) -> bool {
1605 let (sub_bs, bit_pos) = self.index(self.set_size);
1601 let (sub_bs, bit_pos) = self.index(self.set_size);
1606 self.bit_set[sub_bs] >= 1 << bit_pos
1602 self.bit_set[sub_bs] >= 1 << bit_pos
1607 }
1603 }
1608 }
1604 }
1609
1605
1610 /// Set of roots of all non-public phases
1606 /// Set of roots of all non-public phases
1611 pub type RootsPerPhase = [Vec<Revision>; Phase::non_public_phases().len()];
1607 pub type RootsPerPhase = [Vec<Revision>; Phase::non_public_phases().len()];
1612
1608
1613 #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1609 #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1614 pub enum Phase {
1610 pub enum Phase {
1615 Public = 0,
1611 Public = 0,
1616 Draft = 1,
1612 Draft = 1,
1617 Secret = 2,
1613 Secret = 2,
1618 Archived = 3,
1614 Archived = 3,
1619 Internal = 4,
1615 Internal = 4,
1620 }
1616 }
1621
1617
1622 impl TryFrom<usize> for Phase {
1618 impl TryFrom<usize> for Phase {
1623 type Error = RevlogError;
1619 type Error = RevlogError;
1624
1620
1625 fn try_from(value: usize) -> Result<Self, Self::Error> {
1621 fn try_from(value: usize) -> Result<Self, Self::Error> {
1626 Ok(match value {
1622 Ok(match value {
1627 0 => Self::Public,
1623 0 => Self::Public,
1628 1 => Self::Draft,
1624 1 => Self::Draft,
1629 2 => Self::Secret,
1625 2 => Self::Secret,
1630 32 => Self::Archived,
1626 32 => Self::Archived,
1631 96 => Self::Internal,
1627 96 => Self::Internal,
1632 v => {
1628 v => {
1633 return Err(RevlogError::corrupted(format!(
1629 return Err(RevlogError::corrupted(format!(
1634 "invalid phase value {}",
1630 "invalid phase value {}",
1635 v
1631 v
1636 )))
1632 )))
1637 }
1633 }
1638 })
1634 })
1639 }
1635 }
1640 }
1636 }
1641
1637
1642 impl Phase {
1638 impl Phase {
1643 pub const fn all_phases() -> &'static [Self] {
1639 pub const fn all_phases() -> &'static [Self] {
1644 &[
1640 &[
1645 Self::Public,
1641 Self::Public,
1646 Self::Draft,
1642 Self::Draft,
1647 Self::Secret,
1643 Self::Secret,
1648 Self::Archived,
1644 Self::Archived,
1649 Self::Internal,
1645 Self::Internal,
1650 ]
1646 ]
1651 }
1647 }
1652 pub const fn non_public_phases() -> &'static [Self] {
1648 pub const fn non_public_phases() -> &'static [Self] {
1653 &[Self::Draft, Self::Secret, Self::Archived, Self::Internal]
1649 &[Self::Draft, Self::Secret, Self::Archived, Self::Internal]
1654 }
1650 }
1655 }
1651 }
1656
1652
1657 fn inline_scan(bytes: &[u8]) -> (usize, Vec<usize>) {
1653 fn inline_scan(bytes: &[u8]) -> (usize, Vec<usize>) {
1658 let mut offset: usize = 0;
1654 let mut offset: usize = 0;
1659 let mut offsets = Vec::new();
1655 let mut offsets = Vec::new();
1660
1656
1661 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
1657 while offset + INDEX_ENTRY_SIZE <= bytes.len() {
1662 offsets.push(offset);
1658 offsets.push(offset);
1663 let end = offset + INDEX_ENTRY_SIZE;
1659 let end = offset + INDEX_ENTRY_SIZE;
1664 let entry = IndexEntry {
1660 let entry = IndexEntry {
1665 bytes: &bytes[offset..end],
1661 bytes: &bytes[offset..end],
1666 };
1662 };
1667
1663
1668 offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
1664 offset += INDEX_ENTRY_SIZE + entry.compressed_len() as usize;
1669 }
1665 }
1670 (offset, offsets)
1666 (offset, offsets)
1671 }
1667 }
1672
1668
1673 impl super::RevlogIndex for Index {
1669 impl super::RevlogIndex for Index {
1674 fn len(&self) -> usize {
1670 fn len(&self) -> usize {
1675 self.len()
1671 self.len()
1676 }
1672 }
1677
1673
1678 fn node(&self, rev: Revision) -> Option<&Node> {
1674 fn node(&self, rev: Revision) -> Option<&Node> {
1679 if rev == NULL_REVISION {
1675 if rev == NULL_REVISION {
1680 return Some(&NULL_NODE);
1676 return Some(&NULL_NODE);
1681 }
1677 }
1682 self.get_entry(rev).map(|entry| entry.hash())
1678 self.get_entry(rev).map(|entry| entry.hash())
1683 }
1679 }
1684 }
1680 }
1685
1681
1686 #[derive(Debug)]
1682 #[derive(Debug)]
1687 pub struct IndexEntry<'a> {
1683 pub struct IndexEntry<'a> {
1688 bytes: &'a [u8],
1684 bytes: &'a [u8],
1689 }
1685 }
1690
1686
1691 impl<'a> IndexEntry<'a> {
1687 impl<'a> IndexEntry<'a> {
1692 /// Return the offset of the data.
1688 /// Return the offset of the data.
1693 pub fn offset(&self) -> usize {
1689 pub fn offset(&self) -> usize {
1694 let mut bytes = [0; 8];
1690 let mut bytes = [0; 8];
1695 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
1691 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
1696 BigEndian::read_u64(&bytes[..]) as usize
1692 BigEndian::read_u64(&bytes[..]) as usize
1697 }
1693 }
1698 pub fn raw_offset(&self) -> u64 {
1694 pub fn raw_offset(&self) -> u64 {
1699 BigEndian::read_u64(&self.bytes[0..8])
1695 BigEndian::read_u64(&self.bytes[0..8])
1700 }
1696 }
1701
1697
1702 /// Same result (except potentially for rev 0) as C `index_get_start()`
1698 /// Same result (except potentially for rev 0) as C `index_get_start()`
1703 fn c_start(&self) -> u64 {
1699 fn c_start(&self) -> u64 {
1704 self.raw_offset() >> 16
1700 self.raw_offset() >> 16
1705 }
1701 }
1706
1702
1707 pub fn flags(&self) -> u16 {
1703 pub fn flags(&self) -> u16 {
1708 BigEndian::read_u16(&self.bytes[6..=7])
1704 BigEndian::read_u16(&self.bytes[6..=7])
1709 }
1705 }
1710
1706
1711 /// Return the compressed length of the data.
1707 /// Return the compressed length of the data.
1712 pub fn compressed_len(&self) -> u32 {
1708 pub fn compressed_len(&self) -> u32 {
1713 BigEndian::read_u32(&self.bytes[8..=11])
1709 BigEndian::read_u32(&self.bytes[8..=11])
1714 }
1710 }
1715
1711
1716 /// Return the uncompressed length of the data.
1712 /// Return the uncompressed length of the data.
1717 pub fn uncompressed_len(&self) -> i32 {
1713 pub fn uncompressed_len(&self) -> i32 {
1718 BigEndian::read_i32(&self.bytes[12..=15])
1714 BigEndian::read_i32(&self.bytes[12..=15])
1719 }
1715 }
1720
1716
1721 /// Return the revision upon which the data has been derived.
1717 /// Return the revision upon which the data has been derived.
1722 pub fn base_revision_or_base_of_delta_chain(&self) -> UncheckedRevision {
1718 pub fn base_revision_or_base_of_delta_chain(&self) -> UncheckedRevision {
1723 // TODO Maybe return an Option when base_revision == rev?
1719 // TODO Maybe return an Option when base_revision == rev?
1724 // Requires to add rev to IndexEntry
1720 // Requires to add rev to IndexEntry
1725
1721
1726 BigEndian::read_i32(&self.bytes[16..]).into()
1722 BigEndian::read_i32(&self.bytes[16..]).into()
1727 }
1723 }
1728
1724
1729 pub fn link_revision(&self) -> UncheckedRevision {
1725 pub fn link_revision(&self) -> UncheckedRevision {
1730 BigEndian::read_i32(&self.bytes[20..]).into()
1726 BigEndian::read_i32(&self.bytes[20..]).into()
1731 }
1727 }
1732
1728
1733 pub fn p1(&self) -> UncheckedRevision {
1729 pub fn p1(&self) -> UncheckedRevision {
1734 BigEndian::read_i32(&self.bytes[24..]).into()
1730 BigEndian::read_i32(&self.bytes[24..]).into()
1735 }
1731 }
1736
1732
1737 pub fn p2(&self) -> UncheckedRevision {
1733 pub fn p2(&self) -> UncheckedRevision {
1738 BigEndian::read_i32(&self.bytes[28..]).into()
1734 BigEndian::read_i32(&self.bytes[28..]).into()
1739 }
1735 }
1740
1736
1741 /// Return the hash of revision's full text.
1737 /// Return the hash of revision's full text.
1742 ///
1738 ///
1743 /// Currently, SHA-1 is used and only the first 20 bytes of this field
1739 /// Currently, SHA-1 is used and only the first 20 bytes of this field
1744 /// are used.
1740 /// are used.
1745 pub fn hash(&self) -> &'a Node {
1741 pub fn hash(&self) -> &'a Node {
1746 (&self.bytes[32..52]).try_into().unwrap()
1742 (&self.bytes[32..52]).try_into().unwrap()
1747 }
1743 }
1748
1744
1749 pub fn as_bytes(&self) -> &'a [u8] {
1745 pub fn as_bytes(&self) -> &'a [u8] {
1750 self.bytes
1746 self.bytes
1751 }
1747 }
1752 }
1748 }
1753
1749
1754 #[cfg(test)]
1750 #[cfg(test)]
1755 pub use tests::IndexEntryBuilder;
1751 pub use tests::IndexEntryBuilder;
1756
1752
1757 #[cfg(test)]
1753 #[cfg(test)]
1758 mod tests {
1754 mod tests {
1759 use super::*;
1755 use super::*;
1760 use crate::node::NULL_NODE;
1756 use crate::node::NULL_NODE;
1761
1757
1762 #[cfg(test)]
1758 #[cfg(test)]
1763 #[derive(Debug, Copy, Clone)]
1759 #[derive(Debug, Copy, Clone)]
1764 pub struct IndexEntryBuilder {
1760 pub struct IndexEntryBuilder {
1765 is_first: bool,
1761 is_first: bool,
1766 is_inline: bool,
1762 is_inline: bool,
1767 is_general_delta: bool,
1763 is_general_delta: bool,
1768 version: u16,
1764 version: u16,
1769 offset: usize,
1765 offset: usize,
1770 compressed_len: usize,
1766 compressed_len: usize,
1771 uncompressed_len: usize,
1767 uncompressed_len: usize,
1772 base_revision_or_base_of_delta_chain: Revision,
1768 base_revision_or_base_of_delta_chain: Revision,
1773 link_revision: Revision,
1769 link_revision: Revision,
1774 p1: Revision,
1770 p1: Revision,
1775 p2: Revision,
1771 p2: Revision,
1776 node: Node,
1772 node: Node,
1777 }
1773 }
1778
1774
1779 #[cfg(test)]
1775 #[cfg(test)]
1780 impl IndexEntryBuilder {
1776 impl IndexEntryBuilder {
1781 #[allow(clippy::new_without_default)]
1777 #[allow(clippy::new_without_default)]
1782 pub fn new() -> Self {
1778 pub fn new() -> Self {
1783 Self {
1779 Self {
1784 is_first: false,
1780 is_first: false,
1785 is_inline: false,
1781 is_inline: false,
1786 is_general_delta: true,
1782 is_general_delta: true,
1787 version: 1,
1783 version: 1,
1788 offset: 0,
1784 offset: 0,
1789 compressed_len: 0,
1785 compressed_len: 0,
1790 uncompressed_len: 0,
1786 uncompressed_len: 0,
1791 base_revision_or_base_of_delta_chain: Revision(0),
1787 base_revision_or_base_of_delta_chain: Revision(0),
1792 link_revision: Revision(0),
1788 link_revision: Revision(0),
1793 p1: NULL_REVISION,
1789 p1: NULL_REVISION,
1794 p2: NULL_REVISION,
1790 p2: NULL_REVISION,
1795 node: NULL_NODE,
1791 node: NULL_NODE,
1796 }
1792 }
1797 }
1793 }
1798
1794
1799 pub fn is_first(&mut self, value: bool) -> &mut Self {
1795 pub fn is_first(&mut self, value: bool) -> &mut Self {
1800 self.is_first = value;
1796 self.is_first = value;
1801 self
1797 self
1802 }
1798 }
1803
1799
1804 pub fn with_inline(&mut self, value: bool) -> &mut Self {
1800 pub fn with_inline(&mut self, value: bool) -> &mut Self {
1805 self.is_inline = value;
1801 self.is_inline = value;
1806 self
1802 self
1807 }
1803 }
1808
1804
1809 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
1805 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
1810 self.is_general_delta = value;
1806 self.is_general_delta = value;
1811 self
1807 self
1812 }
1808 }
1813
1809
1814 pub fn with_version(&mut self, value: u16) -> &mut Self {
1810 pub fn with_version(&mut self, value: u16) -> &mut Self {
1815 self.version = value;
1811 self.version = value;
1816 self
1812 self
1817 }
1813 }
1818
1814
1819 pub fn with_offset(&mut self, value: usize) -> &mut Self {
1815 pub fn with_offset(&mut self, value: usize) -> &mut Self {
1820 self.offset = value;
1816 self.offset = value;
1821 self
1817 self
1822 }
1818 }
1823
1819
1824 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
1820 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
1825 self.compressed_len = value;
1821 self.compressed_len = value;
1826 self
1822 self
1827 }
1823 }
1828
1824
1829 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
1825 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
1830 self.uncompressed_len = value;
1826 self.uncompressed_len = value;
1831 self
1827 self
1832 }
1828 }
1833
1829
1834 pub fn with_base_revision_or_base_of_delta_chain(
1830 pub fn with_base_revision_or_base_of_delta_chain(
1835 &mut self,
1831 &mut self,
1836 value: Revision,
1832 value: Revision,
1837 ) -> &mut Self {
1833 ) -> &mut Self {
1838 self.base_revision_or_base_of_delta_chain = value;
1834 self.base_revision_or_base_of_delta_chain = value;
1839 self
1835 self
1840 }
1836 }
1841
1837
1842 pub fn with_link_revision(&mut self, value: Revision) -> &mut Self {
1838 pub fn with_link_revision(&mut self, value: Revision) -> &mut Self {
1843 self.link_revision = value;
1839 self.link_revision = value;
1844 self
1840 self
1845 }
1841 }
1846
1842
1847 pub fn with_p1(&mut self, value: Revision) -> &mut Self {
1843 pub fn with_p1(&mut self, value: Revision) -> &mut Self {
1848 self.p1 = value;
1844 self.p1 = value;
1849 self
1845 self
1850 }
1846 }
1851
1847
1852 pub fn with_p2(&mut self, value: Revision) -> &mut Self {
1848 pub fn with_p2(&mut self, value: Revision) -> &mut Self {
1853 self.p2 = value;
1849 self.p2 = value;
1854 self
1850 self
1855 }
1851 }
1856
1852
1857 pub fn with_node(&mut self, value: Node) -> &mut Self {
1853 pub fn with_node(&mut self, value: Node) -> &mut Self {
1858 self.node = value;
1854 self.node = value;
1859 self
1855 self
1860 }
1856 }
1861
1857
1862 pub fn build(&self) -> Vec<u8> {
1858 pub fn build(&self) -> Vec<u8> {
1863 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
1859 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
1864 if self.is_first {
1860 if self.is_first {
1865 bytes.extend(match (self.is_general_delta, self.is_inline) {
1861 bytes.extend(match (self.is_general_delta, self.is_inline) {
1866 (false, false) => [0u8, 0],
1862 (false, false) => [0u8, 0],
1867 (false, true) => [0u8, 1],
1863 (false, true) => [0u8, 1],
1868 (true, false) => [0u8, 2],
1864 (true, false) => [0u8, 2],
1869 (true, true) => [0u8, 3],
1865 (true, true) => [0u8, 3],
1870 });
1866 });
1871 bytes.extend(self.version.to_be_bytes());
1867 bytes.extend(self.version.to_be_bytes());
1872 // Remaining offset bytes.
1868 // Remaining offset bytes.
1873 bytes.extend([0u8; 2]);
1869 bytes.extend([0u8; 2]);
1874 } else {
1870 } else {
1875 // Offset stored on 48 bits (6 bytes)
1871 // Offset stored on 48 bits (6 bytes)
1876 bytes.extend(&(self.offset as u64).to_be_bytes()[2..]);
1872 bytes.extend(&(self.offset as u64).to_be_bytes()[2..]);
1877 }
1873 }
1878 bytes.extend([0u8; 2]); // Revision flags.
1874 bytes.extend([0u8; 2]); // Revision flags.
1879 bytes.extend((self.compressed_len as u32).to_be_bytes());
1875 bytes.extend((self.compressed_len as u32).to_be_bytes());
1880 bytes.extend((self.uncompressed_len as u32).to_be_bytes());
1876 bytes.extend((self.uncompressed_len as u32).to_be_bytes());
1881 bytes.extend(
1877 bytes.extend(
1882 self.base_revision_or_base_of_delta_chain.0.to_be_bytes(),
1878 self.base_revision_or_base_of_delta_chain.0.to_be_bytes(),
1883 );
1879 );
1884 bytes.extend(self.link_revision.0.to_be_bytes());
1880 bytes.extend(self.link_revision.0.to_be_bytes());
1885 bytes.extend(self.p1.0.to_be_bytes());
1881 bytes.extend(self.p1.0.to_be_bytes());
1886 bytes.extend(self.p2.0.to_be_bytes());
1882 bytes.extend(self.p2.0.to_be_bytes());
1887 bytes.extend(self.node.as_bytes());
1883 bytes.extend(self.node.as_bytes());
1888 bytes.extend(vec![0u8; 12]);
1884 bytes.extend(vec![0u8; 12]);
1889 bytes
1885 bytes
1890 }
1886 }
1891 }
1887 }
1892
1888
1893 pub fn is_inline(index_bytes: &[u8]) -> bool {
1889 pub fn is_inline(index_bytes: &[u8]) -> bool {
1894 IndexHeader::parse(index_bytes)
1890 IndexHeader::parse(index_bytes)
1895 .expect("too short")
1891 .expect("too short")
1896 .unwrap()
1892 .unwrap()
1897 .format_flags()
1893 .format_flags()
1898 .is_inline()
1894 .is_inline()
1899 }
1895 }
1900
1896
1901 pub fn uses_generaldelta(index_bytes: &[u8]) -> bool {
1897 pub fn uses_generaldelta(index_bytes: &[u8]) -> bool {
1902 IndexHeader::parse(index_bytes)
1898 IndexHeader::parse(index_bytes)
1903 .expect("too short")
1899 .expect("too short")
1904 .unwrap()
1900 .unwrap()
1905 .format_flags()
1901 .format_flags()
1906 .uses_generaldelta()
1902 .uses_generaldelta()
1907 }
1903 }
1908
1904
1909 pub fn get_version(index_bytes: &[u8]) -> u16 {
1905 pub fn get_version(index_bytes: &[u8]) -> u16 {
1910 IndexHeader::parse(index_bytes)
1906 IndexHeader::parse(index_bytes)
1911 .expect("too short")
1907 .expect("too short")
1912 .unwrap()
1908 .unwrap()
1913 .format_version()
1909 .format_version()
1914 }
1910 }
1915
1911
1916 #[test]
1912 #[test]
1917 fn flags_when_no_inline_flag_test() {
1913 fn flags_when_no_inline_flag_test() {
1918 let bytes = IndexEntryBuilder::new()
1914 let bytes = IndexEntryBuilder::new()
1919 .is_first(true)
1915 .is_first(true)
1920 .with_general_delta(false)
1916 .with_general_delta(false)
1921 .with_inline(false)
1917 .with_inline(false)
1922 .build();
1918 .build();
1923
1919
1924 assert!(!is_inline(&bytes));
1920 assert!(!is_inline(&bytes));
1925 assert!(!uses_generaldelta(&bytes));
1921 assert!(!uses_generaldelta(&bytes));
1926 }
1922 }
1927
1923
1928 #[test]
1924 #[test]
1929 fn flags_when_inline_flag_test() {
1925 fn flags_when_inline_flag_test() {
1930 let bytes = IndexEntryBuilder::new()
1926 let bytes = IndexEntryBuilder::new()
1931 .is_first(true)
1927 .is_first(true)
1932 .with_general_delta(false)
1928 .with_general_delta(false)
1933 .with_inline(true)
1929 .with_inline(true)
1934 .build();
1930 .build();
1935
1931
1936 assert!(is_inline(&bytes));
1932 assert!(is_inline(&bytes));
1937 assert!(!uses_generaldelta(&bytes));
1933 assert!(!uses_generaldelta(&bytes));
1938 }
1934 }
1939
1935
1940 #[test]
1936 #[test]
1941 fn flags_when_inline_and_generaldelta_flags_test() {
1937 fn flags_when_inline_and_generaldelta_flags_test() {
1942 let bytes = IndexEntryBuilder::new()
1938 let bytes = IndexEntryBuilder::new()
1943 .is_first(true)
1939 .is_first(true)
1944 .with_general_delta(true)
1940 .with_general_delta(true)
1945 .with_inline(true)
1941 .with_inline(true)
1946 .build();
1942 .build();
1947
1943
1948 assert!(is_inline(&bytes));
1944 assert!(is_inline(&bytes));
1949 assert!(uses_generaldelta(&bytes));
1945 assert!(uses_generaldelta(&bytes));
1950 }
1946 }
1951
1947
1952 #[test]
1948 #[test]
1953 fn test_offset() {
1949 fn test_offset() {
1954 let bytes = IndexEntryBuilder::new().with_offset(1).build();
1950 let bytes = IndexEntryBuilder::new().with_offset(1).build();
1955 let entry = IndexEntry { bytes: &bytes };
1951 let entry = IndexEntry { bytes: &bytes };
1956
1952
1957 assert_eq!(entry.offset(), 1)
1953 assert_eq!(entry.offset(), 1)
1958 }
1954 }
1959
1955
1960 #[test]
1956 #[test]
1961 fn test_compressed_len() {
1957 fn test_compressed_len() {
1962 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
1958 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
1963 let entry = IndexEntry { bytes: &bytes };
1959 let entry = IndexEntry { bytes: &bytes };
1964
1960
1965 assert_eq!(entry.compressed_len(), 1)
1961 assert_eq!(entry.compressed_len(), 1)
1966 }
1962 }
1967
1963
1968 #[test]
1964 #[test]
1969 fn test_uncompressed_len() {
1965 fn test_uncompressed_len() {
1970 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
1966 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
1971 let entry = IndexEntry { bytes: &bytes };
1967 let entry = IndexEntry { bytes: &bytes };
1972
1968
1973 assert_eq!(entry.uncompressed_len(), 1)
1969 assert_eq!(entry.uncompressed_len(), 1)
1974 }
1970 }
1975
1971
1976 #[test]
1972 #[test]
1977 fn test_base_revision_or_base_of_delta_chain() {
1973 fn test_base_revision_or_base_of_delta_chain() {
1978 let bytes = IndexEntryBuilder::new()
1974 let bytes = IndexEntryBuilder::new()
1979 .with_base_revision_or_base_of_delta_chain(Revision(1))
1975 .with_base_revision_or_base_of_delta_chain(Revision(1))
1980 .build();
1976 .build();
1981 let entry = IndexEntry { bytes: &bytes };
1977 let entry = IndexEntry { bytes: &bytes };
1982
1978
1983 assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1.into())
1979 assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1.into())
1984 }
1980 }
1985
1981
1986 #[test]
1982 #[test]
1987 fn link_revision_test() {
1983 fn link_revision_test() {
1988 let bytes = IndexEntryBuilder::new()
1984 let bytes = IndexEntryBuilder::new()
1989 .with_link_revision(Revision(123))
1985 .with_link_revision(Revision(123))
1990 .build();
1986 .build();
1991
1987
1992 let entry = IndexEntry { bytes: &bytes };
1988 let entry = IndexEntry { bytes: &bytes };
1993
1989
1994 assert_eq!(entry.link_revision(), 123.into());
1990 assert_eq!(entry.link_revision(), 123.into());
1995 }
1991 }
1996
1992
1997 #[test]
1993 #[test]
1998 fn p1_test() {
1994 fn p1_test() {
1999 let bytes = IndexEntryBuilder::new().with_p1(Revision(123)).build();
1995 let bytes = IndexEntryBuilder::new().with_p1(Revision(123)).build();
2000
1996
2001 let entry = IndexEntry { bytes: &bytes };
1997 let entry = IndexEntry { bytes: &bytes };
2002
1998
2003 assert_eq!(entry.p1(), 123.into());
1999 assert_eq!(entry.p1(), 123.into());
2004 }
2000 }
2005
2001
2006 #[test]
2002 #[test]
2007 fn p2_test() {
2003 fn p2_test() {
2008 let bytes = IndexEntryBuilder::new().with_p2(Revision(123)).build();
2004 let bytes = IndexEntryBuilder::new().with_p2(Revision(123)).build();
2009
2005
2010 let entry = IndexEntry { bytes: &bytes };
2006 let entry = IndexEntry { bytes: &bytes };
2011
2007
2012 assert_eq!(entry.p2(), 123.into());
2008 assert_eq!(entry.p2(), 123.into());
2013 }
2009 }
2014
2010
2015 #[test]
2011 #[test]
2016 fn node_test() {
2012 fn node_test() {
2017 let node = Node::from_hex("0123456789012345678901234567890123456789")
2013 let node = Node::from_hex("0123456789012345678901234567890123456789")
2018 .unwrap();
2014 .unwrap();
2019 let bytes = IndexEntryBuilder::new().with_node(node).build();
2015 let bytes = IndexEntryBuilder::new().with_node(node).build();
2020
2016
2021 let entry = IndexEntry { bytes: &bytes };
2017 let entry = IndexEntry { bytes: &bytes };
2022
2018
2023 assert_eq!(*entry.hash(), node);
2019 assert_eq!(*entry.hash(), node);
2024 }
2020 }
2025
2021
2026 #[test]
2022 #[test]
2027 fn version_test() {
2023 fn version_test() {
2028 let bytes = IndexEntryBuilder::new()
2024 let bytes = IndexEntryBuilder::new()
2029 .is_first(true)
2025 .is_first(true)
2030 .with_version(2)
2026 .with_version(2)
2031 .build();
2027 .build();
2032
2028
2033 assert_eq!(get_version(&bytes), 2)
2029 assert_eq!(get_version(&bytes), 2)
2034 }
2030 }
2035 }
2031 }
General Comments 0
You need to be logged in to leave comments. Login now