##// END OF EJS Templates
rust-revlog: teach the revlog opening code to read the repo options...
Raphaël Gomès -
r52084:13f58ce7 default
parent child Browse files
Show More
@@ -16,6 +16,7 b' and O(changes) merge between branches.'
16 16 import binascii
17 17 import collections
18 18 import contextlib
19 import functools
19 20 import io
20 21 import os
21 22 import struct
@@ -224,9 +225,9 b' else:'
224 225 parse_index_v1_nodemap = None
225 226
226 227
227 def parse_index_v1_mixed(data, inline):
228 def parse_index_v1_mixed(data, inline, default_header):
228 229 index, cache = parse_index_v1(data, inline)
229 return rustrevlog.MixedIndex(index, data), cache
230 return rustrevlog.MixedIndex(index, data, default_header), cache
230 231
231 232
232 233 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
@@ -1694,7 +1695,9 b' class revlog:'
1694 1695 elif devel_nodemap:
1695 1696 self._parse_index = parse_index_v1_nodemap
1696 1697 elif use_rust_index:
1697 self._parse_index = parse_index_v1_mixed
1698 self._parse_index = functools.partial(
1699 parse_index_v1_mixed, default_header=new_header
1700 )
1698 1701 try:
1699 1702 d = self._parse_index(index_data, self._inline)
1700 1703 index, chunkcache = d
@@ -6,11 +6,10 b''
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 use crate::repo::Repo;
9 use crate::requirements;
10 9 use crate::revlog::{Revlog, RevlogError};
11 10
12 11 /// Kind of data to debug
13 #[derive(Debug, Copy, Clone)]
12 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
14 13 pub enum DebugDataKind {
15 14 Changelog,
16 15 Manifest,
@@ -26,11 +25,12 b' pub fn debug_data('
26 25 DebugDataKind::Changelog => "00changelog.i",
27 26 DebugDataKind::Manifest => "00manifest.i",
28 27 };
29 let use_nodemap = repo
30 .requirements()
31 .contains(requirements::NODEMAP_REQUIREMENT);
32 let revlog =
33 Revlog::open(&repo.store_vfs(), index_file, None, use_nodemap)?;
28 let revlog = Revlog::open(
29 &repo.store_vfs(),
30 index_file,
31 None,
32 repo.default_revlog_options(kind == DebugDataKind::Changelog)?,
33 )?;
34 34 let rev =
35 35 crate::revset::resolve_rev_number_or_hex_prefix(revset, &revlog)?;
36 36 let data = revlog.get_rev_data_for_checked_rev(rev)?;
@@ -8,6 +8,10 b' use crate::errors::HgResultExt;'
8 8 use crate::errors::{HgError, IoResultExt};
9 9 use crate::lock::{try_with_lock_no_wait, LockError};
10 10 use crate::manifest::{Manifest, Manifestlog};
11 use crate::requirements::{
12 CHANGELOGV2_REQUIREMENT, GENERALDELTA_REQUIREMENT, NODEMAP_REQUIREMENT,
13 REVLOGV1_REQUIREMENT, REVLOGV2_REQUIREMENT,
14 };
11 15 use crate::revlog::filelog::Filelog;
12 16 use crate::revlog::RevlogError;
13 17 use crate::utils::debug::debug_wait_for_file_or_print;
@@ -15,8 +19,10 b' use crate::utils::files::get_path_from_b'
15 19 use crate::utils::hg_path::HgPath;
16 20 use crate::utils::SliceExt;
17 21 use crate::vfs::{is_dir, is_file, Vfs};
18 use crate::DirstateError;
19 use crate::{requirements, NodePrefix, UncheckedRevision};
22 use crate::{
23 requirements, NodePrefix, RevlogVersionOptions, UncheckedRevision,
24 };
25 use crate::{DirstateError, RevlogOpenOptions};
20 26 use std::cell::{Ref, RefCell, RefMut};
21 27 use std::collections::HashSet;
22 28 use std::io::Seek;
@@ -523,7 +529,7 b' impl Repo {'
523 529 }
524 530
525 531 fn new_changelog(&self) -> Result<Changelog, HgError> {
526 Changelog::open(&self.store_vfs(), self.has_nodemap())
532 Changelog::open(&self.store_vfs(), self.default_revlog_options(true)?)
527 533 }
528 534
529 535 pub fn changelog(&self) -> Result<Ref<Changelog>, HgError> {
@@ -535,7 +541,10 b' impl Repo {'
535 541 }
536 542
537 543 fn new_manifestlog(&self) -> Result<Manifestlog, HgError> {
538 Manifestlog::open(&self.store_vfs(), self.has_nodemap())
544 Manifestlog::open(
545 &self.store_vfs(),
546 self.default_revlog_options(false)?,
547 )
539 548 }
540 549
541 550 pub fn manifestlog(&self) -> Result<Ref<Manifestlog>, HgError> {
@@ -581,7 +590,7 b' impl Repo {'
581 590 }
582 591
583 592 pub fn filelog(&self, path: &HgPath) -> Result<Filelog, HgError> {
584 Filelog::open(self, path)
593 Filelog::open(self, path, self.default_revlog_options(false)?)
585 594 }
586 595
587 596 /// Write to disk any updates that were made through `dirstate_map_mut`.
@@ -730,6 +739,35 b' impl Repo {'
730 739 }
731 740 Ok(())
732 741 }
742
743 pub fn default_revlog_options(
744 &self,
745 changelog: bool,
746 ) -> Result<RevlogOpenOptions, HgError> {
747 let requirements = self.requirements();
748 let version = if changelog
749 && requirements.contains(CHANGELOGV2_REQUIREMENT)
750 {
751 let compute_rank = self
752 .config()
753 .get_bool(b"experimental", b"changelog-v2.compute-rank")?;
754 RevlogVersionOptions::ChangelogV2 { compute_rank }
755 } else if requirements.contains(REVLOGV2_REQUIREMENT) {
756 RevlogVersionOptions::V2
757 } else if requirements.contains(REVLOGV1_REQUIREMENT) {
758 RevlogVersionOptions::V1 {
759 generaldelta: requirements.contains(GENERALDELTA_REQUIREMENT),
760 }
761 } else {
762 RevlogVersionOptions::V0
763 };
764 Ok(RevlogOpenOptions {
765 version,
766 // We don't need to dance around the slow path like in the Python
767 // implementation since we know we have access to the fast code.
768 use_nodemap: requirements.contains(NODEMAP_REQUIREMENT),
769 })
770 }
733 771 }
734 772
735 773 /// Lazily-initialized component of `Repo` with interior mutability
@@ -77,7 +77,7 b' const REQUIRED: &[&str] = &["revlogv1", '
77 77
78 78 /// rhg supports repository with or without these
79 79 const SUPPORTED: &[&str] = &[
80 "generaldelta",
80 GENERALDELTA_REQUIREMENT,
81 81 SHARED_REQUIREMENT,
82 82 SHARESAFE_REQUIREMENT,
83 83 SPARSEREVLOG_REQUIREMENT,
@@ -100,6 +100,7 b' const SUPPORTED: &[&str] = &['
100 100 // Copied from mercurial/requirements.py:
101 101
102 102 pub const DIRSTATE_V2_REQUIREMENT: &str = "dirstate-v2";
103 pub const GENERALDELTA_REQUIREMENT: &str = "generaldelta";
103 104
104 105 /// A repository that uses the tracked hint dirstate file
105 106 #[allow(unused)]
@@ -128,11 +129,20 b' pub const INTERNAL_PHASE_REQUIREMENT: &s'
128 129 #[allow(unused)]
129 130 pub const TREEMANIFEST_REQUIREMENT: &str = "treemanifest";
130 131
132 /// Whether to use the "RevlogNG" or V1 of the revlog format
133 #[allow(unused)]
134 pub const REVLOGV1_REQUIREMENT: &str = "revlogv1";
135
131 136 /// Increment the sub-version when the revlog v2 format changes to lock out old
132 137 /// clients.
133 138 #[allow(unused)]
134 139 pub const REVLOGV2_REQUIREMENT: &str = "exp-revlogv2.1";
135 140
141 /// Increment the sub-version when the revlog v2 format changes to lock out old
142 /// clients.
143 #[allow(unused)]
144 pub const CHANGELOGV2_REQUIREMENT: &str = "exp-changelog-v2";
145
136 146 /// A repository with the sparserevlog feature will have delta chains that
137 147 /// can spread over a larger span. Sparse reading cuts these large spans into
138 148 /// pieces, so that each piece isn't too big.
@@ -4,7 +4,7 b' use crate::revlog::{Node, NodePrefix};'
4 4 use crate::revlog::{Revlog, RevlogEntry, RevlogError};
5 5 use crate::utils::hg_path::HgPath;
6 6 use crate::vfs::Vfs;
7 use crate::{Graph, GraphError, UncheckedRevision};
7 use crate::{Graph, GraphError, RevlogOpenOptions, UncheckedRevision};
8 8 use itertools::Itertools;
9 9 use std::ascii::escape_default;
10 10 use std::borrow::Cow;
@@ -18,9 +18,11 b' pub struct Changelog {'
18 18
19 19 impl Changelog {
20 20 /// Open the `changelog` of a repository given by its root.
21 pub fn open(store_vfs: &Vfs, use_nodemap: bool) -> Result<Self, HgError> {
22 let revlog =
23 Revlog::open(store_vfs, "00changelog.i", None, use_nodemap)?;
21 pub fn open(
22 store_vfs: &Vfs,
23 options: RevlogOpenOptions,
24 ) -> Result<Self, HgError> {
25 let revlog = Revlog::open(store_vfs, "00changelog.i", None, options)?;
24 26 Ok(Self { revlog })
25 27 }
26 28
@@ -342,7 +344,9 b' message",'
342 344 let temp = tempfile::tempdir().unwrap();
343 345 let vfs = Vfs { base: temp.path() };
344 346 std::fs::write(temp.path().join("foo.i"), b"").unwrap();
345 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
347 let revlog =
348 Revlog::open(&vfs, "foo.i", None, RevlogOpenOptions::new())
349 .unwrap();
346 350
347 351 let changelog = Changelog { revlog };
348 352 assert_eq!(
@@ -11,6 +11,7 b' use crate::utils::hg_path::HgPath;'
11 11 use crate::utils::SliceExt;
12 12 use crate::Graph;
13 13 use crate::GraphError;
14 use crate::RevlogOpenOptions;
14 15 use crate::UncheckedRevision;
15 16 use std::path::PathBuf;
16 17
@@ -30,16 +31,21 b' impl Filelog {'
30 31 pub fn open_vfs(
31 32 store_vfs: &crate::vfs::Vfs<'_>,
32 33 file_path: &HgPath,
34 options: RevlogOpenOptions,
33 35 ) -> Result<Self, HgError> {
34 36 let index_path = store_path(file_path, b".i");
35 37 let data_path = store_path(file_path, b".d");
36 38 let revlog =
37 Revlog::open(store_vfs, index_path, Some(&data_path), false)?;
39 Revlog::open(store_vfs, index_path, Some(&data_path), options)?;
38 40 Ok(Self { revlog })
39 41 }
40 42
41 pub fn open(repo: &Repo, file_path: &HgPath) -> Result<Self, HgError> {
42 Self::open_vfs(&repo.store_vfs(), file_path)
43 pub fn open(
44 repo: &Repo,
45 file_path: &HgPath,
46 options: RevlogOpenOptions,
47 ) -> Result<Self, HgError> {
48 Self::open_vfs(&repo.store_vfs(), file_path, options)
43 49 }
44 50
45 51 /// The given node ID is that of the file as found in a filelog, not of a
@@ -15,7 +15,7 b' pub const INDEX_ENTRY_SIZE: usize = 64;'
15 15 pub const COMPRESSION_MODE_INLINE: u8 = 2;
16 16
17 17 pub struct IndexHeader {
18 header_bytes: [u8; 4],
18 pub(super) header_bytes: [u8; 4],
19 19 }
20 20
21 21 #[derive(Copy, Clone)]
@@ -54,32 +54,22 b' impl IndexHeader {'
54 54 BigEndian::read_u16(&self.header_bytes[2..4])
55 55 }
56 56
57 const EMPTY_INDEX_HEADER: IndexHeader = IndexHeader {
58 // We treat an empty file as a valid index with no entries.
59 // Here we make an arbitrary choice of what we assume the format of the
60 // index to be (V1, using generaldelta).
61 // This doesn't matter too much, since we're only doing read-only
62 // access. but the value corresponds to the `new_header` variable in
63 // `revlog.py`, `_loadindex`
64 header_bytes: [0, 3, 0, 1],
65 };
66
67 fn parse(index_bytes: &[u8]) -> Result<IndexHeader, HgError> {
57 pub fn parse(index_bytes: &[u8]) -> Result<Option<IndexHeader>, HgError> {
68 58 if index_bytes.is_empty() {
69 return Ok(IndexHeader::EMPTY_INDEX_HEADER);
59 return Ok(None);
70 60 }
71 61 if index_bytes.len() < 4 {
72 62 return Err(HgError::corrupted(
73 63 "corrupted revlog: can't read the index format header",
74 64 ));
75 65 }
76 Ok(IndexHeader {
66 Ok(Some(IndexHeader {
77 67 header_bytes: {
78 68 let bytes: [u8; 4] =
79 69 index_bytes[0..4].try_into().expect("impossible");
80 70 bytes
81 71 },
82 })
72 }))
83 73 }
84 74 }
85 75
@@ -239,8 +229,10 b' impl Index {'
239 229 /// Calculate the start of each entry when is_inline is true.
240 230 pub fn new(
241 231 bytes: Box<dyn Deref<Target = [u8]> + Send>,
232 default_header: IndexHeader,
242 233 ) -> Result<Self, HgError> {
243 let header = IndexHeader::parse(bytes.as_ref())?;
234 let header =
235 IndexHeader::parse(bytes.as_ref())?.unwrap_or(default_header);
244 236
245 237 if header.format_version() != IndexHeader::REVLOGV1 {
246 238 // A proper new version should have had a repo/store
@@ -598,6 +590,7 b' mod tests {'
598 590 pub fn is_inline(index_bytes: &[u8]) -> bool {
599 591 IndexHeader::parse(index_bytes)
600 592 .expect("too short")
593 .unwrap()
601 594 .format_flags()
602 595 .is_inline()
603 596 }
@@ -605,6 +598,7 b' mod tests {'
605 598 pub fn uses_generaldelta(index_bytes: &[u8]) -> bool {
606 599 IndexHeader::parse(index_bytes)
607 600 .expect("too short")
601 .unwrap()
608 602 .format_flags()
609 603 .uses_generaldelta()
610 604 }
@@ -612,6 +606,7 b' mod tests {'
612 606 pub fn get_version(index_bytes: &[u8]) -> u16 {
613 607 IndexHeader::parse(index_bytes)
614 608 .expect("too short")
609 .unwrap()
615 610 .format_version()
616 611 }
617 612
@@ -4,12 +4,14 b' use crate::revlog::{Revlog, RevlogError}'
4 4 use crate::utils::hg_path::HgPath;
5 5 use crate::utils::SliceExt;
6 6 use crate::vfs::Vfs;
7 use crate::{Graph, GraphError, Revision, UncheckedRevision};
7 use crate::{
8 Graph, GraphError, Revision, RevlogOpenOptions, UncheckedRevision,
9 };
8 10
9 11 /// A specialized `Revlog` to work with `manifest` data format.
10 12 pub struct Manifestlog {
11 13 /// The generic `revlog` format.
12 revlog: Revlog,
14 pub(crate) revlog: Revlog,
13 15 }
14 16
15 17 impl Graph for Manifestlog {
@@ -20,9 +22,11 b' impl Graph for Manifestlog {'
20 22
21 23 impl Manifestlog {
22 24 /// Open the `manifest` of a repository given by its root.
23 pub fn open(store_vfs: &Vfs, use_nodemap: bool) -> Result<Self, HgError> {
24 let revlog =
25 Revlog::open(store_vfs, "00manifest.i", None, use_nodemap)?;
25 pub fn open(
26 store_vfs: &Vfs,
27 options: RevlogOpenOptions,
28 ) -> Result<Self, HgError> {
29 let revlog = Revlog::open(store_vfs, "00manifest.i", None, options)?;
26 30 Ok(Self { revlog })
27 31 }
28 32
@@ -225,6 +225,55 b' impl Graph for Revlog {'
225 225 }
226 226 }
227 227
228 #[derive(Debug, Copy, Clone)]
229 pub enum RevlogVersionOptions {
230 V0,
231 V1 { generaldelta: bool },
232 V2,
233 ChangelogV2 { compute_rank: bool },
234 }
235
236 /// Options to govern how a revlog should be opened, usually from the
237 /// repository configuration or requirements.
238 #[derive(Debug, Copy, Clone)]
239 pub struct RevlogOpenOptions {
240 /// The revlog version, along with any option specific to this version
241 pub version: RevlogVersionOptions,
242 /// Whether the revlog uses a persistent nodemap.
243 pub use_nodemap: bool,
244 // TODO other non-header/version options,
245 }
246
247 impl RevlogOpenOptions {
248 pub fn new() -> Self {
249 Self {
250 version: RevlogVersionOptions::V1 { generaldelta: true },
251 use_nodemap: false,
252 }
253 }
254
255 fn default_index_header(&self) -> index::IndexHeader {
256 index::IndexHeader {
257 header_bytes: match self.version {
258 RevlogVersionOptions::V0 => [0, 0, 0, 0],
259 RevlogVersionOptions::V1 { generaldelta } => {
260 [0, if generaldelta { 3 } else { 1 }, 0, 1]
261 }
262 RevlogVersionOptions::V2 => 0xDEADu32.to_be_bytes(),
263 RevlogVersionOptions::ChangelogV2 { compute_rank: _ } => {
264 0xD34Du32.to_be_bytes()
265 }
266 },
267 }
268 }
269 }
270
271 impl Default for RevlogOpenOptions {
272 fn default() -> Self {
273 Self::new()
274 }
275 }
276
228 277 impl Revlog {
229 278 /// Open a revlog index file.
230 279 ///
@@ -234,24 +283,30 b' impl Revlog {'
234 283 store_vfs: &Vfs,
235 284 index_path: impl AsRef<Path>,
236 285 data_path: Option<&Path>,
237 use_nodemap: bool,
286 options: RevlogOpenOptions,
238 287 ) -> Result<Self, HgError> {
239 Self::open_gen(store_vfs, index_path, data_path, use_nodemap, None)
288 Self::open_gen(store_vfs, index_path, data_path, options, None)
240 289 }
241 290
242 291 fn open_gen(
243 292 store_vfs: &Vfs,
244 293 index_path: impl AsRef<Path>,
245 294 data_path: Option<&Path>,
246 use_nodemap: bool,
295 options: RevlogOpenOptions,
247 296 nodemap_for_test: Option<nodemap::NodeTree>,
248 297 ) -> Result<Self, HgError> {
249 298 let index_path = index_path.as_ref();
250 299 let index = {
251 300 match store_vfs.mmap_open_opt(index_path)? {
252 None => Index::new(Box::<Vec<_>>::default()),
301 None => Index::new(
302 Box::<Vec<_>>::default(),
303 options.default_index_header(),
304 ),
253 305 Some(index_mmap) => {
254 let index = Index::new(Box::new(index_mmap))?;
306 let index = Index::new(
307 Box::new(index_mmap),
308 options.default_index_header(),
309 )?;
255 310 Ok(index)
256 311 }
257 312 }
@@ -270,7 +325,7 b' impl Revlog {'
270 325 Some(Box::new(data_mmap))
271 326 };
272 327
273 let nodemap = if index.is_inline() || !use_nodemap {
328 let nodemap = if index.is_inline() || !options.use_nodemap {
274 329 None
275 330 } else {
276 331 NodeMapDocket::read_from_file(store_vfs, index_path)?.map(
@@ -809,7 +864,9 b' mod tests {'
809 864 let temp = tempfile::tempdir().unwrap();
810 865 let vfs = Vfs { base: temp.path() };
811 866 std::fs::write(temp.path().join("foo.i"), b"").unwrap();
812 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
867 let revlog =
868 Revlog::open(&vfs, "foo.i", None, RevlogOpenOptions::new())
869 .unwrap();
813 870 assert!(revlog.is_empty());
814 871 assert_eq!(revlog.len(), 0);
815 872 assert!(revlog.get_entry(0.into()).is_err());
@@ -855,7 +912,9 b' mod tests {'
855 912 .flatten()
856 913 .collect_vec();
857 914 std::fs::write(temp.path().join("foo.i"), contents).unwrap();
858 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
915 let revlog =
916 Revlog::open(&vfs, "foo.i", None, RevlogOpenOptions::new())
917 .unwrap();
859 918
860 919 let entry0 = revlog.get_entry(0.into()).ok().unwrap();
861 920 assert_eq!(entry0.revision(), Revision(0));
@@ -926,8 +985,14 b' mod tests {'
926 985 idx.insert_node(Revision(0), node0).unwrap();
927 986 idx.insert_node(Revision(1), node1).unwrap();
928 987
929 let revlog =
930 Revlog::open_gen(&vfs, "foo.i", None, true, Some(idx.nt)).unwrap();
988 let revlog = Revlog::open_gen(
989 &vfs,
990 "foo.i",
991 None,
992 RevlogOpenOptions::new(),
993 Some(idx.nt),
994 )
995 .unwrap();
931 996
932 997 // accessing the data shows the corruption
933 998 revlog.get_entry(0.into()).unwrap().data().unwrap_err();
@@ -17,6 +17,7 b' use cpython::{'
17 17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
18 18 };
19 19 use hg::{
20 index::IndexHeader,
20 21 nodemap::{Block, NodeMapError, NodeTree},
21 22 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
22 23 BaseRevision, Revision, UncheckedRevision,
@@ -47,9 +48,10 b' py_class!(pub class MixedIndex |py| {'
47 48 def __new__(
48 49 _cls,
49 50 cindex: PyObject,
50 data: PyObject
51 data: PyObject,
52 default_header: u32,
51 53 ) -> PyResult<MixedIndex> {
52 Self::new(py, cindex, data)
54 Self::new(py, cindex, data, default_header)
53 55 }
54 56
55 57 /// Compatibility layer used for Python consumers needing access to the C index
@@ -364,6 +366,7 b' impl MixedIndex {'
364 366 py: Python,
365 367 cindex: PyObject,
366 368 data: PyObject,
369 header: u32,
367 370 ) -> PyResult<MixedIndex> {
368 371 // Safety: we keep the buffer around inside the class as `index_mmap`
369 372 let (buf, bytes) = unsafe { mmap_keeparound(py, data)? };
@@ -371,7 +374,15 b' impl MixedIndex {'
371 374 Self::create_instance(
372 375 py,
373 376 RefCell::new(cindex::Index::new(py, cindex)?),
374 RefCell::new(hg::index::Index::new(bytes).unwrap()),
377 RefCell::new(
378 hg::index::Index::new(
379 bytes,
380 IndexHeader::parse(&header.to_be_bytes())
381 .expect("default header is broken")
382 .unwrap(),
383 )
384 .unwrap(),
385 ),
375 386 RefCell::new(None),
376 387 RefCell::new(None),
377 388 RefCell::new(None),
@@ -28,12 +28,12 b' use hg::utils::files::{'
28 28 get_bytes_from_os_str, get_bytes_from_os_string, get_path_from_bytes,
29 29 };
30 30 use hg::utils::hg_path::{hg_path_to_path_buf, HgPath};
31 use hg::DirstateStatus;
32 31 use hg::PatternFileWarning;
33 32 use hg::Revision;
34 33 use hg::StatusError;
35 34 use hg::StatusOptions;
36 35 use hg::{self, narrow, sparse};
36 use hg::{DirstateStatus, RevlogOpenOptions};
37 37 use log::info;
38 38 use rayon::prelude::*;
39 39 use std::borrow::Cow;
@@ -383,6 +383,7 b' pub fn run(invocation: &crate::CliInvoca'
383 383 })?;
384 384 let working_directory_vfs = repo.working_directory_vfs();
385 385 let store_vfs = repo.store_vfs();
386 let revlog_open_options = repo.default_revlog_options(false)?;
386 387 let res: Vec<_> = take(&mut ds_status.unsure)
387 388 .into_par_iter()
388 389 .map(|to_check| {
@@ -396,6 +397,7 b' pub fn run(invocation: &crate::CliInvoca'
396 397 check_exec,
397 398 &manifest,
398 399 &to_check.path,
400 revlog_open_options,
399 401 ) {
400 402 Err(HgError::IoError { .. }) => {
401 403 // IO errors most likely stem from the file being
@@ -747,6 +749,7 b' fn unsure_is_modified('
747 749 check_exec: bool,
748 750 manifest: &Manifest,
749 751 hg_path: &HgPath,
752 revlog_open_options: RevlogOpenOptions,
750 753 ) -> Result<UnsureOutcome, HgError> {
751 754 let vfs = working_directory_vfs;
752 755 let fs_path = hg_path_to_path_buf(hg_path).expect("HgPath conversion");
@@ -778,7 +781,11 b' fn unsure_is_modified('
778 781 if entry_flags != fs_flags {
779 782 return Ok(UnsureOutcome::Modified);
780 783 }
781 let filelog = hg::filelog::Filelog::open_vfs(&store_vfs, hg_path)?;
784 let filelog = hg::filelog::Filelog::open_vfs(
785 &store_vfs,
786 hg_path,
787 revlog_open_options,
788 )?;
782 789 let fs_len = fs_metadata.len();
783 790 let file_node = entry.node_id()?;
784 791 let filelog_entry = filelog.entry_for_node(file_node).map_err(|_| {
@@ -1,3 +1,4 b''
1 import struct
1 2 import unittest
2 3
3 4 try:
@@ -14,6 +15,8 b' else:'
14 15
15 16 from mercurial.testing import revlog as revlogtesting
16 17
18 header = struct.unpack(">I", revlogtesting.data_non_inlined[:4])[0]
19
17 20
18 21 @unittest.skipIf(
19 22 rustext is None,
@@ -22,24 +25,24 b' from mercurial.testing import revlog as '
22 25 class RustRevlogIndexTest(revlogtesting.RevlogBasedTestBase):
23 26 def test_heads(self):
24 27 idx = self.parseindex()
25 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined)
28 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined, header)
26 29 self.assertEqual(rustidx.headrevs(), idx.headrevs())
27 30
28 31 def test_get_cindex(self):
29 32 # drop me once we no longer need the method for shortest node
30 33 idx = self.parseindex()
31 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined)
34 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined, header)
32 35 cidx = rustidx.get_cindex()
33 36 self.assertTrue(idx is cidx)
34 37
35 38 def test_len(self):
36 39 idx = self.parseindex()
37 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined)
40 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined, header)
38 41 self.assertEqual(len(rustidx), len(idx))
39 42
40 43 def test_ancestors(self):
41 44 idx = self.parseindex()
42 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined)
45 rustidx = revlog.MixedIndex(idx, revlogtesting.data_non_inlined, header)
43 46 lazy = LazyAncestors(rustidx, [3], 0, True)
44 47 # we have two more references to the index:
45 48 # - in its inner iterator for __contains__ and __bool__
General Comments 0
You need to be logged in to leave comments. Login now