diff --git a/turbopack/crates/turbo-persistence/src/arc_bytes.rs b/turbopack/crates/turbo-persistence/src/arc_bytes.rs index bc9df993226c7..51900c354184c 100644 --- a/turbopack/crates/turbo-persistence/src/arc_bytes.rs +++ b/turbopack/crates/turbo-persistence/src/arc_bytes.rs @@ -89,6 +89,17 @@ impl ArcBytes { pub fn is_mmap_backed(&self) -> bool { matches!(self.backing, Backing::Mmap { .. }) } + + /// Returns `true` if the backing `Arc` allocation is shared (i.e., there + /// are other `Arc` clones referencing the same data outside the cache). + /// Always returns `false` for mmap-backed bytes, since the mmap `Arc` is + /// shared across all slices from the same file and is not a useful signal. + pub fn is_shared_arc(&self) -> bool { + match &self.backing { + Backing::Arc { _backing } => Arc::strong_count(_backing) > 1, + Backing::Mmap { .. } => false, + } + } } impl SharedBytes for ArcBytes { diff --git a/turbopack/crates/turbo-persistence/src/lib.rs b/turbopack/crates/turbo-persistence/src/lib.rs index 3a877ae5ee7f9..e75abfeede1d9 100644 --- a/turbopack/crates/turbo-persistence/src/lib.rs +++ b/turbopack/crates/turbo-persistence/src/lib.rs @@ -74,7 +74,8 @@ pub use key::{KeyBase, QueryKey, StoreKey, hash_key}; pub use meta_file::MetaEntryFlags; pub use parallel_scheduler::{ParallelScheduler, SerialScheduler}; pub use static_sorted_file::{ - BlockCache, BlockWeighter, SstLookupResult, StaticSortedFile, StaticSortedFileMetaData, + BlockCache, BlockCacheLifecycle, BlockWeighter, SstLookupResult, StaticSortedFile, + StaticSortedFileMetaData, }; pub use static_sorted_file_builder::{ BLOCK_HEADER_SIZE, Entry, EntryValue, StreamingSstWriter, write_static_stored_file, diff --git a/turbopack/crates/turbo-persistence/src/static_sorted_file.rs b/turbopack/crates/turbo-persistence/src/static_sorted_file.rs index 6679b6a1be164..ad0ec57f31f00 100644 --- a/turbopack/crates/turbo-persistence/src/static_sorted_file.rs +++ b/turbopack/crates/turbo-persistence/src/static_sorted_file.rs @@ -12,7 +12,7 @@ use std::{ use anyhow::{Context, Result, bail, ensure}; use memmap2::Mmap; -use quick_cache::sync::GuardResult; +use quick_cache::{Lifecycle, sync::GuardResult}; use rustc_hash::FxHasher; use smallvec::SmallVec; @@ -100,8 +100,33 @@ impl quick_cache::Weighter<(u32, u16), ArcBytes> for BlockWeighter { } } -pub type BlockCache = - quick_cache::sync::Cache<(u32, u16), ArcBytes, BlockWeighter, BuildHasherDefault>; +/// Lifecycle hooks for the block cache that prevent eviction of entries +/// still referenced outside the cache (i.e., with `Arc` strong count > 1). +#[derive(Clone, Default)] +pub struct BlockCacheLifecycle; + +impl Lifecycle<(u32, u16), ArcBytes> for BlockCacheLifecycle { + type RequestState = (); + + #[inline] + fn is_pinned(&self, _key: &(u32, u16), val: &ArcBytes) -> bool { + val.is_shared_arc() + } + + #[inline] + fn begin_request(&self) -> Self::RequestState {} + + #[inline] + fn on_evict(&self, _state: &mut Self::RequestState, _key: (u32, u16), _val: ArcBytes) {} +} + +pub type BlockCache = quick_cache::sync::Cache< + (u32, u16), + ArcBytes, + BlockWeighter, + BuildHasherDefault, + BlockCacheLifecycle, +>; /// Trait abstracting value block reading for `handle_key_match_generic`. /// diff --git a/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs b/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs index 89f828d7701d8..b966ae0418d06 100644 --- a/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs +++ b/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs @@ -1224,25 +1224,17 @@ impl IndexBlockBuilder { #[cfg(test)] mod tests { - use std::hash::BuildHasherDefault; - - use quick_cache::sync::Cache; - use rustc_hash::FxHasher; - use super::*; use crate::{ key::hash_key, lookup_entry::LookupValue, static_sorted_file::{ - BlockWeighter, SstLookupResult, StaticSortedFile, StaticSortedFileMetaData, + BlockCache, SstLookupResult, StaticSortedFile, StaticSortedFileMetaData, }, }; - type TestBlockCache = - Cache<(u32, u16), crate::ArcBytes, BlockWeighter, BuildHasherDefault>; - - fn make_cache() -> TestBlockCache { - TestBlockCache::with( + fn make_cache() -> BlockCache { + BlockCache::with( 100, 4 * 1024 * 1024, Default::default(), @@ -1385,8 +1377,8 @@ mod tests { fn assert_lookup( sst: &StaticSortedFile, entry: &TestEntry, - kc: &TestBlockCache, - vc: &TestBlockCache, + kc: &BlockCache, + vc: &BlockCache, ) -> Result<()> { let result = sst.lookup::<_, false>(entry.hash, &entry.key, kc, vc)?; match (&entry.value_kind, result) {