👷 Improve memory storage

This commit is contained in:
kiyon
2020-11-03 08:26:25 +08:00
parent f927b040f4
commit 2350adcae2
3 changed files with 83 additions and 47 deletions

View File

@@ -15,7 +15,7 @@ var ConfigDefault = Config{
GCInterval: 10 * time.Second,
}
// Helper function to set default values
// configDefault is a helper function to set default values
func configDefault(config ...Config) Config {
// Return default config if nothing provided
if len(config) < 1 {

View File

@@ -43,7 +43,7 @@ func (s *Storage) Get(key string) ([]byte, error) {
return nil, nil
}
if v.expiry <= time.Now().Unix() && v.expiry != 0 {
if v.expiry != 0 && v.expiry <= time.Now().Unix() {
return nil, nil
}
@@ -80,15 +80,11 @@ func (s *Storage) Clear() error {
}
func (s *Storage) gc() {
tick := time.NewTicker(s.gcInterval)
for {
<-tick.C
for t := range time.NewTicker(s.gcInterval).C {
now := t.Unix()
s.mux.Lock()
now := time.Now().Unix()
for id, v := range s.db {
if v.expiry < now && v.expiry != 0 {
if v.expiry != 0 && v.expiry < now {
delete(s.db, id)
}
}

View File

@@ -7,20 +7,31 @@ import (
"github.com/gofiber/utils"
)
func Test_Memory_Config(t *testing.T) {
t.Parallel()
store := New(Config{})
utils.AssertEqual(t, ConfigDefault.GCInterval, store.gcInterval)
}
func Test_Memory_Set(t *testing.T) {
t.Parallel()
store := New()
id := "hello"
value := []byte("Hi there!")
store.Set(id, value, 0)
err := store.Set(id, value, 0)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, entry{value, 0}, store.db[id])
}
func Test_Memory_SetExpiry(t *testing.T) {
t.Parallel()
store := New()
@@ -28,7 +39,9 @@ func Test_Memory_SetExpiry(t *testing.T) {
value := []byte("Hi there!")
expiry := time.Second * 10
store.Set(id, value, expiry)
err := store.Set(id, value, expiry)
utils.AssertEqual(t, nil, err)
now := time.Now().Unix()
fromStore, found := store.db[id]
@@ -44,45 +57,66 @@ func Test_Memory_SetExpiry(t *testing.T) {
}
// func Test_Memory_GC(t *testing.T) {
func Test_Memory_GC(t *testing.T) {
t.Parallel()
// // New() isn't being used here so the gcInterval can be set low
// store := &Storage{
// DB: make(map[string]entry),
// gcInterval: time.Second * 1,
// }
// go store.gc()
// id := "hello"
// value := []byte("Hi there!")
// expireAt := time.Now().Add(time.Second * 2).Unix()
// store.db[id] = entry{value, expireAt}
// time.Sleep(time.Second * 4) // The purpose of the long delay is to ensure the GC has time to run and delete the value
// _, found := store.db[id]
// utils.AssertEqual(t, false, found)
// }
func Test_Memory_Get(t *testing.T) {
store := New()
store := &Storage{
db: make(map[string]entry),
gcInterval: time.Millisecond * 10,
}
id := "hello"
value := []byte("Hi there!")
store.db[id] = entry{value, 0}
expireAt := time.Now().Add(-time.Second).Unix()
returnedValue, err := store.Get(id)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, value, returnedValue)
store.db[id] = entry{value, expireAt}
go store.gc()
// The purpose of the long delay is to ensure the GC has time to run and delete the value
time.Sleep(time.Millisecond * 15)
store.mux.RLock()
_, found := store.db[id]
utils.AssertEqual(t, false, found)
store.mux.RUnlock()
}
func Test_Memory_Get(t *testing.T) {
t.Parallel()
store := New()
t.Run("exist", func(t *testing.T) {
id := "hello"
value := []byte("Hi there!")
store.db[id] = entry{value, 0}
returnedValue, err := store.Get(id)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, value, returnedValue)
})
t.Run("expired", func(t *testing.T) {
expired := "expired"
store.db[expired] = entry{[]byte{}, time.Now().Add(-time.Second).Unix()}
returnedValue, err := store.Get(expired)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, true, returnedValue == nil)
})
t.Run("non-exist", func(t *testing.T) {
returnedValue, err := store.Get("non-exist")
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, true, returnedValue == nil)
})
}
func Test_Memory_Delete(t *testing.T) {
t.Parallel()
store := New()
@@ -100,6 +134,7 @@ func Test_Memory_Delete(t *testing.T) {
}
func Test_Memory_Clear(t *testing.T) {
t.Parallel()
store := New()
@@ -122,12 +157,14 @@ func Benchmark_Memory_Set(b *testing.B) {
value := []byte("Hi there!")
expiry := time.Duration(0)
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
store.Set(id, value, expiry)
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = store.Set(id, value, expiry)
}
})
}
func Benchmark_Memory_Get(b *testing.B) {
@@ -139,9 +176,12 @@ func Benchmark_Memory_Get(b *testing.B) {
store.db[id] = entry{value, 0}
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
store.Get(id)
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = store.Get(id)
}
})
}