rust-status: don't trigger dirstate v1 rewrite when only v2 data is changed
The assumption that we need to rewrite (or append to) the dirstate if the
ignore pattern hash has changed or if any cached directory mtimes have changed
is only valid when using dirstate-v2. In dirstate-v1, neither of these things
are written to disk.
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Tue Jun 14 04:04:08 2022 +0200
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Wed Jun 08 19:15:58 2022 +0200
@@ -31,6 +31,13 @@
/// anymore) is less than this fraction of the total amount of existing data.
const ACCEPTABLE_UNREACHABLE_BYTES_RATIO: f32 = 0.5;
+#[derive(Debug, PartialEq, Eq)]
+/// Version of the on-disk format
+pub enum DirstateVersion {
+ V1,
+ V2,
+}
+
pub struct DirstateMap<'on_disk> {
/// Contents of the `.hg/dirstate` file
pub(super) on_disk: &'on_disk [u8],
@@ -53,6 +60,8 @@
/// Size of the data used to first load this `DirstateMap`. Used in case
/// we need to write some new metadata, but no new data on disk.
pub(super) old_data_size: usize,
+
+ pub(super) dirstate_version: DirstateVersion,
}
/// Using a plain `HgPathBuf` of the full path from the repository root as a
@@ -434,6 +443,7 @@
ignore_patterns_hash: [0; on_disk::IGNORE_PATTERNS_HASH_LEN],
unreachable_bytes: 0,
old_data_size: 0,
+ dirstate_version: DirstateVersion::V1,
}
}
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs Tue Jun 14 04:04:08 2022 +0200
+++ b/rust/hg-core/src/dirstate_tree/on_disk.rs Wed Jun 08 19:15:58 2022 +0200
@@ -3,6 +3,7 @@
//! See `mercurial/helptext/internals/dirstate-v2.txt`
use crate::dirstate::TruncatedTimestamp;
+use crate::dirstate_tree::dirstate_map::DirstateVersion;
use crate::dirstate_tree::dirstate_map::{self, DirstateMap, NodeRef};
use crate::dirstate_tree::path_with_basename::WithBasename;
use crate::errors::HgError;
@@ -276,7 +277,9 @@
metadata: &[u8],
) -> Result<DirstateMap<'on_disk>, DirstateV2ParseError> {
if on_disk.is_empty() {
- return Ok(DirstateMap::empty(on_disk));
+ let mut map = DirstateMap::empty(on_disk);
+ map.dirstate_version = DirstateVersion::V2;
+ return Ok(map);
}
let (meta, _) = TreeMetadata::from_bytes(metadata)
.map_err(|_| DirstateV2ParseError)?;
@@ -291,6 +294,7 @@
ignore_patterns_hash: meta.ignore_patterns_hash,
unreachable_bytes: meta.unreachable_bytes.get(),
old_data_size: on_disk.len(),
+ dirstate_version: DirstateVersion::V2,
};
Ok(dirstate_map)
}
--- a/rust/hg-core/src/dirstate_tree/status.rs Tue Jun 14 04:04:08 2022 +0200
+++ b/rust/hg-core/src/dirstate_tree/status.rs Wed Jun 08 19:15:58 2022 +0200
@@ -4,6 +4,7 @@
use crate::dirstate_tree::dirstate_map::BorrowedPath;
use crate::dirstate_tree::dirstate_map::ChildNodesRef;
use crate::dirstate_tree::dirstate_map::DirstateMap;
+use crate::dirstate_tree::dirstate_map::DirstateVersion;
use crate::dirstate_tree::dirstate_map::NodeData;
use crate::dirstate_tree::dirstate_map::NodeRef;
use crate::dirstate_tree::on_disk::DirstateV2ParseError;
@@ -61,16 +62,29 @@
let (ignore_fn, warnings, patterns_changed): (IgnoreFnType, _, _) =
if options.list_ignored || options.list_unknown {
- let mut hasher = Sha1::new();
- let (ignore_fn, warnings) = get_ignore_function(
- ignore_files,
- &root_dir,
- &mut |pattern_bytes| hasher.update(pattern_bytes),
- )?;
- let new_hash = *hasher.finalize().as_ref();
- let changed = new_hash != dmap.ignore_patterns_hash;
- dmap.ignore_patterns_hash = new_hash;
- (ignore_fn, warnings, Some(changed))
+ let (ignore_fn, warnings, changed) = match dmap.dirstate_version {
+ DirstateVersion::V1 => {
+ let (ignore_fn, warnings) = get_ignore_function(
+ ignore_files,
+ &root_dir,
+ &mut |_pattern_bytes| {},
+ )?;
+ (ignore_fn, warnings, None)
+ }
+ DirstateVersion::V2 => {
+ let mut hasher = Sha1::new();
+ let (ignore_fn, warnings) = get_ignore_function(
+ ignore_files,
+ &root_dir,
+ &mut |pattern_bytes| hasher.update(pattern_bytes),
+ )?;
+ let new_hash = *hasher.finalize().as_ref();
+ let changed = new_hash != dmap.ignore_patterns_hash;
+ dmap.ignore_patterns_hash = new_hash;
+ (ignore_fn, warnings, Some(changed))
+ }
+ };
+ (ignore_fn, warnings, changed)
} else {
(Box::new(|&_| true), vec![], None)
};
@@ -135,7 +149,8 @@
outcome.dirty = common.ignore_patterns_have_changed == Some(true)
|| !outdated.is_empty()
- || !new_cachable.is_empty();
+ || (!new_cachable.is_empty()
+ && dmap.dirstate_version == DirstateVersion::V2);
// Remove outdated mtimes before adding new mtimes, in case a given
// directory is both