Created
October 29, 2019 15:32
-
-
Save erikdubbelboer/bd904c51f00079421fd3eb2a061a50c0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"math/rand" | |
"net/http" | |
"runtime" | |
"strings" | |
"sync/atomic" | |
"time" | |
"unsafe" | |
"github.com/dgraph-io/ristretto" | |
_ "net/http/pprof" | |
) | |
const charset = "abcdefghijklmnopqrstuvwxyz0123456789" | |
// key generates a random key. | |
func key() string { | |
b := make([]byte, 3) // 36^3 = 46656 possible keys | |
for i := 0; i < len(b); i++ { | |
b[i] = charset[rand.Intn(len(charset))] | |
} | |
return string(b) | |
} | |
type Value struct { | |
key string | |
val string | |
} | |
var sizeofValue = int(unsafe.Sizeof(Value{})) | |
func (v *Value) cost() int64 { | |
return int64(len(v.key) + len(v.val) + sizeofValue) | |
} | |
func main() { | |
runtime.MemProfileRate = 1 | |
start := time.Now() | |
cache, err := ristretto.NewCache(&ristretto.Config{ | |
NumCounters: 466560, // Possible keys * 10 | |
MaxCost: 1024 * 1024 * 1024, // 1 GiB | |
BufferItems: 64, | |
Metrics: false, | |
}) | |
if err != nil { | |
panic(err) | |
} | |
hits := int64(0) | |
misses := int64(0) | |
// Speed things up by using 5 goroutines. | |
// Can also remove the time.Sleep or just wait longer. | |
for i := 0; i < 5; i++ { | |
go func() { | |
for { | |
// Sleep a little bit to give the cache some time to do things. | |
time.Sleep(time.Millisecond) | |
k := key() | |
v, ok := cache.Get(k) // Just doing Set without Get doesn't cause the bug to happen. | |
if ok && v != nil { | |
atomic.AddInt64(&hits, 1) | |
} else { | |
atomic.AddInt64(&misses, 1) | |
var val string | |
// This is important, only 1 size won't trigger the bug. | |
if rand.Intn(100) < 10 { | |
val = "test" | |
} else { | |
val = strings.Repeat("a", 1024*1024) | |
} | |
// If we uncomment this to insert as the same key as the miss above it doesn't happen. | |
k := key() | |
v := &Value{ | |
key: k, | |
val: val, | |
} | |
cache.Set(k, v, v.cost()) | |
} | |
} | |
}() | |
} | |
go func() { | |
panic(http.ListenAndServe("localhost:6060", nil)) | |
}() | |
for { | |
time.Sleep(time.Second) | |
// Do a GC to get better allocation stats. | |
runtime.GC() | |
var m runtime.MemStats | |
runtime.ReadMemStats(&m) | |
hi := atomic.SwapInt64(&hits, 0) | |
mi := atomic.SwapInt64(&misses, 0) | |
fmt.Printf("time: %s alloc: %.2f MiB hits: %d misses: %d\n", time.Since(start).Round(time.Second), float64(m.Alloc)/1024/1024, hi, mi) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment