changeset 49555:8ee3889bab92 stable

rust-status: save new dircache even if just invalidated There was a functional race between invalidating the cache (not acted upon until the end of the status algorithm) and populating the new cache (which relies upon an up-to-date version of the cache). We simply inform the cache populating function that we've just invalidated the cache for this particular directory since the information is present in the same scope.
author Raphaël Gomès <rgomes@octobus.net>
date Wed, 19 Oct 2022 16:28:41 +0200
parents ecf9788cd9c4
children 9172bd49cedc
files rust/hg-core/src/dirstate_tree/status.rs tests/test-status.t
diffstat 2 files changed, 22 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-core/src/dirstate_tree/status.rs	Wed Oct 19 15:11:05 2022 +0200
+++ b/rust/hg-core/src/dirstate_tree/status.rs	Wed Oct 19 16:28:41 2022 +0200
@@ -303,7 +303,7 @@
     fn check_for_outdated_directory_cache(
         &self,
         dirstate_node: &NodeRef<'tree, 'on_disk>,
-    ) -> Result<(), DirstateV2ParseError> {
+    ) -> Result<bool, DirstateV2ParseError> {
         if self.ignore_patterns_have_changed == Some(true)
             && dirstate_node.cached_directory_mtime()?.is_some()
         {
@@ -311,9 +311,10 @@
                 dirstate_node
                     .full_path_borrowed(self.dmap.on_disk)?
                     .detach_from_tree(),
-            )
+            );
+            return Ok(true);
         }
-        Ok(())
+        Ok(false)
     }
 
     /// If this returns true, we can get accurate results by only using
@@ -473,7 +474,8 @@
         dirstate_node: NodeRef<'tree, 'on_disk>,
         has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>,
     ) -> Result<(), DirstateV2ParseError> {
-        self.check_for_outdated_directory_cache(&dirstate_node)?;
+        let outdated_dircache =
+            self.check_for_outdated_directory_cache(&dirstate_node)?;
         let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?;
         let file_type = fs_metadata.file_type();
         let file_or_symlink = file_type.is_file() || file_type.is_symlink();
@@ -510,6 +512,7 @@
                 children_all_have_dirstate_node_or_are_ignored,
                 fs_metadata,
                 dirstate_node,
+                outdated_dircache,
             )?
         } else {
             if file_or_symlink && self.matcher.matches(&hg_path) {
@@ -549,11 +552,17 @@
         Ok(())
     }
 
+    /// Save directory mtime if applicable.
+    ///
+    /// `outdated_directory_cache` is `true` if we've just invalidated the
+    /// cache for this directory in `check_for_outdated_directory_cache`,
+    /// which forces the update.
     fn maybe_save_directory_mtime(
         &self,
         children_all_have_dirstate_node_or_are_ignored: bool,
         directory_metadata: &std::fs::Metadata,
         dirstate_node: NodeRef<'tree, 'on_disk>,
+        outdated_directory_cache: bool,
     ) -> Result<(), DirstateV2ParseError> {
         if !children_all_have_dirstate_node_or_are_ignored {
             return Ok(());
@@ -621,12 +630,13 @@
         // We deem this scenario (unlike the previous one) to be
         // unlikely enough in practice.
 
-        let is_up_to_date =
-            if let Some(cached) = dirstate_node.cached_directory_mtime()? {
-                cached.likely_equal(directory_mtime)
-            } else {
-                false
-            };
+        let is_up_to_date = if let Some(cached) =
+            dirstate_node.cached_directory_mtime()?
+        {
+            !outdated_directory_cache && cached.likely_equal(directory_mtime)
+        } else {
+            false
+        };
         if !is_up_to_date {
             let hg_path = dirstate_node
                 .full_path_borrowed(self.dmap.on_disk)?
--- a/tests/test-status.t	Wed Oct 19 15:11:05 2022 +0200
+++ b/tests/test-status.t	Wed Oct 19 16:28:41 2022 +0200
@@ -993,16 +993,8 @@
   $ hg status
   ? another-subdir/something-else
 
-  $ hg debugdirstate --all --no-dates | grep '^ '
-      0         -1 unset               subdir (known-bad-output !)
-
-For some reason the first [status] is not enough to save the updated
-directory mtime into the cache. The second invocation does it.
-The first call only clears the directory cache by marking the directories
-as "outdated", which seems like a bug.
-
-  $ hg status
-  ? another-subdir/something-else
+One invocation of status is enough to populate the cache even if it's invalidated
+in the same run.
 
   $ hg debugdirstate --all --no-dates | grep '^ '
       0         -1 set                 subdir