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()
|
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 {
|
if loadErr == nil {
|
||||||
for batchKey, batchChunk := range generatedBatch {
|
for batchKey, batchChunk := range generatedBatch {
|
||||||
if batchKey == key || batchChunk == nil || batchChunk.X != batchKey[0] || batchChunk.Z != batchKey[1] {
|
if batchKey == key || batchChunk == nil || batchChunk.X != batchKey[0] || batchChunk.Z != batchKey[1] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, loading := c.loads[batchKey]; loading {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, exists := c.chunks[batchKey]; !exists {
|
if _, exists := c.chunks[batchKey]; !exists {
|
||||||
c.chunks[batchKey] = batchChunk
|
c.chunks[batchKey] = batchChunk
|
||||||
c.touch(batchKey)
|
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.chunks[key] = ch
|
||||||
c.touch(key)
|
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)
|
started := make(chan struct{}, 2)
|
||||||
release := make(chan struct{})
|
release := make(chan struct{})
|
||||||
c := NewCache(-1, GenerateFlat)
|
c := NewCache(-1, GenerateFlat)
|
||||||
c.SetBatchGenerator(func(cx, cz int32) (map[[2]int32]*Chunk, error) {
|
c.SetBatchGenerator(func(cx, cz int32) (map[[2]int32]*Chunk, error) {
|
||||||
started <- struct{}{}
|
started <- struct{}{}
|
||||||
<-release
|
<-release
|
||||||
|
biome := uint16(cx + 10)
|
||||||
return map[[2]int32]*Chunk{
|
return map[[2]int32]*Chunk{
|
||||||
{cx, cz}: NewChunk(cx, cz, BiomePlains),
|
{cx, cz}: NewChunk(cx, cz, biome),
|
||||||
{cx + 1, cz}: NewChunk(cx+1, cz, BiomePlains),
|
{cx + 1, cz}: NewChunk(cx+1, cz, biome),
|
||||||
{cx - 1, cz}: NewChunk(cx-1, cz, BiomePlains),
|
{cx - 1, cz}: NewChunk(cx-1, cz, biome),
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -261,15 +262,24 @@ func TestConcurrentOverlappingBatchLoadsKeepOwnership(t *testing.T) {
|
||||||
<-started
|
<-started
|
||||||
<-started
|
<-started
|
||||||
close(release)
|
close(release)
|
||||||
|
loaded := make(map[[2]int32]*Chunk)
|
||||||
for range 2 {
|
for range 2 {
|
||||||
result := <-results
|
result := <-results
|
||||||
if result.err != nil || result.chunk == nil {
|
if result.err != nil || result.chunk == nil {
|
||||||
t.Fatalf("overlapping batch load = %v, %v", result.chunk, result.err)
|
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")
|
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) {
|
func TestBatchGeneratorRejectsWrongTargetCoordinates(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue