Skip to content

Commit ad116a8

Browse files
committed
perf(module-graph): compact connection overlay
1 parent 95c928f commit ad116a8

1 file changed

Lines changed: 97 additions & 17 deletions

File tree

crates/rspack_core/src/module_graph/rollback/dense_dependency_id_overlay_map.rs

Lines changed: 97 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,65 @@
11
use super::OverlayValue;
22
use crate::DependencyId;
33

4+
const UNCHANGED: u32 = 0;
5+
6+
#[derive(Debug, Clone)]
7+
struct DenseOverlay<V> {
8+
/// Maps a dependency id to an index in `values`. Zero means the base value is unchanged.
9+
value_indices: Vec<u32>,
10+
/// Stores only values that differ from the base map.
11+
values: Vec<OverlayValue<V>>,
12+
}
13+
14+
impl<V> Default for DenseOverlay<V> {
15+
fn default() -> Self {
16+
Self {
17+
value_indices: Vec::new(),
18+
values: Vec::new(),
19+
}
20+
}
21+
}
22+
23+
impl<V> DenseOverlay<V> {
24+
#[inline]
25+
fn get(&self, index: usize) -> Option<&OverlayValue<V>> {
26+
let value_index = *self.value_indices.get(index)?;
27+
if value_index == UNCHANGED {
28+
return None;
29+
}
30+
self.values.get(value_index as usize - 1)
31+
}
32+
33+
#[inline]
34+
fn get_mut(&mut self, index: usize) -> Option<&mut OverlayValue<V>> {
35+
let value_index = *self.value_indices.get(index)?;
36+
if value_index == UNCHANGED {
37+
return None;
38+
}
39+
self.values.get_mut(value_index as usize - 1)
40+
}
41+
42+
#[inline]
43+
fn insert(&mut self, index: usize, value: OverlayValue<V>) {
44+
if self.value_indices.len() <= index {
45+
self.value_indices.resize(index + 1, UNCHANGED);
46+
}
47+
48+
let value_index = &mut self.value_indices[index];
49+
if *value_index == UNCHANGED {
50+
self.values.push(value);
51+
*value_index = u32::try_from(self.values.len())
52+
.expect("dense dependency overlay cannot contain more than u32::MAX values");
53+
} else {
54+
self.values[*value_index as usize - 1] = value;
55+
}
56+
}
57+
}
58+
459
#[derive(Debug, Clone)]
560
pub struct DenseDependencyIdOverlayMap<V> {
661
base: Vec<Option<V>>,
7-
overlay: Option<Vec<Option<OverlayValue<V>>>>,
62+
overlay: Option<DenseOverlay<V>>,
863
}
964

