rust/hg-core/src/dirstate_tree/dirstate_map.rs
changeset 47478 ca8121d26732
parent 47477 eb416759af7e
child 47511 eaae39894312
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Mon Jun 28 15:52:10 2021 +0200
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Mon Jun 28 16:50:19 2021 +0200
@@ -332,6 +332,15 @@
         }
     }
 
+    pub(super) fn descendants_with_entry_count(&self) -> u32 {
+        match self {
+            NodeRef::InMemory(_path, node) => {
+                node.descendants_with_entry_count
+            }
+            NodeRef::OnDisk(node) => node.descendants_with_entry_count.get(),
+        }
+    }
+
     pub(super) fn tracked_descendants_count(&self) -> u32 {
         match self {
             NodeRef::InMemory(_path, node) => node.tracked_descendants_count,
@@ -349,7 +358,11 @@
 
     pub(super) children: ChildNodes<'on_disk>,
 
-    /// How many (non-inclusive) descendants of this node are tracked files
+    /// How many (non-inclusive) descendants of this node have an entry.
+    pub(super) descendants_with_entry_count: u32,
+
+    /// How many (non-inclusive) descendants of this node have an entry whose
+    /// state is "tracked".
     pub(super) tracked_descendants_count: u32,
 }
 
@@ -421,6 +434,7 @@
                         if tracked {
                             ancestor.tracked_descendants_count += 1
                         }
+                        ancestor.descendants_with_entry_count += 1
                     },
                 )?;
                 assert!(
@@ -547,6 +561,7 @@
         old_state: EntryState,
         new_entry: DirstateEntry,
     ) -> Result<(), DirstateV2ParseError> {
+        let had_entry = old_state != EntryState::Unknown;
         let tracked_count_increment =
             match (old_state.is_tracked(), new_entry.state.is_tracked()) {
                 (false, true) => 1,
@@ -560,6 +575,10 @@
             path,
             WithBasename::to_cow_owned,
             |ancestor| {
+                if !had_entry {
+                    ancestor.descendants_with_entry_count += 1;
+                }
+
                 // We can’t use `+= increment` because the counter is unsigned,
                 // and we want debug builds to detect accidental underflow
                 // through zero
@@ -570,7 +589,7 @@
                 }
             },
         )?;
-        if !node.data.has_entry() {
+        if !had_entry {
             self.nodes_with_entry_count += 1
         }
         node.data = NodeData::Entry(new_entry);
@@ -755,6 +774,9 @@
                     recur(on_disk, &mut node.children, rest)?
                 {
                     dropped = d;
+                    if dropped.had_entry {
+                        node.descendants_with_entry_count -= 1;
+                    }
                     if dropped.was_tracked {
                         node.tracked_descendants_count -= 1;
                     }
@@ -899,7 +921,8 @@
         if let Some(node) = self.get_node(directory)? {
             // A node without a `DirstateEntry` was created to hold child
             // nodes, and is therefore a directory.
-            Ok(node.state()?.is_none())
+            let state = node.state()?;
+            Ok(state.is_none() && node.descendants_with_entry_count() > 0)
         } else {
             Ok(false)
         }