perf(server): generate chunk baselines outside the cache lock

This commit is contained in:
Serkyo 2026-07-28 00:22:37 +02:00
parent 1d041e035e
commit 95c798954c

View file

@ -26,8 +26,12 @@ impl ChunkCache {
} }
/// Returns the baseline for `pos`, generating and caching it on a miss. /// Returns the baseline for `pos`, generating and caching it on a miss.
///
/// Generation runs outside the lock, so concurrent callers do not serialise on a cache miss. Two callers racing on the same position may each generate a baseline; generation is deterministic and side-effect-free, so the duplicated work is redundant rather than incorrect, and is far cheaper than serialising every miss behind the store.
#[must_use] #[must_use]
pub fn get_or_generate(&self, pos: ChunkPos, generator: &VoxelGenerator) -> Chunk { pub fn get_or_generate(&self, pos: ChunkPos, generator: &VoxelGenerator) -> Chunk {
// Probe under the lock, then release it before generating.
{
// A poisoned lock cannot yield a usable cache; recovering the guard lets generation proceed rather than propagating a panic across every worker that shares this cache. // A poisoned lock cannot yield a usable cache; recovering the guard lets generation proceed rather than propagating a panic across every worker that shares this cache.
let mut guard = self let mut guard = self
.inner .inner
@ -36,8 +40,16 @@ impl ChunkCache {
if let Some(hit) = guard.get(&pos) { if let Some(hit) = guard.get(&pos) {
return hit.clone(); return hit.clone();
} }
}
let chunk = generator.generate_chunk(pos); let chunk = generator.generate_chunk(pos);
guard.put(pos, chunk.clone());
// Retake the lock only to publish. A concurrent caller may have inserted the same position in the meantime; overwriting is harmless because both baselines are identical.
self.inner
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.put(pos, chunk.clone());
chunk chunk
} }
} }