diff --git a/Cargo.lock b/Cargo.lock index 49e34e8534f0..468143b42bc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5380,7 +5380,7 @@ dependencies = [ "linera-storage-service", "linera-version", "linera-views", - "lru 0.12.5", + "lru 0.15.0", "meta-counter", "papaya", "prometheus", @@ -5457,7 +5457,7 @@ dependencies = [ "linera-wasmer", "linera-wasmer-compiler-singlepass", "linera-witty", - "lru 0.12.5", + "lru 0.15.0", "oneshot", "papaya", "prometheus", @@ -6338,18 +6338,18 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" -version = "0.12.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ "hashbrown 0.15.5", ] [[package]] name = "lru" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +checksum = "0281c2e25e62316a5c9d98f2d2e9e95a37841afdaf4383c177dbb5c1dfab0568" dependencies = [ "hashbrown 0.15.5", ] diff --git a/Cargo.toml b/Cargo.toml index 393257346064..8b2e4fe0bdf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -152,7 +152,7 @@ kube = "0.88.1" linera-kywasmtime = "0.1.0" linked-hash-map = "0.5.6" log = "0.4.21" -lru = "0.12.3" +lru = "0.15.0" mini-moka = "0.10.3" nonzero_lit = "0.1.2" num-bigint = "0.4.3" diff --git a/examples/Cargo.lock b/examples/Cargo.lock index c40a6c188509..1985ce15f2d1 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -38,18 +38,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.7.35", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -3000,7 +2988,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.8", + "ahash", ] [[package]] @@ -3008,10 +2996,6 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.11", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -3720,7 +3704,7 @@ dependencies = [ "linera-storage-service", "linera-version", "linera-views", - "lru 0.12.4", + "lru 0.15.0", "papaya", "prometheus", "proptest", @@ -3783,7 +3767,7 @@ dependencies = [ "linera-wasmer", "linera-wasmer-compiler-singlepass", "linera-witty", - "lru 0.12.4", + "lru 0.15.0", "oneshot", "papaya", "prometheus", @@ -4170,18 +4154,18 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] name = "lru" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +checksum = "0281c2e25e62316a5c9d98f2d2e9e95a37841afdaf4383c177dbb5c1dfab0568" dependencies = [ "hashbrown 0.15.2", ] diff --git a/linera-execution/src/wasm/module_cache.rs b/linera-execution/src/wasm/module_cache.rs index 03a99f9c2e11..7c4f4f32e3e8 100644 --- a/linera-execution/src/wasm/module_cache.rs +++ b/linera-execution/src/wasm/module_cache.rs @@ -32,6 +32,17 @@ impl Default for ModuleCache { } } +impl ModuleCache { + #[cfg(test)] + fn with_max_size(max_size: u64) -> Self { + ModuleCache { + modules: LruCache::unbounded(), + total_size: 0, + max_size, + } + } +} + impl ModuleCache { /// Returns a `Module` for the requested `bytecode`, creating it with `module_builder` and /// adding it to the cache if it doesn't already exist in the cache. @@ -58,11 +69,20 @@ impl ModuleCache { pub fn insert(&mut self, bytecode: Bytecode, module: Module) { let bytecode_size = bytecode.as_ref().len() as u64; + if bytecode_size > self.max_size { + return; + } + + if self.modules.promote(&bytecode) { + return; + } + if self.total_size + bytecode_size > self.max_size { self.reduce_size_to(self.max_size - bytecode_size); } self.modules.put(bytecode, module); + self.total_size += bytecode_size; } /// Evicts entries from the cache so that the total size of cached bytecode files is less than @@ -79,3 +99,71 @@ impl ModuleCache { } } } + +#[cfg(test)] +mod tests { + use super::*; + + fn bytecode(size: usize) -> Bytecode { + Bytecode::new(vec![0u8; size]) + } + + fn distinct_bytecode(size: usize, discriminant: u8) -> Bytecode { + let mut bytes = vec![0u8; size]; + bytes[0] = discriminant; + Bytecode::new(bytes) + } + + #[test] + fn total_size_tracks_insertions() { + let mut cache = ModuleCache::::with_max_size(1000); + cache.insert(bytecode(100), 1); + assert_eq!(cache.total_size, 100); + cache.insert(distinct_bytecode(200, 1), 2); + assert_eq!(cache.total_size, 300); + } + + #[test] + fn eviction_triggers_when_full() { + let mut cache = ModuleCache::::with_max_size(250); + cache.insert(bytecode(100), 1); + cache.insert(distinct_bytecode(100, 1), 2); + assert_eq!(cache.total_size, 200); + assert_eq!(cache.modules.len(), 2); + + cache.insert(distinct_bytecode(100, 2), 3); + assert_eq!(cache.modules.len(), 2); + assert!(cache.total_size <= 250); + } + + #[test] + fn oversized_bytecode_is_rejected() { + let mut cache = ModuleCache::::with_max_size(50); + cache.insert(bytecode(100), 1); + assert_eq!(cache.total_size, 0); + assert_eq!(cache.modules.len(), 0); + } + + #[test] + fn reinserting_same_key_does_not_double_count() { + let mut cache = ModuleCache::::with_max_size(1000); + let bc = bytecode(100); + cache.insert(bc.clone(), 1); + assert_eq!(cache.total_size, 100); + cache.insert(bc, 2); + assert_eq!(cache.total_size, 100); + assert_eq!(cache.modules.len(), 1); + } + + #[test] + fn reinserting_existing_key_does_not_evict() { + let mut cache = ModuleCache::::with_max_size(200); + cache.insert(bytecode(100), 1); + cache.insert(distinct_bytecode(100, 1), 2); + assert_eq!(cache.modules.len(), 2); + + cache.insert(bytecode(100), 3); + assert_eq!(cache.modules.len(), 2); + assert_eq!(cache.total_size, 200); + } +} diff --git a/linera-sdk/tests/fixtures/Cargo.lock b/linera-sdk/tests/fixtures/Cargo.lock index 850785cfabe3..336ec87ede3f 100644 --- a/linera-sdk/tests/fixtures/Cargo.lock +++ b/linera-sdk/tests/fixtures/Cargo.lock @@ -2663,9 +2663,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" -version = "0.12.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "0281c2e25e62316a5c9d98f2d2e9e95a37841afdaf4383c177dbb5c1dfab0568" dependencies = [ "hashbrown 0.15.5", ]