Skip to content

Commit 25661fe

Browse files
authored
feat(memory-cache): add maxGenerations support (#9517)
feat(memory-cache): add `maxGenerations` support
1 parent a2a1f74 commit 25661fe

File tree

10 files changed

+85
-25
lines changed

10 files changed

+85
-25
lines changed

crates/node_binding/binding.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,7 @@ export interface RawCacheGroupOptions {
14221422

14231423
export interface RawCacheOptions {
14241424
type: string
1425+
maxGenerations?: number
14251426
}
14261427

14271428
export interface RawConsumeOptions {

crates/node_binding/src/raw_options/raw_cache.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ use rspack_core::CacheOptions;
55
#[napi(object, object_to_js = false)]
66
pub struct RawCacheOptions {
77
pub r#type: String,
8+
pub max_generations: Option<u32>,
89
}
910

1011
impl From<RawCacheOptions> for CacheOptions {
1112
fn from(value: RawCacheOptions) -> CacheOptions {
12-
let RawCacheOptions { r#type } = value;
13+
let RawCacheOptions {
14+
r#type,
15+
max_generations,
16+
} = value;
1317

1418
match r#type.as_str() {
15-
"memory" => CacheOptions::Memory,
19+
"memory" => CacheOptions::Memory { max_generations },
1620
_ => CacheOptions::Disabled,
1721
}
1822
}

crates/rspack/src/builder/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,9 @@ impl CompilerOptionsBuilder {
916916
let bail = d!(self.bail.take(), false);
917917
let cache = d!(self.cache.take(), {
918918
if development {
919-
CacheOptions::Memory
919+
CacheOptions::Memory {
920+
max_generations: None,
921+
}
920922
} else {
921923
CacheOptions::Disabled
922924
}
+5-15
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
use std::{
2-
path::PathBuf,
3-
sync::{
4-
atomic::{AtomicBool, Ordering},
5-
Arc,
6-
},
7-
};
1+
use std::{path::PathBuf, sync::Arc};
82

93
use crate::CompilerOptions;
104

@@ -17,7 +11,6 @@ use storage::new_storage;
1711

1812
#[derive(Debug)]
1913
pub struct Cache {
20-
is_idle: AtomicBool,
2114
pub code_generate_occasion: CodeGenerateOccasion,
2215
pub process_runtime_requirements_occasion: ProcessRuntimeRequirementsOccasion,
2316
pub chunk_render_occasion: ChunkRenderOccasion,
@@ -26,7 +19,6 @@ pub struct Cache {
2619
impl Cache {
2720
pub fn new(options: Arc<CompilerOptions>) -> Self {
2821
Self {
29-
is_idle: true.into(),
3022
code_generate_occasion: CodeGenerateOccasion::new(new_storage(&options.cache)),
3123
process_runtime_requirements_occasion: ProcessRuntimeRequirementsOccasion::new(new_storage(
3224
&options.cache,
@@ -40,12 +32,10 @@ impl Cache {
4032
}
4133

4234
pub fn begin_idle(&self) {
43-
if self.is_idle.load(Ordering::Relaxed) {
44-
// TODO clean cache
45-
}
35+
self.code_generate_occasion.begin_idle();
36+
self.process_runtime_requirements_occasion.begin_idle();
37+
self.chunk_render_occasion.begin_idle();
4638
}
4739

48-
pub fn end_idle(&self) {
49-
self.is_idle.store(false, Ordering::Relaxed);
50-
}
40+
pub fn end_idle(&self) {}
5141
}

crates/rspack_core/src/old_cache/occasion/chunk_render.rs

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ impl ChunkRenderOccasion {
1717
Self { storage }
1818
}
1919

20+
pub fn begin_idle(&self) {
21+
if let Some(s) = &self.storage {
22+
s.begin_idle();
23+
}
24+
}
25+
2026
pub async fn use_cache<G, F>(
2127
&self,
2228
compilation: &Compilation,

crates/rspack_core/src/old_cache/occasion/code_generate.rs

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ impl CodeGenerateOccasion {
1616
Self { storage }
1717
}
1818

19+
pub fn begin_idle(&self) {
20+
if let Some(s) = &self.storage {
21+
s.begin_idle();
22+
}
23+
}
24+
1925
// #[tracing::instrument(skip_all, fields(module = ?job.module))]
2026
pub fn use_cache(
2127
&self,

crates/rspack_core/src/old_cache/occasion/process_runtime_requirements.rs

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ impl ProcessRuntimeRequirementsOccasion {
1818
Self { storage }
1919
}
2020

21+
pub fn begin_idle(&self) {
22+
if let Some(s) = &self.storage {
23+
s.begin_idle();
24+
}
25+
}
26+
2127
// #[tracing::instrument(skip_all, fields(module = ?module))]
2228
pub fn use_cache(
2329
&self,
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,34 @@
1+
use std::sync::atomic::{AtomicU32, Ordering};
2+
13
use dashmap::DashMap;
24
use rspack_collections::{Identifier, IdentifierDashMap};
35

46
use super::Storage;
57

8+
#[derive(Debug, Hash, PartialEq, Eq)]
9+
struct CacheData<Item> {
10+
item: Item,
11+
generation: u32,
12+
}
13+
14+
impl<Item> CacheData<Item> {
15+
fn new(item: Item, generation: u32) -> Self {
16+
Self { item, generation }
17+
}
18+
}
19+
620
#[derive(Debug)]
721
pub struct MemoryStorage<Item> {
8-
data: IdentifierDashMap<Item>,
22+
generation: AtomicU32,
23+
max_generations: u32,
24+
data: IdentifierDashMap<CacheData<Item>>,
925
}
1026

1127
impl<Item> MemoryStorage<Item> {
12-
pub fn new() -> Self {
28+
pub fn new(max_generations: u32) -> Self {
1329
Self {
30+
generation: AtomicU32::new(0),
31+
max_generations,
1432
data: DashMap::default(),
1533
}
1634
}
@@ -21,12 +39,31 @@ where
2139
Item: Clone + std::fmt::Debug + Send + Sync,
2240
{
2341
fn get(&self, id: &Identifier) -> Option<Item> {
24-
self.data.get(id).map(|item| item.clone())
42+
self.data.get_mut(id).map(|mut item| {
43+
// Reset the generation to the current generation if the item is accessed
44+
item.generation = self.generation.load(Ordering::Relaxed);
45+
item.item.clone()
46+
})
2547
}
2648
fn set(&self, id: Identifier, data: Item) {
27-
self.data.insert(id, data);
49+
self.data.insert(
50+
id,
51+
CacheData::new(data, self.generation.load(Ordering::Relaxed)),
52+
);
2853
}
2954
fn remove(&self, id: &Identifier) {
3055
self.data.remove(id);
3156
}
57+
fn begin_idle(&self) {
58+
let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1;
59+
self.data.retain(|_, cache_data| {
60+
// Remove the data if it is not accessed for `max_generations`.
61+
// With `max_generations` set to x, the cache was generated on generation y, will be removed on generation x + y + 1.
62+
//
63+
// For example:
64+
// Cache created on generation 0 will be removed on generation 2 with `max_generations` set to 1,
65+
// If it's not accessed on generation 1.
66+
cache_data.generation.saturating_add(self.max_generations) >= generation
67+
});
68+
}
3269
}

crates/rspack_core/src/old_cache/storage/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub trait Storage<Item>: Debug + Send + Sync {
1111
fn get(&self, id: &Identifier) -> Option<Item>;
1212
fn set(&self, id: Identifier, data: Item);
1313
fn remove(&self, id: &Identifier);
14-
// fn begin_idle(&self);
14+
fn begin_idle(&self);
1515
// fn end_idle(&self);
1616
// fn clear(&self);
1717
}
@@ -22,6 +22,8 @@ where
2222
{
2323
match options {
2424
CacheOptions::Disabled => None,
25-
_ => Some(Box::new(MemoryStorage::new())),
25+
CacheOptions::Memory { max_generations } => {
26+
Some(Box::new(MemoryStorage::new(max_generations.unwrap_or(1))))
27+
}
2628
}
2729
}

crates/rspack_core/src/options/cache.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22
pub enum CacheOptions {
33
#[default]
44
Disabled,
5-
Memory,
5+
Memory {
6+
/// The maximum number of generations to keep in memory.
7+
///
8+
/// For example, if `max_generations` is set to 1,
9+
/// the cache will be removed if it's not accessed for 1 compilation generation.
10+
max_generations: Option<u32>,
11+
},
612
}

0 commit comments

Comments
 (0)