Mercurial > hg
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 } |