Implement ticketed chunk lifecycle

This commit is contained in:
Master290 2026-07-21 10:04:56 +03:00
parent cae06eb97e
commit cbd5c7b546
12 changed files with 696 additions and 100 deletions

View file

@ -0,0 +1,78 @@
package world
import (
"context"
"errors"
"testing"
)
func TestTicketPinsChunkUntilRelease(t *testing.T) {
cache := NewCacheWithLimit(-1, func(cx, cz int32) *Chunk {
return NewChunk(cx, cz, BiomePlains)
}, nil, 2)
tickets := cache.NewTicketSet()
tickets.Replace([]ChunkPos{{X: 0, Z: 0}}, nil)
for x := int32(0); x < 4; x++ {
if _, err := cache.FrameErr(x, 0); err != nil {
t.Fatal(err)
}
}
if !hasChunk(cache, 0, 0) {
t.Fatal("ticketed chunk was evicted")
}
if got := cache.Stats().Tickets; got != 1 {
t.Fatalf("ticket count = %d, want 1", got)
}
tickets.Close()
if got := cache.Stats(); got.Tickets != 0 || got.Chunks > 2 {
t.Fatalf("after release stats = %+v, want no tickets and <=2 chunks", got)
}
}
func TestOverlappingTicketSetsRequireFinalRelease(t *testing.T) {
cache := NewCacheWithLimit(-1, func(cx, cz int32) *Chunk {
return NewChunk(cx, cz, BiomePlains)
}, nil, 1)
first, second := cache.NewTicketSet(), cache.NewTicketSet()
pos := []ChunkPos{{X: 0, Z: 0}}
first.Replace(pos, nil)
second.Replace(nil, pos)
if _, err := cache.FrameErr(0, 0); err != nil {
t.Fatal(err)
}
first.Close()
if got := cache.Stats().Tickets; got != 1 {
t.Fatalf("tickets after first close = %d, want 1", got)
}
if _, err := cache.FrameErr(1, 0); err != nil {
t.Fatal(err)
}
if !hasChunk(cache, 0, 0) {
t.Fatal("chunk was evicted while second owner still held it")
}
second.Close()
second.Close() // idempotent
if got := cache.Stats(); got.Tickets != 0 || got.Chunks > 1 {
t.Fatalf("after final close stats = %+v", got)
}
}
func TestFrameAdmissionCanBeCancelled(t *testing.T) {
cache := NewCache(-1, func(cx, cz int32) *Chunk {
return NewChunk(cx, cz, BiomePlains)
})
for i := 0; i < cap(cache.frameSlots); i++ {
cache.frameSlots <- struct{}{}
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err := cache.FrameErrContext(ctx, 0, 0)
if !errors.Is(err, context.Canceled) {
t.Fatalf("FrameErrContext error = %v, want context.Canceled", err)
}
for i := 0; i < cap(cache.frameSlots); i++ {
<-cache.frameSlots
}
}