Skip to content

Commit c1a015f

Browse files
committed
Respect ModuleCache max size
1 parent 8805a12 commit c1a015f

File tree

1 file changed

+75
-1
lines changed

1 file changed

+75
-1
lines changed

linera-execution/src/wasm/module_cache.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ impl<Module> Default for ModuleCache<Module> {
3232
}
3333
}
3434

35+
impl<Module> ModuleCache<Module> {
36+
#[cfg(test)]
37+
fn with_max_size(max_size: u64) -> Self {
38+
ModuleCache {
39+
modules: LruCache::unbounded(),
40+
total_size: 0,
41+
max_size,
42+
}
43+
}
44+
}
45+
3546
impl<Module: Clone> ModuleCache<Module> {
3647
/// Returns a `Module` for the requested `bytecode`, creating it with `module_builder` and
3748
/// adding it to the cache if it doesn't already exist in the cache.
@@ -58,11 +69,18 @@ impl<Module: Clone> ModuleCache<Module> {
5869
pub fn insert(&mut self, bytecode: Bytecode, module: Module) {
5970
let bytecode_size = bytecode.as_ref().len() as u64;
6071

72+
if bytecode_size > self.max_size {
73+
return;
74+
}
75+
6176
if self.total_size + bytecode_size > self.max_size {
6277
self.reduce_size_to(self.max_size - bytecode_size);
6378
}
6479

65-
self.modules.put(bytecode, module);
80+
let already_present = self.modules.put(bytecode, module).is_some();
81+
if !already_present {
82+
self.total_size += bytecode_size;
83+
}
6684
}
6785

6886
/// Evicts entries from the cache so that the total size of cached bytecode files is less than
@@ -79,3 +97,59 @@ impl<Module: Clone> ModuleCache<Module> {
7997
}
8098
}
8199
}
100+
101+
#[cfg(test)]
102+
mod tests {
103+
use super::*;
104+
105+
fn bytecode(size: usize) -> Bytecode {
106+
Bytecode::new(vec![0u8; size])
107+
}
108+
109+
fn distinct_bytecode(size: usize, discriminant: u8) -> Bytecode {
110+
let mut bytes = vec![0u8; size];
111+
bytes[0] = discriminant;
112+
Bytecode::new(bytes)
113+
}
114+
115+
#[test]
116+
fn total_size_tracks_insertions() {
117+
let mut cache = ModuleCache::<u32>::with_max_size(1000);
118+
cache.insert(bytecode(100), 1);
119+
assert_eq!(cache.total_size, 100);
120+
cache.insert(distinct_bytecode(200, 1), 2);
121+
assert_eq!(cache.total_size, 300);
122+
}
123+
124+
#[test]
125+
fn eviction_triggers_when_full() {
126+
let mut cache = ModuleCache::<u32>::with_max_size(250);
127+
cache.insert(bytecode(100), 1);
128+
cache.insert(distinct_bytecode(100, 1), 2);
129+
assert_eq!(cache.total_size, 200);
130+
assert_eq!(cache.modules.len(), 2);
131+
132+
cache.insert(distinct_bytecode(100, 2), 3);
133+
assert_eq!(cache.modules.len(), 2);
134+
assert!(cache.total_size <= 250);
135+
}
136+
137+
#[test]
138+
fn oversized_bytecode_is_rejected() {
139+
let mut cache = ModuleCache::<u32>::with_max_size(50);
140+
cache.insert(bytecode(100), 1);
141+
assert_eq!(cache.total_size, 0);
142+
assert_eq!(cache.modules.len(), 0);
143+
}
144+
145+
#[test]
146+
fn reinserting_same_key_does_not_double_count() {
147+
let mut cache = ModuleCache::<u32>::with_max_size(1000);
148+
let bc = bytecode(100);
149+
cache.insert(bc.clone(), 1);
150+
assert_eq!(cache.total_size, 100);
151+
cache.insert(bc, 2);
152+
assert_eq!(cache.total_size, 100);
153+
assert_eq!(cache.modules.len(), 1);
154+
}
155+
}

0 commit comments

Comments
 (0)