diff --git a/Makefile b/Makefile index b0f88d8..85020f0 100644 --- a/Makefile +++ b/Makefile @@ -16,9 +16,13 @@ witchcraft-save: mkdir witchcraft-save ./spatial-db load worldsave "saves/Witchcraft/region" --output "witchcraft-save" +.PHONY: compile +compile: + CC=clang go build . + .PHONY: bench -bench: - go test -bench . -benchtime=10s -count 10 +bench: compile + CC=clang go test -bench . -benchtime=2s -count 10 .PHONY: clean clean: diff --git a/scaling_test.go b/scaling_test.go index 519ed9b..5100b51 100644 --- a/scaling_test.go +++ b/scaling_test.go @@ -2,13 +2,14 @@ package main import ( "errors" + "io" "testing" "git.nicholasnovak.io/nnovak/spatial-db/storage" "git.nicholasnovak.io/nnovak/spatial-db/world" ) -var server storage.SimpleServer +var server storage.InMemoryServer func init() { server.SetStorageRoot("skygrid-save") @@ -20,7 +21,7 @@ func readBlockTemplate(rootDir string, b *testing.B, pointSpread int) { for i := 0; i < b.N; i++ { pos := world.RandomBlockPosWithRange(float64(pointSpread)) if _, err := server.ReadBlockAt(pos); err != nil { - if errors.Is(err, storage.ChunkNotFoundError) { + if errors.Is(err, storage.ChunkNotFoundError) || errors.Is(err, io.EOF) { continue } else { b.Error(err) @@ -49,3 +50,7 @@ func BenchmarkReadClusteredPoints(b *testing.B) { func BenchmarkReadSparserPoints(b *testing.B) { readBlockTemplate("skygrid-test", b, 2048) } + +func BenchmarkReadSparserPoints1(b *testing.B) { + readBlockTemplate("skygrid-test", b, 65536) +} diff --git a/storage/file_cache.go b/storage/file_cache.go index 1171d0a..967f56b 100644 --- a/storage/file_cache.go +++ b/storage/file_cache.go @@ -3,6 +3,7 @@ package storage import ( "math/rand" "os" + "time" ) // A `FileCache` stores open file descriptors for all files that have been @@ -12,6 +13,8 @@ type FileCache struct { fileNames map[string]int indexesOfFiles map[int]string files []*os.File + + randSource *rand.Rand } func NewFileCache(cacheSize int) FileCache { @@ -22,6 +25,8 @@ func NewFileCache(cacheSize int) FileCache { c.indexesOfFiles = make(map[int]string) c.files = make([]*os.File, cacheSize) + c.randSource = rand.New(rand.NewSource(time.Now().UnixNano())) + return c } @@ -36,8 +41,13 @@ func (fc *FileCache) FetchFile(fileName string) (*os.File, error) { // The file was not in the cache, try and insert it + f, err := os.Open(fileName) + if err != nil { + return nil, err + } + // Random cache eviction - indexToRemove := rand.Intn(fc.cacheSize) + indexToRemove := fc.randSource.Intn(fc.cacheSize) // Remove the old value oldName, present := fc.indexesOfFiles[indexToRemove] @@ -48,11 +58,6 @@ func (fc *FileCache) FetchFile(fileName string) (*os.File, error) { delete(fc.indexesOfFiles, indexToRemove) } - f, err := os.Open(fileName) - if err != nil { - return nil, err - } - // Insert the new value fc.files[indexToRemove] = f fc.fileNames[fileName] = indexToRemove diff --git a/storage/hashserver.go b/storage/hashserver.go index c65ef25..70a9a0f 100644 --- a/storage/hashserver.go +++ b/storage/hashserver.go @@ -69,7 +69,7 @@ func (hs *HashServer) ChangeBlockRange( } func (hs *HashServer) ReadBlockAt(pos world.BlockPos) (world.BlockID, error) { - panic("Unimplemented") + return hs.blocks[pos], nil } func (hs *HashServer) ReadChunkAt(pos world.ChunkPos) (world.ChunkData, error) { diff --git a/storage/simple_server.go b/storage/simple_server.go index d28d2d2..4c696b3 100644 --- a/storage/simple_server.go +++ b/storage/simple_server.go @@ -18,10 +18,12 @@ var ( type SimpleServer struct { StorageDir string + cache FileCache } func (s *SimpleServer) SetStorageRoot(path string) { s.StorageDir = path + s.cache = NewFileCache(256) } // Filesystem operations @@ -57,12 +59,13 @@ func (s *SimpleServer) FetchOrCreateChunk(pos world.ChunkPos) (world.ChunkData, return ReadChunkFromFile(chunkFile) } +// `FetchChunk' fetches the chunk's data, given the chunk's position func (s *SimpleServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) { chunkFileName := filepath.Join(s.StorageDir, pos.ToFileName()) var chunkData world.ChunkData - chunkFile, err := os.Open(chunkFileName) + chunkFile, err := s.cache.FetchFile(chunkFileName) if err != nil { if errors.Is(err, fs.ErrNotExist) { return chunkData, ChunkNotFoundError @@ -70,7 +73,6 @@ func (s *SimpleServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) { return chunkData, err } } - defer chunkFile.Close() return ReadChunkFromFile(chunkFile) } @@ -99,7 +101,7 @@ func (s *SimpleServer) ChangeBlockRange( } func (s *SimpleServer) ReadBlockAt(pos world.BlockPos) (world.BlockID, error) { - chunk, err := s.FetchOrCreateChunk(pos.ToChunkPos()) + chunk, err := s.FetchChunk(pos.ToChunkPos()) if err != nil { return world.Empty, err }