rust-nodemap: a method for full invalidation
authorGeorges Racinet <georges.racinet@octobus.net>
Tue, 18 Feb 2020 19:11:18 +0100
changeset 44421 d518994384a4
parent 44420 6329ce04c69f
child 44422 a6fb134bd086
rust-nodemap: a method for full invalidation This will be used for exceptional operations, such as a `__delitem__` on the `MixedIndex` with Rust nodemap. In principle, `NodeTree` should also be able to forget an entry in an efficient way, by accepting to insert `Element::None` instead of only `Element::Rev(r)`, but that seems really overkill at this point. We need to support exceptional operations such as `__delitem__`, only for completeness of the revlog index as seen from Python. The Python callers don't seem to even really need it, deciding to drop the nodemap unconditionally at at higher level when calling `hg strip`. Also, `hg strip` is very costly for reasons that are unrelated to nodemap aspects. Differential Revision: https://phab.mercurial-scm.org/D8098
rust/hg-core/src/revlog/nodemap.rs
--- a/rust/hg-core/src/revlog/nodemap.rs	Tue Feb 18 19:11:17 2020 +0100
+++ b/rust/hg-core/src/revlog/nodemap.rs	Tue Feb 18 19:11:18 2020 +0100
@@ -575,11 +575,25 @@
         Ok(())
     }
 
+    /// Make the whole `NodeTree` logically empty, without touching the
+    /// immutable part.
+    pub fn invalidate_all(&mut self) {
+        self.root = Block::new();
+        self.growable = Vec::new();
+        self.masked_inner_blocks = self.readonly.len();
+    }
+
     /// Return the number of blocks in the readonly part that are currently
     /// masked in the mutable part.
     ///
     /// The `NodeTree` structure has no efficient way to know how many blocks
     /// are already unreachable in the readonly part.
+    ///
+    /// After a call to `invalidate_all()`, the returned number can be actually
+    /// bigger than the whole readonly part, a conventional way to mean that
+    /// all the readonly blocks have been masked. This is what is really
+    /// useful to the caller and does not require to know how many were
+    /// actually unreachable to begin with.
     pub fn masked_readonly_blocks(&self) -> usize {
         if let Some(readonly_root) = self.readonly.last() {
             if readonly_root == &self.root {
@@ -1060,6 +1074,27 @@
     }
 
     #[test]
+    fn test_invalidate_all() -> Result<(), NodeMapError> {
+        let mut idx = TestNtIndex::new();
+        idx.insert(0, "1234")?;
+        idx.insert(1, "1235")?;
+        idx.insert(2, "131")?;
+        idx.insert(3, "cafe")?;
+        let mut idx = idx.commit();
+
+        idx.nt.invalidate_all();
+
+        assert_eq!(idx.find_hex("1234")?, None);
+        assert_eq!(idx.find_hex("1235")?, None);
+        assert_eq!(idx.find_hex("131")?, None);
+        assert_eq!(idx.find_hex("cafe")?, None);
+        // all the readonly blocks have been masked, this is the
+        // conventional expected response
+        assert_eq!(idx.nt.masked_readonly_blocks(), idx.nt.readonly.len() + 1);
+        Ok(())
+    }
+
+    #[test]
     fn test_into_added_empty() {
         assert!(sample_nodetree().into_readonly_and_added().1.is_empty());
         assert!(sample_nodetree()