Coalesce overlapping chunk batches
This commit is contained in:
parent
3f0f1f70b9
commit
d804dc11f1
2 changed files with 27 additions and 8 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue