From 234147239a8c9469917de3add51f86670b82b34f Mon Sep 17 00:00:00 2001 From: Jun Wu Date: Wed, 3 Jun 2020 13:20:11 -0700 Subject: [PATCH] dag: add ToIdSet trait Summary: The trait converts NameSet to IdSet. It'll be used by the revlog index. Reviewed By: sfilipco Differential Revision: D21795869 fbshipit-source-id: 55f7a238158442db9d8bdfe84e64438be504f618 --- eden/scm/lib/dag/src/namedag.rs | 70 +++++++++++---------------------- eden/scm/lib/dag/src/ops.rs | 44 +++++++++++++++++++++ 2 files changed, 68 insertions(+), 46 deletions(-) diff --git a/eden/scm/lib/dag/src/namedag.rs b/eden/scm/lib/dag/src/namedag.rs index ccba50524d..0b832d8877 100644 --- a/eden/scm/lib/dag/src/namedag.rs +++ b/eden/scm/lib/dag/src/namedag.rs @@ -31,7 +31,9 @@ use crate::ops::DagAddHeads; use crate::ops::DagAlgorithm; use crate::ops::DagPersistent; use crate::ops::IdConvert; +use crate::ops::IdMapEq; use crate::ops::PrefixLookup; +use crate::ops::ToIdSet; use crate::spanset::SpanSet; use anyhow::{anyhow, bail, ensure, Result}; use indexedlog::multi; @@ -356,7 +358,7 @@ impl DagAlgorithm for T { /// Calculates all ancestors reachable from any name from the given set. fn ancestors(&self, set: NameSet) -> Result { - let spans = self.dag().ancestors(self.to_span_set(&set)?)?; + let spans = self.dag().ancestors(self.to_id_set(&set)?)?; Ok(NameSet::from_spans_idmap(spans, self.clone_map())) } @@ -365,7 +367,7 @@ impl DagAlgorithm for T { /// Note: Parent order is not preserved. Use [`NameDag::parent_names`] /// to preserve order. fn parents(&self, set: NameSet) -> Result { - let spans = self.dag().parents(self.to_span_set(&set)?)?; + let spans = self.dag().parents(self.to_id_set(&set)?)?; let result = NameSet::from_spans_idmap(spans, self.clone_map()); #[cfg(test)] { @@ -391,7 +393,7 @@ impl DagAlgorithm for T { /// Calculates heads of the given set. fn heads(&self, set: NameSet) -> Result { - let spans = self.dag().heads(self.to_span_set(&set)?)?; + let spans = self.dag().heads(self.to_id_set(&set)?)?; let result = NameSet::from_spans_idmap(spans, self.clone_map()); #[cfg(test)] { @@ -402,13 +404,13 @@ impl DagAlgorithm for T { /// Calculates children of the given set. fn children(&self, set: NameSet) -> Result { - let spans = self.dag().children(self.to_span_set(&set)?)?; + let spans = self.dag().children(self.to_id_set(&set)?)?; Ok(NameSet::from_spans_idmap(spans, self.clone_map())) } /// Calculates roots of the given set. fn roots(&self, set: NameSet) -> Result { - let spans = self.dag().roots(self.to_span_set(&set)?)?; + let spans = self.dag().roots(self.to_id_set(&set)?)?; let result = NameSet::from_spans_idmap(spans, self.clone_map()); #[cfg(test)] { @@ -423,7 +425,7 @@ impl DagAlgorithm for T { /// If there are multiple greatest common ancestors, pick one arbitrarily. /// Use `gca_all` to get all of them. fn gca_one(&self, set: NameSet) -> Result> { - let result: Option = match self.dag().gca_one(self.to_span_set(&set)?)? { + let result: Option = match self.dag().gca_one(self.to_id_set(&set)?)? { None => None, Some(id) => Some(self.map().vertex_name(id)?), }; @@ -437,7 +439,7 @@ impl DagAlgorithm for T { /// Calculates all "greatest common ancestor"s of the given set. /// `gca_one` is faster if an arbitrary answer is ok. fn gca_all(&self, set: NameSet) -> Result { - let spans = self.dag().gca_all(self.to_span_set(&set)?)?; + let spans = self.dag().gca_all(self.to_id_set(&set)?)?; let result = NameSet::from_spans_idmap(spans, self.clone_map()); #[cfg(test)] { @@ -448,7 +450,7 @@ impl DagAlgorithm for T { /// Calculates all common ancestors of the given set. fn common_ancestors(&self, set: NameSet) -> Result { - let spans = self.dag().common_ancestors(self.to_span_set(&set)?)?; + let spans = self.dag().common_ancestors(self.to_id_set(&set)?)?; let result = NameSet::from_spans_idmap(spans, self.clone_map()); #[cfg(test)] { @@ -481,7 +483,7 @@ impl DagAlgorithm for T { /// an ancestor of X, but not the immediate ancestor, `heads` will include /// Y while this function won't. fn heads_ancestors(&self, set: NameSet) -> Result { - let spans = self.dag().heads_ancestors(self.to_span_set(&set)?)?; + let spans = self.dag().heads_ancestors(self.to_id_set(&set)?)?; let result = NameSet::from_spans_idmap(spans, self.clone_map()); #[cfg(test)] { @@ -492,46 +494,19 @@ impl DagAlgorithm for T { /// Calculates the "dag range" - vertexes reachable from both sides. fn range(&self, roots: NameSet, heads: NameSet) -> Result { - let roots = self.to_span_set(&roots)?; - let heads = self.to_span_set(&heads)?; + let roots = self.to_id_set(&roots)?; + let heads = self.to_id_set(&heads)?; let spans = self.dag().range(roots, heads)?; Ok(NameSet::from_spans_idmap(spans, self.clone_map())) } /// Calculates the descendants of the given set. fn descendants(&self, set: NameSet) -> Result { - let spans = self.dag().descendants(self.to_span_set(&set)?)?; + let spans = self.dag().descendants(self.to_id_set(&set)?)?; Ok(NameSet::from_spans_idmap(spans, self.clone_map())) } } -pub trait ToSpanSet { - /// Converts [`NameSet`] to [`SpanSet`]. - fn to_span_set(&self, set: &NameSet) -> Result; -} - -impl ToSpanSet for T { - /// Converts [`NameSet`] to [`SpanSet`]. - fn to_span_set(&self, set: &NameSet) -> Result { - // Fast path: extract SpanSet directly. - if let Some(set) = set.as_any().downcast_ref::() { - if self.is_map_compatible(&set.map) { - return Ok(set.spans.clone()); - } - } - - // Slow path: iterate through the set and convert it to a non-lazy - // SpanSet. - let mut spans = SpanSet::empty(); - for name in set.iter()? { - let name = name?; - let id = self.map().vertex_id(name)?; - spans.push(id); - } - Ok(spans) - } -} - impl PrefixLookup for T where T: NameDagStorage, @@ -693,7 +668,7 @@ fn is_ok_some(value: Result>) -> bool { } /// IdMap + IdDag backend for DagAlgorithm. -pub trait NameDagStorage { +pub trait NameDagStorage: IdMapEq { type IdDagStore: IdDagStore; type IdMap: IdConvert; @@ -705,9 +680,6 @@ pub trait NameDagStorage { /// (Cheaply) clone the map. fn clone_map(&self) -> Arc; - - /// (Cheaply) test if the map is compatible (same). - fn is_map_compatible(&self, other: &Arc) -> bool; } impl NameDagStorage for NameDag { @@ -723,9 +695,6 @@ impl NameDagStorage for NameDag { fn clone_map(&self) -> Arc { self.snapshot_map.clone() } - fn is_map_compatible(&self, other: &Arc) -> bool { - Arc::ptr_eq(other, &self.snapshot_map) - } } impl NameDagStorage for MemNameDag { @@ -741,6 +710,15 @@ impl NameDagStorage for MemNameDag { fn clone_map(&self) -> Arc { self.snapshot_map.clone() } +} + +impl IdMapEq for NameDag { + fn is_map_compatible(&self, other: &Arc) -> bool { + Arc::ptr_eq(other, &self.snapshot_map) + } +} + +impl IdMapEq for MemNameDag { fn is_map_compatible(&self, other: &Arc) -> bool { Arc::ptr_eq(other, &self.snapshot_map) } diff --git a/eden/scm/lib/dag/src/ops.rs b/eden/scm/lib/dag/src/ops.rs index 30d60f162f..4acf9ebb05 100644 --- a/eden/scm/lib/dag/src/ops.rs +++ b/eden/scm/lib/dag/src/ops.rs @@ -12,9 +12,13 @@ use crate::id::Group; use crate::id::Id; use crate::id::VertexName; use crate::namedag::MemNameDag; +use crate::nameset::id_lazy::IdLazySet; +use crate::nameset::id_static::IdStaticSet; use crate::nameset::NameSet; +use crate::IdSet; use anyhow::Result; use std::collections::HashMap; +use std::sync::Arc; /// DAG related read-only algorithms. pub trait DagAlgorithm { @@ -330,3 +334,43 @@ where Ok(()) } } + +pub trait ToIdSet { + /// Converts [`NameSet`] to [`SpanSet`]. + fn to_id_set(&self, set: &NameSet) -> Result; +} + +pub trait IdMapEq { + /// (Cheaply) test if the map is compatible (same). + fn is_map_compatible(&self, other: &Arc) -> bool; +} + +impl ToIdSet for T { + /// Converts [`NameSet`] to [`IdSet`]. + fn to_id_set(&self, set: &NameSet) -> Result { + // Fast path: extract IdSet from IdStaticSet. + if let Some(set) = set.as_any().downcast_ref::() { + if self.is_map_compatible(&set.map) { + return Ok(set.spans.clone()); + } + } + + // Convert IdLazySet to IdStaticSet. Bypass hash lookups. + if let Some(set) = set.as_any().downcast_ref::() { + if self.is_map_compatible(&set.map) { + let set: IdStaticSet = set.to_static()?; + return Ok(set.spans); + } + } + + // Slow path: iterate through the set and convert it to a non-lazy + // IdSet. Does not bypass hash lookups. + let mut spans = IdSet::empty(); + for name in set.iter()? { + let name = name?; + let id = self.vertex_id(name)?; + spans.push(id); + } + Ok(spans) + } +}