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