Details
Details
Diff Detail
Diff Detail
- Repository
 - rHG Mercurial
 - Lint
 Lint Skipped - Unit
 Unit Tests Skipped 
| Lint Skipped | 
| Unit Tests Skipped | 
| extern crate rand; | extern crate rand; | ||||
| extern crate rand_pcg; | extern crate rand_pcg; | ||||
| use self::rand::seq::SliceRandom; | use self::rand::seq::SliceRandom; | ||||
| use self::rand::{thread_rng, RngCore, SeedableRng}; | use self::rand::{thread_rng, RngCore, SeedableRng}; | ||||
| use super::{Graph, GraphError, Revision, NULL_REVISION}; | use super::{Graph, GraphError, Revision, NULL_REVISION}; | ||||
| use crate::ancestors::MissingAncestors; | use crate::ancestors::MissingAncestors; | ||||
| use crate::dagops; | use crate::dagops; | ||||
| use std::cmp::Reverse; | |||||
| use std::collections::BinaryHeap; | |||||
| use std::collections::{HashMap, HashSet, VecDeque}; | use std::collections::{HashMap, HashSet, VecDeque}; | ||||
| type Rng = self::rand_pcg::Pcg32; | type Rng = self::rand_pcg::Pcg32; | ||||
| pub struct PartialDiscovery<G: Graph + Clone> { | pub struct PartialDiscovery<G: Graph + Clone> { | ||||
| target_heads: Option<Vec<Revision>>, | target_heads: Option<Vec<Revision>>, | ||||
| graph: G, // plays the role of self._repo | graph: G, // plays the role of self._repo | ||||
| common: MissingAncestors<G>, | common: MissingAncestors<G>, | ||||
| } | } | ||||
| /// Register revisions known as being missing | /// Register revisions known as being missing | ||||
| pub fn add_missing_revisions( | pub fn add_missing_revisions( | ||||
| &mut self, | &mut self, | ||||
| missing: impl IntoIterator<Item = Revision>, | missing: impl IntoIterator<Item = Revision>, | ||||
| ) -> Result<(), GraphError> { | ) -> Result<(), GraphError> { | ||||
| self.ensure_undecided()?; | self.ensure_undecided()?; | ||||
| if let Some(ref children) = self.children_cache { | |||||
| let mut seen: HashSet<Revision> = HashSet::new(); | |||||
| let mut tovisit: VecDeque<Revision> = | |||||
| missing.into_iter().map(|r| -r).collect(); | |||||
| let undecided_mut = self.undecided.as_mut().unwrap(); | |||||
| loop { | |||||
| match tovisit.pop_front() { | |||||
| None => { | |||||
| break; | |||||
| } | |||||
| Some(opp_rev) => { | |||||
| let rev = -opp_rev; | |||||
| self.missing.insert(rev); | |||||
| undecided_mut.remove(&rev); | |||||
| match children.get(&rev) { | |||||
| None => { | |||||
| continue; | |||||
| } | |||||
| Some(this_children) => { | |||||
| for child in this_children.iter().cloned() { | |||||
| if child != NULL_REVISION | |||||
| && !seen.contains(&child) | |||||
| { | |||||
| tovisit.push_back(-child); | |||||
| seen.insert(child); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } else { | |||||
| let range = dagops::range( | let range = dagops::range( | ||||
| &self.graph, | &self.graph, | ||||
| missing, | missing, | ||||
| self.undecided.as_ref().unwrap().iter().cloned(), | self.undecided.as_ref().unwrap().iter().cloned(), | ||||
| )?; | )?; | ||||
| let undecided_mut = self.undecided.as_mut().unwrap(); | let undecided_mut = self.undecided.as_mut().unwrap(); | ||||
| for missrev in range { | for missrev in range { | ||||
| self.missing.insert(missrev); | self.missing.insert(missrev); | ||||
| undecided_mut.remove(&missrev); | undecided_mut.remove(&missrev); | ||||
| } | } | ||||
| } | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| /// Do we have any information about the peer? | /// Do we have any information about the peer? | ||||
| pub fn has_info(&self) -> bool { | pub fn has_info(&self) -> bool { | ||||
| self.common.has_bases() | self.common.has_bases() | ||||
| } | } | ||||
| assert_eq!(sorted_undecided(&disco), vec![]); | assert_eq!(sorted_undecided(&disco), vec![]); | ||||
| assert_eq!(sorted_missing(&disco), vec![8, 10, 13]); | assert_eq!(sorted_missing(&disco), vec![8, 10, 13]); | ||||
| assert!(disco.is_complete()); | assert!(disco.is_complete()); | ||||
| assert_eq!(sorted_common_heads(&disco)?, vec![5, 11, 12]); | assert_eq!(sorted_common_heads(&disco)?, vec![5, 11, 12]); | ||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| #[test] | #[test] | ||||
| fn test_discovery_with_children_cache() -> Result<(), GraphError> { | |||||
| let mut disco = full_disco(); | |||||
| disco.add_common_revisions(vec![11, 12])?; | |||||
| disco.ensure_children_cache(); | |||||
| disco.add_missing_revisions(vec![8, 10])?; | |||||
| assert_eq!(sorted_undecided(&disco), vec![5]); | |||||
| assert_eq!(sorted_missing(&disco), vec![8, 10, 13]); | |||||
| assert!(!disco.is_complete()); | |||||
| disco.add_common_revisions(vec![5])?; | |||||
| assert_eq!(sorted_undecided(&disco), vec![]); | |||||
| assert_eq!(sorted_missing(&disco), vec![8, 10, 13]); | |||||
| assert!(disco.is_complete()); | |||||
| assert_eq!(sorted_common_heads(&disco)?, vec![5, 11, 12]); | |||||
| Ok(()) | |||||
| } | |||||
| #[test] | |||||
| fn test_limit_sample_no_need_to() { | fn test_limit_sample_no_need_to() { | ||||
| let sample = vec![1, 2, 3, 4]; | let sample = vec![1, 2, 3, 4]; | ||||
| assert_eq!(full_disco().limit_sample(sample, 10), vec![1, 2, 3, 4]); | assert_eq!(full_disco().limit_sample(sample, 10), vec![1, 2, 3, 4]); | ||||
| } | } | ||||
| #[test] | #[test] | ||||
| fn test_limit_sample_less_than_half() { | fn test_limit_sample_less_than_half() { | ||||
| assert_eq!(full_disco().limit_sample((1..6).collect(), 2), vec![4, 2]); | assert_eq!(full_disco().limit_sample((1..6).collect(), 2), vec![4, 2]); | ||||