changeset 50221:1891086f6c7f stable

dirstate: use more than a bool to control append behavior When writing dirstate-v2, we might either append to the existing file, or create a new file. We are about to introduce some configuration to control this behavior. As a prelude, we change the current way the behavior was automatically controlled to make the change smaller/clearer.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Fri, 24 Feb 2023 18:21:54 +0100
parents 35ea3c139104
children ecd28d89c29e
files mercurial/dirstatemap.py rust/hg-core/src/dirstate_tree/dirstate_map.rs rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-core/src/repo.rs rust/hg-cpython/src/dirstate/dirstate_map.rs
diffstat 5 files changed, 40 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dirstatemap.py	Fri Feb 24 01:15:45 2023 +0100
+++ b/mercurial/dirstatemap.py	Fri Feb 24 18:21:54 2023 +0100
@@ -31,6 +31,9 @@
 
 rangemask = 0x7FFFFFFF
 
+WRITE_MODE_AUTO = 0
+WRITE_MODE_FORCE_NEW = 1
+
 
 class _dirstatemapcommon:
     """
@@ -609,8 +612,10 @@
                 return
 
             # We can only append to an existing data file if there is one
-            can_append = self.docket.uuid is not None
-            packed, meta, append = self._map.write_v2(can_append)
+            write_mode = WRITE_MODE_AUTO
+            if self.docket.uuid is None:
+                write_mode = WRITE_MODE_FORCE_NEW
+            packed, meta, append = self._map.write_v2(write_mode)
             if append:
                 docket = self.docket
                 data_filename = docket.data_filename()
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Fri Feb 24 01:15:45 2023 +0100
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Fri Feb 24 18:21:54 2023 +0100
@@ -38,6 +38,12 @@
     V2,
 }
 
+#[derive(Debug, PartialEq, Eq)]
+pub enum DirstateMapWriteMode {
+    Auto,
+    ForceNewDataFile,
+}
+
 #[derive(Debug)]
 pub struct DirstateMap<'on_disk> {
     /// Contents of the `.hg/dirstate` file
@@ -1251,11 +1257,11 @@
     #[timed]
     pub fn pack_v2(
         &self,
-        can_append: bool,
+        write_mode: DirstateMapWriteMode,
     ) -> Result<(Vec<u8>, on_disk::TreeMetadata, bool, usize), DirstateError>
     {
         let map = self.get_map();
-        on_disk::write(map, can_append)
+        on_disk::write(map, write_mode)
     }
 
     /// `callback` allows the caller to process and do something with the
@@ -1812,7 +1818,7 @@
         )?;
 
         let (packed, metadata, _should_append, _old_data_size) =
-            map.pack_v2(false)?;
+            map.pack_v2(DirstateMapWriteMode::ForceNewDataFile)?;
         let packed_len = packed.len();
         assert!(packed_len > 0);
 
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs	Fri Feb 24 01:15:45 2023 +0100
+++ b/rust/hg-core/src/dirstate_tree/on_disk.rs	Fri Feb 24 18:21:54 2023 +0100
@@ -4,7 +4,9 @@
 
 use crate::dirstate::{DirstateV2Data, TruncatedTimestamp};
 use crate::dirstate_tree::dirstate_map::DirstateVersion;
-use crate::dirstate_tree::dirstate_map::{self, DirstateMap, NodeRef};
+use crate::dirstate_tree::dirstate_map::{
+    self, DirstateMap, DirstateMapWriteMode, NodeRef,
+};
 use crate::dirstate_tree::path_with_basename::WithBasename;
 use crate::errors::HgError;
 use crate::utils::hg_path::HgPath;
@@ -634,9 +636,12 @@
 /// (false), and the previous size of data on disk.
 pub(super) fn write(
     dirstate_map: &DirstateMap,
-    can_append: bool,
+    write_mode: DirstateMapWriteMode,
 ) -> Result<(Vec<u8>, TreeMetadata, bool, usize), DirstateError> {
-    let append = can_append && dirstate_map.write_should_append();
+    let append = match write_mode {
+        DirstateMapWriteMode::Auto => dirstate_map.write_should_append(),
+        DirstateMapWriteMode::ForceNewDataFile => false,
+    };
     if append {
         log::trace!("appending to the dirstate data file");
     } else {
--- a/rust/hg-core/src/repo.rs	Fri Feb 24 01:15:45 2023 +0100
+++ b/rust/hg-core/src/repo.rs	Fri Feb 24 18:21:54 2023 +0100
@@ -1,6 +1,7 @@
 use crate::changelog::Changelog;
 use crate::config::{Config, ConfigError, ConfigParseError};
 use crate::dirstate::DirstateParents;
+use crate::dirstate_tree::dirstate_map::DirstateMapWriteMode;
 use crate::dirstate_tree::on_disk::Docket as DirstateDocket;
 use crate::dirstate_tree::owning::OwningDirstateMap;
 use crate::errors::HgResultExt;
@@ -436,9 +437,13 @@
                 .dirstate_data_file_uuid
                 .get_or_init(|| self.read_dirstate_data_file_uuid())?;
             let uuid_opt = uuid_opt.as_ref();
-            let can_append = uuid_opt.is_some();
+            let write_mode = if uuid_opt.is_some() {
+                DirstateMapWriteMode::Auto
+            } else {
+                DirstateMapWriteMode::ForceNewDataFile
+            };
             let (data, tree_metadata, append, old_data_size) =
-                map.pack_v2(can_append)?;
+                map.pack_v2(write_mode)?;
 
             // Reuse the uuid, or generate a new one, keeping the old for
             // deletion.
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs	Fri Feb 24 01:15:45 2023 +0100
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs	Fri Feb 24 18:21:54 2023 +0100
@@ -23,7 +23,8 @@
     pybytes_deref::PyBytesDeref,
 };
 use hg::{
-    dirstate::StateMapIter, dirstate_tree::on_disk::DirstateV2ParseError,
+    dirstate::StateMapIter, dirstate_tree::dirstate_map::DirstateMapWriteMode,
+    dirstate_tree::on_disk::DirstateV2ParseError,
     dirstate_tree::owning::OwningDirstateMap, revlog::Node,
     utils::files::normalize_case, utils::hg_path::HgPath, DirstateEntry,
     DirstateError, DirstateParents,
@@ -247,10 +248,15 @@
     /// instead of written to a new data file (False).
     def write_v2(
         &self,
-        can_append: bool,
+        write_mode: usize,
     ) -> PyResult<PyObject> {
         let inner = self.inner(py).borrow();
-        let result = inner.pack_v2(can_append);
+        let rust_write_mode = match write_mode {
+            0 => DirstateMapWriteMode::Auto,
+            1 => DirstateMapWriteMode::ForceNewDataFile,
+            _ => DirstateMapWriteMode::Auto, // XXX should we error out?
+        };
+        let result = inner.pack_v2(rust_write_mode);
         match result {
             Ok((packed, tree_metadata, append, _old_data_size)) => {
                 let packed = PyBytes::new(py, &packed);