--- 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
@@ -48,14 +48,17 @@
pub(super) enum ChildNodes<'on_disk> {
InMemory(FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>),
+ OnDisk(&'on_disk [on_disk::Node]),
}
pub(super) enum ChildNodesRef<'tree, 'on_disk> {
InMemory(&'tree FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>),
+ OnDisk(&'on_disk [on_disk::Node]),
}
pub(super) enum NodeRef<'tree, 'on_disk> {
InMemory(&'tree NodeKey<'on_disk>, &'tree Node<'on_disk>),
+ OnDisk(&'on_disk on_disk::Node),
}
impl Default for ChildNodes<'_> {
@@ -70,24 +73,42 @@
) -> ChildNodesRef<'tree, 'on_disk> {
match self {
ChildNodes::InMemory(nodes) => ChildNodesRef::InMemory(nodes),
+ ChildNodes::OnDisk(nodes) => ChildNodesRef::OnDisk(nodes),
}
}
pub(super) fn is_empty(&self) -> bool {
match self {
ChildNodes::InMemory(nodes) => nodes.is_empty(),
+ ChildNodes::OnDisk(nodes) => nodes.is_empty(),
}
}
pub(super) fn make_mut(
&mut self,
- _on_disk: &'on_disk [u8],
+ on_disk: &'on_disk [u8],
) -> Result<
&mut FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>,
DirstateV2ParseError,
> {
match self {
ChildNodes::InMemory(nodes) => Ok(nodes),
+ ChildNodes::OnDisk(nodes) => {
+ let nodes = nodes
+ .iter()
+ .map(|node| {
+ Ok((
+ node.path(on_disk)?,
+ node.to_in_memory_node(on_disk)?,
+ ))
+ })
+ .collect::<Result<_, _>>()?;
+ *self = ChildNodes::InMemory(nodes);
+ match self {
+ ChildNodes::InMemory(nodes) => Ok(nodes),
+ ChildNodes::OnDisk(_) => unreachable!(),
+ }
+ }
}
}
}
@@ -96,12 +117,29 @@
pub(super) fn get(
&self,
base_name: &HgPath,
- _on_disk: &'on_disk [u8],
+ on_disk: &'on_disk [u8],
) -> Result<Option<NodeRef<'tree, 'on_disk>>, DirstateV2ParseError> {
match self {
ChildNodesRef::InMemory(nodes) => Ok(nodes
.get_key_value(base_name)
.map(|(k, v)| NodeRef::InMemory(k, v))),
+ ChildNodesRef::OnDisk(nodes) => {
+ let mut parse_result = Ok(());
+ let search_result = nodes.binary_search_by(|node| {
+ match node.base_name(on_disk) {
+ Ok(node_base_name) => node_base_name.cmp(base_name),
+ Err(e) => {
+ parse_result = Err(e);
+ // Dummy comparison result, `search_result` won’t
+ // be used since `parse_result` is an error
+ std::cmp::Ordering::Equal
+ }
+ }
+ });
+ parse_result.map(|()| {
+ search_result.ok().map(|i| NodeRef::OnDisk(&nodes[i]))
+ })
+ }
}
}
@@ -110,8 +148,11 @@
&self,
) -> impl Iterator<Item = NodeRef<'tree, 'on_disk>> {
match self {
- ChildNodesRef::InMemory(nodes) => {
- nodes.iter().map(|(k, v)| NodeRef::InMemory(k, v))
+ ChildNodesRef::InMemory(nodes) => itertools::Either::Left(
+ nodes.iter().map(|(k, v)| NodeRef::InMemory(k, v)),
+ ),
+ ChildNodesRef::OnDisk(nodes) => {
+ itertools::Either::Right(nodes.iter().map(NodeRef::OnDisk))
}
}
}
@@ -123,9 +164,12 @@
{
use rayon::prelude::*;
match self {
- ChildNodesRef::InMemory(nodes) => {
- nodes.par_iter().map(|(k, v)| NodeRef::InMemory(k, v))
- }
+ ChildNodesRef::InMemory(nodes) => rayon::iter::Either::Left(
+ nodes.par_iter().map(|(k, v)| NodeRef::InMemory(k, v)),
+ ),
+ ChildNodesRef::OnDisk(nodes) => rayon::iter::Either::Right(
+ nodes.par_iter().map(NodeRef::OnDisk),
+ ),
}
}
@@ -139,6 +183,7 @@
fn sort_key<'a>(node: &'a NodeRef) -> &'a HgPath {
match node {
NodeRef::InMemory(path, _node) => path.base_name(),
+ NodeRef::OnDisk(_) => unreachable!(),
}
}
// `sort_unstable_by_key` doesn’t allow keys borrowing from the
@@ -146,6 +191,10 @@
vec.sort_unstable_by(|a, b| sort_key(a).cmp(sort_key(b)));
vec
}
+ ChildNodesRef::OnDisk(nodes) => {
+ // Nodes on disk are already sorted
+ nodes.iter().map(NodeRef::OnDisk).collect()
+ }
}
}
}
@@ -153,61 +202,72 @@
impl<'tree, 'on_disk> NodeRef<'tree, 'on_disk> {
pub(super) fn full_path(
&self,
- _on_disk: &'on_disk [u8],
+ on_disk: &'on_disk [u8],
) -> Result<&'tree HgPath, DirstateV2ParseError> {
match self {
NodeRef::InMemory(path, _node) => Ok(path.full_path()),
+ NodeRef::OnDisk(node) => node.full_path(on_disk),
}
}
/// Returns a `Cow` that can borrow 'on_disk but is detached from 'tree
pub(super) fn full_path_cow(
&self,
- _on_disk: &'on_disk [u8],
+ on_disk: &'on_disk [u8],
) -> Result<Cow<'on_disk, HgPath>, DirstateV2ParseError> {
match self {
NodeRef::InMemory(path, _node) => Ok(path.full_path().clone()),
+ NodeRef::OnDisk(node) => {
+ Ok(Cow::Borrowed(node.full_path(on_disk)?))
+ }
}
}
pub(super) fn base_name(
&self,
- _on_disk: &'on_disk [u8],
+ on_disk: &'on_disk [u8],
) -> Result<&'tree HgPath, DirstateV2ParseError> {
match self {
NodeRef::InMemory(path, _node) => Ok(path.base_name()),
+ NodeRef::OnDisk(node) => node.base_name(on_disk),
}
}
pub(super) fn children(
&self,
- _on_disk: &'on_disk [u8],
+ on_disk: &'on_disk [u8],
) -> Result<ChildNodesRef<'tree, 'on_disk>, DirstateV2ParseError> {
match self {
NodeRef::InMemory(_path, node) => Ok(node.children.as_ref()),
+ NodeRef::OnDisk(node) => {
+ Ok(ChildNodesRef::OnDisk(node.children(on_disk)?))
+ }
}
}
pub(super) fn has_copy_source(&self) -> bool {
match self {
NodeRef::InMemory(_path, node) => node.copy_source.is_some(),
+ NodeRef::OnDisk(node) => node.has_copy_source(),
}
}
pub(super) fn copy_source(
&self,
- _on_disk: &'on_disk [u8],
+ on_disk: &'on_disk [u8],
) -> Result<Option<&'tree HgPath>, DirstateV2ParseError> {
match self {
NodeRef::InMemory(_path, node) => {
Ok(node.copy_source.as_ref().map(|s| &**s))
}
+ NodeRef::OnDisk(node) => node.copy_source(on_disk),
}
}
pub(super) fn has_entry(&self) -> bool {
match self {
NodeRef::InMemory(_path, node) => node.entry.is_some(),
+ NodeRef::OnDisk(node) => node.has_entry(),
}
}
@@ -216,6 +276,7 @@
) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
match self {
NodeRef::InMemory(_path, node) => Ok(node.entry),
+ NodeRef::OnDisk(node) => node.entry(),
}
}
@@ -226,12 +287,14 @@
NodeRef::InMemory(_path, node) => {
Ok(node.entry.as_ref().map(|entry| entry.state))
}
+ NodeRef::OnDisk(node) => node.state(),
}
}
pub(super) fn tracked_descendants_count(&self) -> u32 {
match self {
NodeRef::InMemory(_path, node) => node.tracked_descendants_count,
+ NodeRef::OnDisk(node) => node.tracked_descendants_count.get(),
}
}
}