From d804dc11f1fc57aadb3491fe45896464154275f7 Mon Sep 17 00:00:00 2001 From: Daniar Mannanov Date: Tue, 18 Aug 2026 01:24:20 +0300 Subject: [PATCH] Coalesce overlapping chunk batches --- internal/world/cache.go | 15 ++++++++++++--- internal/world/cache_test.go | 20 +++++++++++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/internal/world/cache.go b/internal/world/cache.go index 64090a1..221305e 100644 --- a/internal/world/cache.go +++ b/internal/world/cache.go @@ -242,18 +242,27 @@ func (c *Cache) chunkAtErr(cx, cz int32) (*Chunk, error) { } c.mu.Lock() + if c.loads[key] != pending { + // An overlapping batch completed this target while its own generation was + // running. Keep the first published result and do not close done twice. + ch, loadErr = pending.ch, pending.err + c.mu.Unlock() + return ch, loadErr + } if loadErr == nil { for batchKey, batchChunk := range generatedBatch { if batchKey == key || batchChunk == nil || batchChunk.X != batchKey[0] || batchChunk.Z != batchKey[1] { continue } - if _, loading := c.loads[batchKey]; loading { - continue - } if _, exists := c.chunks[batchKey]; !exists { c.chunks[batchKey] = batchChunk c.touch(batchKey) } + if neighborLoad := c.loads[batchKey]; neighborLoad != nil { + neighborLoad.ch = c.chunks[batchKey] + delete(c.loads, batchKey) + close(neighborLoad.done) + } } c.chunks[key] = ch c.touch(key) diff --git a/internal/world/cache_test.go b/internal/world/cache_test.go index be44f0a..4350feb 100644 --- a/internal/world/cache_test.go +++ b/internal/world/cache_test.go @@ -231,17 +231,18 @@ func TestBatchGeneratorPublishesNeighborsAtomically(t *testing.T) { } } -func TestConcurrentOverlappingBatchLoadsKeepOwnership(t *testing.T) { +func TestConcurrentOverlappingBatchLoadsShareFirstResult(t *testing.T) { started := make(chan struct{}, 2) release := make(chan struct{}) c := NewCache(-1, GenerateFlat) c.SetBatchGenerator(func(cx, cz int32) (map[[2]int32]*Chunk, error) { started <- struct{}{} <-release + biome := uint16(cx + 10) return map[[2]int32]*Chunk{ - {cx, cz}: NewChunk(cx, cz, BiomePlains), - {cx + 1, cz}: NewChunk(cx+1, cz, BiomePlains), - {cx - 1, cz}: NewChunk(cx-1, cz, BiomePlains), + {cx, cz}: NewChunk(cx, cz, biome), + {cx + 1, cz}: NewChunk(cx+1, cz, biome), + {cx - 1, cz}: NewChunk(cx-1, cz, biome), }, nil }) @@ -261,15 +262,24 @@ func TestConcurrentOverlappingBatchLoadsKeepOwnership(t *testing.T) { <-started <-started close(release) + loaded := make(map[[2]int32]*Chunk) for range 2 { result := <-results if result.err != nil || result.chunk == nil { t.Fatalf("overlapping batch load = %v, %v", result.chunk, result.err) } + loaded[[2]int32{result.chunk.X, result.chunk.Z}] = result.chunk } - if c.chunkAt(0, 0) == nil || c.chunkAt(1, 0) == nil { + left, right := c.chunkAt(0, 0), c.chunkAt(1, 0) + if left == nil || right == nil { t.Fatal("overlapping targets were not retained") } + if left != loaded[[2]int32{0, 0}] || right != loaded[[2]int32{1, 0}] { + t.Fatal("requesters did not receive the canonical cached batch results") + } + if left.GetBiome(0, MinY, 0) != right.GetBiome(0, MinY, 0) { + t.Fatal("overlapping chunks came from different batch results") + } } func TestBatchGeneratorRejectsWrongTargetCoordinates(t *testing.T) {