Mercurial > hg
diff rust/hg-core/src/dirstate_tree/dirstate_map.rs @ 47348:a4de570e61fa
dirstate-v2: Allow tree nodes without an entry to store a timestamp
Timestamps are stored on 96 bits:
* 64 bits for the signed number of seconds since the Unix epoch
* 32 bits for the nanoseconds in the `0 <= ns < 1_000_000_000` range
For now timestamps are not used or set yet.
Differential Revision: https://phab.mercurial-scm.org/D10825
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Thu, 27 May 2021 18:40:54 +0200 |
parents | 73ddcedeaadf |
children | 7138c863d0a1 |
line wrap: on
line diff
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Fri May 28 20:07:27 2021 +0200 +++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Thu May 27 18:40:54 2021 +0200 @@ -295,18 +295,13 @@ } } - pub(super) fn has_entry(&self) -> bool { - match self { - NodeRef::InMemory(_path, node) => node.entry.is_some(), - NodeRef::OnDisk(node) => node.has_entry(), - } - } - pub(super) fn entry( &self, ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { match self { - NodeRef::InMemory(_path, node) => Ok(node.entry), + NodeRef::InMemory(_path, node) => { + Ok(node.data.as_entry().copied()) + } NodeRef::OnDisk(node) => node.entry(), } } @@ -316,7 +311,7 @@ ) -> Result<Option<EntryState>, DirstateV2ParseError> { match self { NodeRef::InMemory(_path, node) => { - Ok(node.entry.as_ref().map(|entry| entry.state)) + Ok(node.data.as_entry().map(|entry| entry.state)) } NodeRef::OnDisk(node) => node.state(), } @@ -333,8 +328,7 @@ /// Represents a file or a directory #[derive(Default)] pub(super) struct Node<'on_disk> { - /// `None` for directories - pub(super) entry: Option<DirstateEntry>, + pub(super) data: NodeData, pub(super) copy_source: Option<Cow<'on_disk, HgPath>>, @@ -344,6 +338,34 @@ pub(super) tracked_descendants_count: u32, } +pub(super) enum NodeData { + Entry(DirstateEntry), + CachedDirectory { mtime: on_disk::Timestamp }, + None, +} + +impl Default for NodeData { + fn default() -> Self { + NodeData::None + } +} + +impl NodeData { + fn has_entry(&self) -> bool { + match self { + NodeData::Entry(_) => true, + _ => false, + } + } + + fn as_entry(&self) -> Option<&DirstateEntry> { + match self { + NodeData::Entry(entry) => Some(entry), + _ => None, + } + } +} + impl<'on_disk> DirstateMap<'on_disk> { pub(super) fn empty(on_disk: &'on_disk [u8]) -> Self { Self { @@ -386,14 +408,14 @@ }, )?; assert!( - node.entry.is_none(), + !node.data.has_entry(), "duplicate dirstate entry in read" ); assert!( node.copy_source.is_none(), "duplicate dirstate entry in read" ); - node.entry = Some(*entry); + node.data = NodeData::Entry(*entry); node.copy_source = copy_source.map(Cow::Borrowed); map.nodes_with_entry_count += 1; if copy_source.is_some() { @@ -519,10 +541,10 @@ } }, )?; - if node.entry.is_none() { + if !node.data.has_entry() { self.nodes_with_entry_count += 1 } - node.entry = Some(new_entry); + node.data = NodeData::Entry(new_entry); Ok(()) } @@ -587,7 +609,7 @@ &mut self.root, path.as_ref(), )? { - if let Some(entry) = node.entry.as_mut() { + if let NodeData::Entry(entry) = &mut node.data { entry.clear_mtime(); } } @@ -703,18 +725,22 @@ return Ok(None); } } else { + let had_entry = node.data.has_entry(); + if had_entry { + node.data = NodeData::None + } dropped = Dropped { was_tracked: node - .entry - .as_ref() + .data + .as_entry() .map_or(false, |entry| entry.state.is_tracked()), - had_entry: node.entry.take().is_some(), + had_entry, had_copy_source: node.copy_source.take().is_some(), }; } // After recursion, for both leaf (rest_of_path is None) nodes and // parent nodes, remove a node if it just became empty. - if node.entry.is_none() + if !node.data.has_entry() && node.copy_source.is_none() && node.children.is_empty() { @@ -746,7 +772,7 @@ if let Some(node) = Self::get_node_mut(self.on_disk, &mut self.root, &filename)? { - if let Some(entry) = node.entry.as_mut() { + if let NodeData::Entry(entry) = &mut node.data { entry.clear_ambiguous_mtime(now); } } @@ -815,7 +841,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.has_entry() && node.tracked_descendants_count() > 0) + let state = node.state()?; + Ok(state.is_none() && node.tracked_descendants_count() > 0) } else { Ok(false) } @@ -825,7 +852,7 @@ 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.has_entry()) + Ok(node.state()?.is_none()) } else { Ok(false) }