This commit is contained in:
Eduard Urbach 2023-07-08 22:10:02 +02:00
parent 06320cf976
commit a21ea3a6ef
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
5 changed files with 105 additions and 93 deletions

99
Benchmarks_test.go Normal file
View File

@ -0,0 +1,99 @@
package ocean_test
import (
"fmt"
"strconv"
"testing"
"git.akyoto.dev/go/assert"
"git.akyoto.dev/go/ocean"
)
func BenchmarkGet(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
users.Set("1", &User{Name: "User 1"})
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
user, err := users.Get("1")
assert.Nil(b, err)
assert.NotNil(b, user)
assert.Equal(b, user.Name, "User 1")
}
})
b.StopTimer()
}
func BenchmarkSet(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
user := &User{Name: "User 1"}
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
users.Set("1", user)
}
})
b.StopTimer()
}
func BenchmarkDelete(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
users.Delete("1")
}
})
b.StopTimer()
}
func BenchmarkColdStart(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
b.Run("100", func(b *testing.B) {
for i := 0; i < 100; i++ {
users.Set(strconv.Itoa(i), &User{Name: fmt.Sprintf("User %d", i)})
}
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
again, err := ocean.New[User]("test")
assert.Nil(b, err)
assert.NotNil(b, again)
}
b.StopTimer()
})
}

View File

@ -78,10 +78,6 @@ func (c *collection[T]) Clear() {
// Delete deletes a key from the collection. // Delete deletes a key from the collection.
func (c *collection[T]) Delete(key string) { func (c *collection[T]) Delete(key string) {
if !c.Exists(key) {
return
}
c.data.Delete(key) c.data.Delete(key)
c.storage.Delete(key) c.storage.Delete(key)
} }

View File

@ -1,8 +1,6 @@
package ocean_test package ocean_test
import ( import (
"fmt"
"strconv"
"sync" "sync"
"testing" "testing"
@ -17,6 +15,7 @@ type User struct {
func TestCollection(t *testing.T) { func TestCollection(t *testing.T) {
users, err := ocean.New[User]("test") users, err := ocean.New[User]("test")
assert.Nil(t, err) assert.Nil(t, err)
defer users.Sync() defer users.Sync()
defer users.Clear() defer users.Clear()
@ -131,87 +130,3 @@ func TestCollection(t *testing.T) {
assert.True(t, !users.Exists("3")) assert.True(t, !users.Exists("3"))
}) })
} }
func BenchmarkGet(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
users.Set("1", &User{Name: "User 1"})
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, err := users.Get("1")
if err != nil {
b.Fail()
}
}
})
b.StopTimer()
}
func BenchmarkSet(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
user := &User{Name: "User 1"}
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
users.Set("1", user)
}
})
b.StopTimer()
}
func BenchmarkDelete(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
users.Delete("1")
}
})
b.StopTimer()
}
func BenchmarkColdStart(b *testing.B) {
users, err := ocean.New[User]("test")
assert.Nil(b, err)
defer users.Sync()
defer users.Clear()
b.Run("100", func(b *testing.B) {
for i := 0; i < 100; i++ {
users.Set(strconv.Itoa(i), &User{Name: fmt.Sprintf("User %d", i)})
}
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
again, err := ocean.New[User]("test")
assert.Nil(b, err)
assert.NotNil(b, again)
}
b.StopTimer()
})
}

View File

@ -12,6 +12,8 @@ import (
"time" "time"
) )
const diskWriteInterval = 100 * time.Millisecond
type FileStorage[T any] struct { type FileStorage[T any] struct {
collection *collection[T] collection *collection[T]
dirty atomic.Uint32 dirty atomic.Uint32
@ -25,7 +27,7 @@ func (fs *FileStorage[T]) Init(c *collection[T]) error {
go fs.flushWorker() go fs.flushWorker()
fileName := filepath.Join(c.root, c.name+".dat") fileName := filepath.Join(c.root, c.name+".dat")
file, err := os.OpenFile(fileName, os.O_RDONLY, 0600) file, err := os.Open(fileName)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil return nil
@ -55,7 +57,7 @@ func (fs *FileStorage[T]) Sync() {
func (fs *FileStorage[T]) flushWorker() { func (fs *FileStorage[T]) flushWorker() {
for { for {
time.Sleep(time.Millisecond) time.Sleep(diskWriteInterval)
if fs.dirty.Swap(0) == 0 { if fs.dirty.Swap(0) == 0 {
select { select {

View File

@ -35,7 +35,7 @@ Data will be stored in `~/.ocean/todolist/User.dat`.
## Example file: User.dat ## Example file: User.dat
``` ```json
1 1
{"name":"User 1"} {"name":"User 1"}
2 2