Patchwork D10492: dirstate-tree: Add "non normal" and "from other parent" sets

login
register
mail settings
Submitter phabricator
Date April 20, 2021, 2:19 p.m.
Message ID <differential-rev-PHID-DREV-exwer3av5t5mxbrxnmrq-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/48810/
State Superseded
Headers show

Comments

phabricator - April 20, 2021, 2:19 p.m.
SimonSapin created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Unlike the other DirstateMap implementation, these sets are not materialized
  separately in memory. Instead we traverse the main tree.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D10492

AFFECTED FILES
  rust/hg-core/src/dirstate.rs
  rust/hg-core/src/dirstate/dirstate_map.rs
  rust/hg-core/src/dirstate_tree/dirstate_map.rs
  rust/hg-core/src/dirstate_tree/dispatch.rs

CHANGE DETAILS




To: SimonSapin, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/rust/hg-core/src/dirstate_tree/dispatch.rs b/rust/hg-core/src/dirstate_tree/dispatch.rs
--- a/rust/hg-core/src/dirstate_tree/dispatch.rs
+++ b/rust/hg-core/src/dirstate_tree/dispatch.rs
@@ -45,7 +45,7 @@ 
 
     fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool;
 
-    fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool;
+    fn non_normal_entries_remove(&mut self, key: &HgPath);
 
     fn non_normal_or_other_parent_paths(
         &mut self,
@@ -179,7 +179,7 @@ 
         non_normal.contains(key)
     }
 
-    fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool {
+    fn non_normal_entries_remove(&mut self, key: &HgPath) {
         self.non_normal_entries_remove(key)
     }
 
diff --git a/rust/hg-core/src/dirstate_tree/dirstate_map.rs b/rust/hg-core/src/dirstate_tree/dirstate_map.rs
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs
@@ -398,40 +398,61 @@ 
         }
     }
 
-    fn non_normal_entries_contains(&mut self, _key: &HgPath) -> bool {
-        todo!()
+    fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
+        self.get_node(key)
+            .and_then(|node| node.entry.as_ref())
+            .map_or(false, DirstateEntry::is_non_normal)
     }
 
-    fn non_normal_entries_remove(&mut self, _key: &HgPath) -> bool {
-        todo!()
+    fn non_normal_entries_remove(&mut self, _key: &HgPath) {
+        // Do nothing, this `DirstateMap` does not have a separate "non normal
+        // entries" set that need to be kept up to date
     }
 
     fn non_normal_or_other_parent_paths(
         &mut self,
     ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
-        todo!()
+        Box::new(self.iter_nodes().filter_map(|(path, node)| {
+            node.entry
+                .as_ref()
+                .filter(|entry| {
+                    entry.is_non_normal() || entry.is_from_other_parent()
+                })
+                .map(|_| path.full_path())
+        }))
     }
 
     fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
-        todo!()
+        // Do nothing, this `DirstateMap` does not have a separate "non normal
+        // entries" and "from other parent" sets that need to be recomputed
     }
 
     fn iter_non_normal_paths(
         &mut self,
     ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
-        todo!()
+        self.iter_non_normal_paths_panic()
     }
 
     fn iter_non_normal_paths_panic(
         &self,
     ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
-        todo!()
+        Box::new(self.iter_nodes().filter_map(|(path, node)| {
+            node.entry
+                .as_ref()
+                .filter(|entry| entry.is_non_normal())
+                .map(|_| path.full_path())
+        }))
     }
 
     fn iter_other_parent_paths(
         &mut self,
     ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
-        todo!()
+        Box::new(self.iter_nodes().filter_map(|(path, node)| {
+            node.entry
+                .as_ref()
+                .filter(|entry| entry.is_from_other_parent())
+                .map(|_| path.full_path())
+        }))
     }
 
     fn has_tracked_dir(
diff --git a/rust/hg-core/src/dirstate/dirstate_map.rs b/rust/hg-core/src/dirstate/dirstate_map.rs
--- a/rust/hg-core/src/dirstate/dirstate_map.rs
+++ b/rust/hg-core/src/dirstate/dirstate_map.rs
@@ -10,7 +10,7 @@ 
 use crate::errors::HgError;
 use crate::revlog::node::NULL_NODE;
 use crate::{
-    dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
+    dirstate::{parsers::PARENT_SIZE, EntryState},
     pack_dirstate, parse_dirstate,
     utils::{
         files::normalize_case,
@@ -27,8 +27,6 @@ 
 
 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
 
-const MTIME_UNSET: i32 = -1;
-
 #[derive(Default)]
 pub struct DirstateMap {
     state_map: StateMap,
@@ -99,13 +97,13 @@ 
         }
         self.state_map.insert(filename.to_owned(), entry.to_owned());
 
-        if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
+        if entry.is_non_normal() {
             self.get_non_normal_other_parent_entries()
                 .0
                 .insert(filename.to_owned());
         }
 
-        if entry.size == SIZE_FROM_OTHER_PARENT {
+        if entry.is_from_other_parent() {
             self.get_non_normal_other_parent_entries()
                 .1
                 .insert(filename.to_owned());
@@ -199,14 +197,12 @@ 
         }
     }
 
-    pub fn non_normal_entries_remove(
-        &mut self,
-        key: impl AsRef<HgPath>,
-    ) -> bool {
+    pub fn non_normal_entries_remove(&mut self, key: impl AsRef<HgPath>) {
         self.get_non_normal_other_parent_entries()
             .0
-            .remove(key.as_ref())
+            .remove(key.as_ref());
     }
+
     pub fn non_normal_entries_union(
         &mut self,
         other: HashSet<HgPathBuf>,
@@ -257,18 +253,11 @@ 
         let mut non_normal = HashSet::new();
         let mut other_parent = HashSet::new();
 
-        for (
-            filename,
-            DirstateEntry {
-                state, size, mtime, ..
-            },
-        ) in self.state_map.iter()
-        {
-            if *state != EntryState::Normal || *mtime == MTIME_UNSET {
+        for (filename, entry) in self.state_map.iter() {
+            if entry.is_non_normal() {
                 non_normal.insert(filename.to_owned());
             }
-            if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
-            {
+            if entry.is_from_other_parent() {
                 other_parent.insert(filename.to_owned());
             }
         }
diff --git a/rust/hg-core/src/dirstate.rs b/rust/hg-core/src/dirstate.rs
--- a/rust/hg-core/src/dirstate.rs
+++ b/rust/hg-core/src/dirstate.rs
@@ -34,6 +34,16 @@ 
     pub size: i32,
 }
 
+impl DirstateEntry {
+    pub fn is_non_normal(&self) -> bool {
+        self.state != EntryState::Normal || self.mtime == MTIME_UNSET
+    }
+
+    pub fn is_from_other_parent(&self) -> bool {
+        self.state == EntryState::Normal && self.size == SIZE_FROM_OTHER_PARENT
+    }
+}
+
 #[derive(BytesCast)]
 #[repr(C)]
 struct RawEntry {
@@ -44,6 +54,8 @@ 
     length: unaligned::I32Be,
 }
 
+const MTIME_UNSET: i32 = -1;
+
 /// A `DirstateEntry` with a size of `-2` means that it was merged from the
 /// other parent. This allows revert to pick the right status back during a
 /// merge.