perf(server): generate chunk baselines outside the cache lock
This commit is contained in:
parent
1d041e035e
commit
95c798954c
|
|
@ -26,18 +26,30 @@ impl ChunkCache {
|
|||
}
|
||||
|
||||
/// 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]
|
||||
pub fn get_or_generate(&self, pos: ChunkPos, generator: &VoxelGenerator) -> Chunk {
|
||||
// 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
|
||||
.inner
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
if let Some(hit) = guard.get(&pos) {
|
||||
return hit.clone();
|
||||
// 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.
|
||||
let mut guard = self
|
||||
.inner
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
if let Some(hit) = guard.get(&pos) {
|
||||
return hit.clone();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue