You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.0 KiB
Go
92 lines
2.0 KiB
Go
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Given is some code to cache key-value pairs from a database into
|
|
// the main memory (to reduce access time). Note that golang's map are
|
|
// not entirely thread safe. Multiple readers are fine, but multiple
|
|
// writers are not. Change the code to make this thread safe.
|
|
//
|
|
|
|
package main
|
|
|
|
import "container/list"
|
|
|
|
// CacheSize determines how big the cache can grow
|
|
const CacheSize = 100
|
|
|
|
// KeyStoreCacheLoader is an interface for the KeyStoreCache
|
|
type KeyStoreCacheLoader interface {
|
|
// Load implements a function where the cache should gets it's content from
|
|
Load(string) string
|
|
}
|
|
|
|
type page struct {
|
|
Key string
|
|
Value string
|
|
}
|
|
|
|
// KeyStoreCache is a LRU cache for string key-value pairs
|
|
type KeyStoreCache struct {
|
|
cache map[string]*list.Element
|
|
pages list.List
|
|
load func(string) string
|
|
}
|
|
|
|
// New creates a new KeyStoreCache
|
|
func New(load KeyStoreCacheLoader) *KeyStoreCache {
|
|
return &KeyStoreCache{
|
|
load: load.Load,
|
|
cache: make(map[string]*list.Element),
|
|
}
|
|
}
|
|
|
|
// Get gets the key from cache, loads it from the source if needed
|
|
func (k *KeyStoreCache) Get(key string) string {
|
|
if e, ok := k.cache[key]; ok {
|
|
k.pages.MoveToFront(e)
|
|
return e.Value.(page).Value
|
|
}
|
|
// Miss - load from database and save it in cache
|
|
p := page{key, k.load(key)}
|
|
// if cache is full remove the least used item
|
|
if len(k.cache) >= CacheSize {
|
|
end := k.pages.Back()
|
|
// remove from map
|
|
delete(k.cache, end.Value.(page).Key)
|
|
// remove from list
|
|
k.pages.Remove(end)
|
|
}
|
|
k.pages.PushFront(p)
|
|
k.cache[key] = k.pages.Front()
|
|
return p.Value
|
|
}
|
|
|
|
// Loader implements KeyStoreLoader
|
|
type Loader struct {
|
|
DB *MockDB
|
|
}
|
|
|
|
// Load gets the data from the database
|
|
func (l *Loader) Load(key string) string {
|
|
val, err := l.DB.Get(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return val
|
|
}
|
|
|
|
func run() *KeyStoreCache {
|
|
loader := Loader{
|
|
DB: GetMockDB(),
|
|
}
|
|
cache := New(&loader)
|
|
|
|
RunMockServer(cache)
|
|
|
|
return cache
|
|
}
|
|
|
|
func main() {
|
|
run()
|
|
}
|