Mercurial > hg
diff rust/hg-core/src/dirstate_tree/dirstate_map.rs @ 47280:1766130fe9ba
dirstate-v2: Change the on-disk format when the requirement is enabled
For now, the format is the same except with an additional marker at the start.
This marker is redundant: for existing repositories it is `.hg/requires` that
determines which format to use. For new repositories, it is the new
`format.exp-dirstate-v2` config. There is no upgrade or downgrade so far.
Most of the changes are about plumbing a boolean through layers of APIs to
indicate which format should be used.
Differential Revision: https://phab.mercurial-scm.org/D10719
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Wed, 19 May 2021 13:15:00 +0200 |
parents | 47ccab19bf9f |
children | ce41ee53263f |
line wrap: on
line diff
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Wed May 19 13:15:00 2021 +0200 +++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Wed May 19 13:15:00 2021 +0200 @@ -4,14 +4,17 @@ use std::convert::TryInto; use std::path::PathBuf; +use super::on_disk::V2_FORMAT_MARKER; use super::path_with_basename::WithBasename; use crate::dirstate::parsers::clear_ambiguous_mtime; use crate::dirstate::parsers::pack_entry; use crate::dirstate::parsers::packed_entry_size; use crate::dirstate::parsers::parse_dirstate_entries; use crate::dirstate::parsers::Timestamp; +use crate::errors::HgError; use crate::matchers::Matcher; use crate::utils::hg_path::{HgPath, HgPathBuf}; +use crate::utils::SliceExt; use crate::CopyMapIter; use crate::DirstateEntry; use crate::DirstateError; @@ -75,7 +78,24 @@ ); impl<'on_disk> DirstateMap<'on_disk> { - pub fn new( + #[timed] + pub fn new_v2( + on_disk: &'on_disk [u8], + ) -> Result<(Self, Option<DirstateParents>), DirstateError> { + if let Some(rest) = on_disk.drop_prefix(V2_FORMAT_MARKER) { + Self::new_v1(rest) + } else if on_disk.is_empty() { + Self::new_v1(on_disk) + } else { + return Err(HgError::corrupted( + "missing dirstate-v2 magic number", + ) + .into()); + } + } + + #[timed] + pub fn new_v1( on_disk: &'on_disk [u8], ) -> Result<(Self, Option<DirstateParents>), DirstateError> { let mut map = Self { @@ -84,23 +104,16 @@ nodes_with_entry_count: 0, nodes_with_copy_source_count: 0, }; - let parents = map.read()?; - Ok((map, parents)) - } - - /// Should only be called in `new` - #[timed] - fn read(&mut self) -> Result<Option<DirstateParents>, DirstateError> { - if self.on_disk.is_empty() { - return Ok(None); + if map.on_disk.is_empty() { + return Ok((map, None)); } let parents = parse_dirstate_entries( - self.on_disk, + map.on_disk, |path, entry, copy_source| { let tracked = entry.state.is_tracked(); let node = Self::get_or_insert_node( - &mut self.root, + &mut map.root, path, WithBasename::to_cow_borrowed, |ancestor| { @@ -119,14 +132,15 @@ ); node.entry = Some(*entry); node.copy_source = copy_source.map(Cow::Borrowed); - self.nodes_with_entry_count += 1; + map.nodes_with_entry_count += 1; if copy_source.is_some() { - self.nodes_with_copy_source_count += 1 + map.nodes_with_copy_source_count += 1 } }, )?; + let parents = Some(parents.clone()); - Ok(Some(parents.clone())) + Ok((map, parents)) } fn get_node(&self, path: &HgPath) -> Option<&Node> { @@ -498,7 +512,8 @@ } } - fn pack( + #[timed] + fn pack_v1( &mut self, parents: DirstateParents, now: Timestamp, @@ -533,6 +548,18 @@ Ok(packed) } + #[timed] + fn pack_v2( + &mut self, + parents: DirstateParents, + now: Timestamp, + ) -> Result<Vec<u8>, DirstateError> { + // Inefficient but temporary + let mut v2 = V2_FORMAT_MARKER.to_vec(); + v2.append(&mut self.pack_v1(parents, now)?); + Ok(v2) + } + fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> { // Do nothing, this `DirstateMap` does not a separate `all_dirs` that // needs to be recomputed