1
+ use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
2
+
1
3
use dashmap:: DashMap ;
2
4
use rspack_collections:: { Identifier , IdentifierDashMap } ;
3
5
4
6
use super :: Storage ;
5
7
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
+
6
20
#[ derive( Debug ) ]
7
21
pub struct MemoryStorage < Item > {
8
- data : IdentifierDashMap < Item > ,
22
+ generation : AtomicU32 ,
23
+ max_generations : u32 ,
24
+ data : IdentifierDashMap < CacheData < Item > > ,
9
25
}
10
26
11
27
impl < Item > MemoryStorage < Item > {
12
- pub fn new ( ) -> Self {
28
+ pub fn new ( max_generations : u32 ) -> Self {
13
29
Self {
30
+ generation : AtomicU32 :: new ( 0 ) ,
31
+ max_generations,
14
32
data : DashMap :: default ( ) ,
15
33
}
16
34
}
@@ -21,12 +39,31 @@ where
21
39
Item : Clone + std:: fmt:: Debug + Send + Sync ,
22
40
{
23
41
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
+ } )
25
47
}
26
48
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
+ ) ;
28
53
}
29
54
fn remove ( & self , id : & Identifier ) {
30
55
self . data . remove ( id) ;
31
56
}
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
+ }
32
69
}
0 commit comments