comparison rust/hg-core/src/dagops.rs @ 51260:c4f1a790bda8

rust-index: use a `BitVec` instead of plain `Vec` for heads computation The `Vec` method uses one byte per revision, this uses 1 per 8 revisions, which improves our memory footprint. For large graphs (10+ millions), this can make a measurable difference server-side. I have seen no measurable impact on execution speed.
author Raphaël Gomès <rgomes@octobus.net>
date Wed, 29 Nov 2023 15:58:24 -0500
parents ed6683d4cb29
children
comparison
equal deleted inserted replaced
51259:ed6683d4cb29 51260:c4f1a790bda8
10 //! # Terminology 10 //! # Terminology
11 //! - By *relative heads* of a collection of revision numbers (`Revision`), we 11 //! - By *relative heads* of a collection of revision numbers (`Revision`), we
12 //! mean those revisions that have no children among the collection. 12 //! mean those revisions that have no children among the collection.
13 //! - Similarly *relative roots* of a collection of `Revision`, we mean those 13 //! - Similarly *relative roots* of a collection of `Revision`, we mean those
14 //! whose parents, if any, don't belong to the collection. 14 //! whose parents, if any, don't belong to the collection.
15 use bitvec::slice::BitSlice;
16
15 use super::{Graph, GraphError, Revision, NULL_REVISION}; 17 use super::{Graph, GraphError, Revision, NULL_REVISION};
16 use crate::{ancestors::AncestorsIterator, BaseRevision}; 18 use crate::{ancestors::AncestorsIterator, BaseRevision};
17 use std::collections::{BTreeSet, HashSet}; 19 use std::collections::{BTreeSet, HashSet};
18 20
19 fn remove_parents<S: std::hash::BuildHasher>( 21 fn remove_parents<S: std::hash::BuildHasher>(
79 } 81 }
80 } 82 }
81 Ok(()) 83 Ok(())
82 } 84 }
83 85
84 /// Optimized version of `retain_heads` that expects an zeroed array of the size 86 /// Optimized version of `retain_heads` that expects an zeroed bitvec of the
85 /// of the graph, to act as a faster but less space-efficient `HashSet`. 87 /// size of the graph, to act as a faster but less space-efficient `HashSet`.
86 /// 88 ///
87 /// # Panics 89 /// # Panics
88 /// 90 ///
89 /// Can panic if `not_heads` is shorten than the length of graph. 91 /// Can panic if `not_heads` is shorten than the length of graph.
90 pub fn retain_heads_fast( 92 pub fn retain_heads_fast(
91 graph: &impl Graph, 93 graph: &impl Graph,
92 not_heads: &mut [bool], 94 not_heads: &mut BitSlice,
93 filtered_revs: &HashSet<Revision>, 95 filtered_revs: &HashSet<Revision>,
94 ) -> Result<(), GraphError> { 96 ) -> Result<(), GraphError> {
95 for idx in (0..not_heads.len()).rev() { 97 for idx in (0..not_heads.len()).rev() {
96 let rev = Revision(idx as BaseRevision); 98 let rev = Revision(idx as BaseRevision);
97 if !not_heads[idx] && filtered_revs.contains(&rev) { 99 if !not_heads[idx] && filtered_revs.contains(&rev) {
98 not_heads[idx] = true; 100 not_heads.get_mut(idx).unwrap().commit(true);
99 continue; 101 continue;
100 } 102 }
101 for parent in graph.parents(rev)?.iter() { 103 for parent in graph.parents(rev)?.iter() {
102 if *parent != NULL_REVISION { 104 if *parent != NULL_REVISION {
103 not_heads[parent.0 as usize] = true; 105 not_heads.get_mut(parent.0 as usize).unwrap().commit(true);
104 } 106 }
105 } 107 }
106 } 108 }
107 Ok(()) 109 Ok(())
108 } 110 }