1065
impl<V> Default for DenseDependencyIdOverlayMap<V> {
@@ -19,7 +74,7 @@ impl<V> Default for DenseDependencyIdOverlayMap<V> {
1974
impl<V> DenseDependencyIdOverlayMap<V> {
2075
#[inline]
2176
pub fn checkpoint(&mut self) {
22-
self.overlay.get_or_insert_with(Vec::new);
77+
self.overlay.get_or_insert_default();
2378
}
2479

2580
#[inline]
@@ -30,10 +85,8 @@ impl<V> DenseDependencyIdOverlayMap<V> {
3085
#[inline]
3186
pub fn insert(&mut self, key: DependencyId, value: V) {
3287
let index = key.as_u32() as usize;
33-
if self.overlay.is_some() {
34-
Self::ensure_len(self.overlay(), index);
35-
self.overlay.as_mut().expect("overlay checked above")[index] =
36-
Some(OverlayValue::Value(value));
88+
if let Some(overlay) = &mut self.overlay {
89+
overlay.insert(index, OverlayValue::Value(value));
3790
} else {
3891
Self::ensure_len(&mut self.base, index);
3992
self.base[index] = Some(value);
@@ -43,9 +96,8 @@ impl<V> DenseDependencyIdOverlayMap<V> {
4396
#[inline]
4497
pub fn remove(&mut self, key: &DependencyId) {
4598
let index = key.as_u32() as usize;
46-
if self.overlay.is_some() {
47-
Self::ensure_len(self.overlay(), index);
48-
self.overlay.as_mut().expect("overlay checked above")[index] = Some(OverlayValue::Tombstone);
99+
if let Some(overlay) = &mut self.overlay {
100+
overlay.insert(index, OverlayValue::Tombstone);
49101
} else if let Some(value) = self.base.get_mut(index) {
50102
*value = None;
51103
}
@@ -55,7 +107,7 @@ impl<V> DenseDependencyIdOverlayMap<V> {
55107
pub fn get(&self, key: &DependencyId) -> Option<&V> {
56108
let index = key.as_u32() as usize;
57109
if let Some(overlay) = &self.overlay
58-
&& let Some(Some(value)) = overlay.get(index)
110+
&& let Some(value) = overlay.get(index)
59111
{
60112
return match value {
61113
OverlayValue::Value(value) => Some(value),
@@ -74,7 +126,7 @@ impl<V> DenseDependencyIdOverlayMap<V> {
74126
if self.overlay.is_some() {
75127
self.materialize_overlay_value(index);
76128
let overlay = self.overlay.as_mut().expect("overlay checked above");
77-
match overlay.get_mut(index).and_then(Option::as_mut) {
129+
match overlay.get_mut(index) {
78130
Some(OverlayValue::Value(value)) => Some(value),
79131
_ => None,
80132
}
@@ -89,20 +141,18 @@ impl<V> DenseDependencyIdOverlayMap<V> {
89141
V: Clone,
90142
{
91143
let overlay = self.overlay.as_ref().expect("overlay checked above");
92-
if matches!(overlay.get(index), Some(Some(_))) {
144+
if overlay.get(index).is_some() {
93145
return;
94146
}
95147

96148
if let Some(value) = self.base.get(index).and_then(Option::as_ref).cloned() {
97-
Self::ensure_len(self.overlay(), index);
98-
self.overlay.as_mut().expect("overlay checked above")[index] =
99-
Some(OverlayValue::Value(value));
149+
self.overlay().insert(index, OverlayValue::Value(value));
100150
}
101151
}
102152

103153
#[inline]
104-
fn overlay(&mut self) -> &mut Vec<Option<OverlayValue<V>>> {
105-
self.overlay.get_or_insert_with(Vec::new)
154+
fn overlay(&mut self) -> &mut DenseOverlay<V> {
155+
self.overlay.get_or_insert_default()
106156
}
107157

108158
#[inline]
@@ -172,4 +222,34 @@ mod tests {
172222

173223
assert_eq!(map.get(&a), Some(&1));
174224
}
225+
226+
#[test]
227+
fn repeated_overlay_writes_reuse_the_value_slot() {
228+
let mut map = DenseDependencyIdOverlayMap::default();
229+
let id = DependencyId::from(7);
230+
231+
map.checkpoint();
232+
map.insert(id, 1);
233+
map.insert(id, 2);
234+
map.remove(&id);
235+
236+
let overlay = map.overlay.as_ref().expect("should have overlay");
237+
assert_eq!(overlay.value_indices.len(), 8);
238+
assert_eq!(overlay.values.len(), 1);
239+
assert_eq!(map.get(&id), None);
240+
}
241+
242+
#[test]
243+
fn sparse_overlay_stores_only_changed_values() {
244+
let mut map = DenseDependencyIdOverlayMap::default();
245+
let id = DependencyId::from(1024);
246+
247+
map.checkpoint();
248+
map.insert(id, 1);
249+
250+
let overlay = map.overlay.as_ref().expect("should have overlay");
251+
assert_eq!(overlay.value_indices.len(), 1025);
252+
assert_eq!(overlay.values.len(), 1);
253+
assert_eq!(map.get(&id), Some(&1));
254+
}
175255
}

0 commit comments

Comments
 (0)