perf: O(1) chunk cache lookup with shared Arc buffers instead of O(n) scan+clone
The decompressed-chunk LRU cache was the hottest path in the read pipeline (every chunked-dataset read goes through it) but did a linear scan through up to 521 slots on every get/put, and a full buffer copy on every cache hit (to_vec()/clone() of the whole decompressed chunk). chunked_read.rs then cloned the buffer a second time just to insert it into the cache after already having it in hand. - Added a HashMap<ChunkCoord, usize> index alongside the LRU slots for O(1) lookup. Eviction uses swap_remove, so the swapped-in slot's index entry is fixed up on every eviction (covered by a dedicated test). - CachedChunk.data is now Arc<CacheAlignedBuffer> — a cache hit is a refcount bump, not a copy. CacheAlignedBuffer gained a Sync impl (same soundness argument as its existing Send impl: access is only ever through borrow-checked &/&mut, like Vec<u8>) so Arc<CacheAlignedBuffer> is itself Send/Sync. - put_decompressed/put_decompressed_aligned now return the Arc they just inserted (or the existing cached copy), so callers can reuse that allocation instead of holding a separate clone — eliminates the second copy in chunked_read.rs's three call sites, which now consume the Arc<CacheAlignedBuffer> (Deref's to &[u8], so downstream indexing/copy code is unchanged). - prefetch_hint's doc comment now leads with "bookkeeping only, does not prefetch" instead of describing behavior it doesn't have. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b9898c2a9c
commit
b70d594c4f
@@ -9,6 +9,8 @@ use alloc::{format, vec, vec::Vec};
|
||||
use crate::chunk_cache::CacheAlignedBuffer;
|
||||
#[cfg(feature = "std")]
|
||||
use crate::chunk_cache::ChunkCache;
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::Arc;
|
||||
use crate::data_layout::DataLayout;
|
||||
use crate::dataspace::Dataspace;
|
||||
use crate::datatype::Datatype;
|
||||
@@ -689,7 +691,7 @@ pub fn read_chunked_data_cached(
|
||||
let coord: Vec<u64> = chunk_info.offsets.iter().take(rank).copied().collect();
|
||||
|
||||
// Try decompressed cache first
|
||||
let decompressed = if let Some(cached) = cache.get_decompressed(&coord) {
|
||||
let decompressed = if let Some(cached) = cache.get_decompressed_aligned(&coord) {
|
||||
cached
|
||||
} else {
|
||||
// Decompress from file
|
||||
@@ -711,8 +713,7 @@ pub fn read_chunked_data_cached(
|
||||
} else {
|
||||
raw_chunk.to_vec()
|
||||
};
|
||||
cache.put_decompressed(coord, dec.clone());
|
||||
dec
|
||||
cache.put_decompressed(coord, dec)
|
||||
};
|
||||
|
||||
let chunk_offsets: Vec<usize> = chunk_info
|
||||
@@ -1055,7 +1056,7 @@ pub fn read_chunked_data_sweep(
|
||||
}
|
||||
|
||||
// Try decompressed cache first
|
||||
let decompressed = if let Some(cached) = cache.get_decompressed(&coord) {
|
||||
let decompressed = if let Some(cached) = cache.get_decompressed_aligned(&coord) {
|
||||
cached
|
||||
} else {
|
||||
// Decompress from file
|
||||
@@ -1077,8 +1078,7 @@ pub fn read_chunked_data_sweep(
|
||||
} else {
|
||||
raw_chunk.to_vec()
|
||||
};
|
||||
cache.put_decompressed(coord, dec.clone());
|
||||
dec
|
||||
cache.put_decompressed(coord, dec)
|
||||
};
|
||||
|
||||
let chunk_offsets: Vec<usize> = chunk_info
|
||||
@@ -1271,7 +1271,7 @@ pub fn read_chunked_data_indexed(
|
||||
.ok_or_else(|| FormatError::ChunkedReadError("chunk layout not available".into()))?;
|
||||
|
||||
// Decompress chunks (using LRU cache where possible)
|
||||
let mut chunk_buffers: Vec<CacheAlignedBuffer> = Vec::with_capacity(mappings_info.len());
|
||||
let mut chunk_buffers: Vec<Arc<CacheAlignedBuffer>> = Vec::with_capacity(mappings_info.len());
|
||||
for (coord, file_offset, file_size, filter_mask) in &mappings_info {
|
||||
if let Some(cached) = cache.get_decompressed_aligned(coord) {
|
||||
chunk_buffers.push(cached);
|
||||
@@ -1295,8 +1295,8 @@ pub fn read_chunked_data_indexed(
|
||||
raw_chunk.to_vec()
|
||||
};
|
||||
let aligned = CacheAlignedBuffer::from_vec(decompressed);
|
||||
cache.put_decompressed_aligned(coord.clone(), aligned.clone());
|
||||
chunk_buffers.push(aligned);
|
||||
let arc = cache.put_decompressed_aligned(coord.clone(), aligned);
|
||||
chunk_buffers.push(arc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user