change: Finished benchmarking and some more features

This commit is contained in:
Nicholas Novak 2023-12-05 15:27:40 -08:00
parent 93c7564c43
commit 2f4303ddb8
5 changed files with 30 additions and 14 deletions

View File

@ -16,9 +16,13 @@ witchcraft-save:
mkdir witchcraft-save mkdir witchcraft-save
./spatial-db load worldsave "saves/Witchcraft/region" --output "witchcraft-save" ./spatial-db load worldsave "saves/Witchcraft/region" --output "witchcraft-save"
.PHONY: compile
compile:
CC=clang go build .
.PHONY: bench .PHONY: bench
bench: bench: compile
go test -bench . -benchtime=10s -count 10 CC=clang go test -bench . -benchtime=2s -count 10
.PHONY: clean .PHONY: clean
clean: clean:

View File

@ -2,13 +2,14 @@ package main
import ( import (
"errors" "errors"
"io"
"testing" "testing"
"git.nicholasnovak.io/nnovak/spatial-db/storage" "git.nicholasnovak.io/nnovak/spatial-db/storage"
"git.nicholasnovak.io/nnovak/spatial-db/world" "git.nicholasnovak.io/nnovak/spatial-db/world"
) )
var server storage.SimpleServer var server storage.InMemoryServer
func init() { func init() {
server.SetStorageRoot("skygrid-save") server.SetStorageRoot("skygrid-save")
@ -20,7 +21,7 @@ func readBlockTemplate(rootDir string, b *testing.B, pointSpread int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
pos := world.RandomBlockPosWithRange(float64(pointSpread)) pos := world.RandomBlockPosWithRange(float64(pointSpread))
if _, err := server.ReadBlockAt(pos); err != nil { 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 continue
} else { } else {
b.Error(err) b.Error(err)
@ -49,3 +50,7 @@ func BenchmarkReadClusteredPoints(b *testing.B) {
func BenchmarkReadSparserPoints(b *testing.B) { func BenchmarkReadSparserPoints(b *testing.B) {
readBlockTemplate("skygrid-test", b, 2048) readBlockTemplate("skygrid-test", b, 2048)
} }
func BenchmarkReadSparserPoints1(b *testing.B) {
readBlockTemplate("skygrid-test", b, 65536)
}

View File

@ -3,6 +3,7 @@ package storage
import ( import (
"math/rand" "math/rand"
"os" "os"
"time"
) )
// A `FileCache` stores open file descriptors for all files that have been // A `FileCache` stores open file descriptors for all files that have been
@ -12,6 +13,8 @@ type FileCache struct {
fileNames map[string]int fileNames map[string]int
indexesOfFiles map[int]string indexesOfFiles map[int]string
files []*os.File files []*os.File
randSource *rand.Rand
} }
func NewFileCache(cacheSize int) FileCache { func NewFileCache(cacheSize int) FileCache {
@ -22,6 +25,8 @@ func NewFileCache(cacheSize int) FileCache {
c.indexesOfFiles = make(map[int]string) c.indexesOfFiles = make(map[int]string)
c.files = make([]*os.File, cacheSize) c.files = make([]*os.File, cacheSize)
c.randSource = rand.New(rand.NewSource(time.Now().UnixNano()))
return c 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 // 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 // Random cache eviction
indexToRemove := rand.Intn(fc.cacheSize) indexToRemove := fc.randSource.Intn(fc.cacheSize)
// Remove the old value // Remove the old value
oldName, present := fc.indexesOfFiles[indexToRemove] oldName, present := fc.indexesOfFiles[indexToRemove]
@ -48,11 +58,6 @@ func (fc *FileCache) FetchFile(fileName string) (*os.File, error) {
delete(fc.indexesOfFiles, indexToRemove) delete(fc.indexesOfFiles, indexToRemove)
} }
f, err := os.Open(fileName)
if err != nil {
return nil, err
}
// Insert the new value // Insert the new value
fc.files[indexToRemove] = f fc.files[indexToRemove] = f
fc.fileNames[fileName] = indexToRemove fc.fileNames[fileName] = indexToRemove

View File

@ -69,7 +69,7 @@ func (hs *HashServer) ChangeBlockRange(
} }
func (hs *HashServer) ReadBlockAt(pos world.BlockPos) (world.BlockID, error) { 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) { func (hs *HashServer) ReadChunkAt(pos world.ChunkPos) (world.ChunkData, error) {

View File

@ -18,10 +18,12 @@ var (
type SimpleServer struct { type SimpleServer struct {
StorageDir string StorageDir string
cache FileCache
} }
func (s *SimpleServer) SetStorageRoot(path string) { func (s *SimpleServer) SetStorageRoot(path string) {
s.StorageDir = path s.StorageDir = path
s.cache = NewFileCache(256)
} }
// Filesystem operations // Filesystem operations
@ -57,12 +59,13 @@ func (s *SimpleServer) FetchOrCreateChunk(pos world.ChunkPos) (world.ChunkData,
return ReadChunkFromFile(chunkFile) return ReadChunkFromFile(chunkFile)
} }
// `FetchChunk' fetches the chunk's data, given the chunk's position
func (s *SimpleServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) { func (s *SimpleServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) {
chunkFileName := filepath.Join(s.StorageDir, pos.ToFileName()) chunkFileName := filepath.Join(s.StorageDir, pos.ToFileName())
var chunkData world.ChunkData var chunkData world.ChunkData
chunkFile, err := os.Open(chunkFileName) chunkFile, err := s.cache.FetchFile(chunkFileName)
if err != nil { if err != nil {
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
return chunkData, ChunkNotFoundError return chunkData, ChunkNotFoundError
@ -70,7 +73,6 @@ func (s *SimpleServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) {
return chunkData, err return chunkData, err
} }
} }
defer chunkFile.Close()
return ReadChunkFromFile(chunkFile) return ReadChunkFromFile(chunkFile)
} }
@ -99,7 +101,7 @@ func (s *SimpleServer) ChangeBlockRange(
} }
func (s *SimpleServer) ReadBlockAt(pos world.BlockPos) (world.BlockID, error) { 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 { if err != nil {
return world.Empty, err return world.Empty, err
} }