-
Notifications
You must be signed in to change notification settings - Fork 352
/
main.go
94 lines (79 loc) · 2.02 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//////////////////////////////////////////////////////////////////////
//
// 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"
"testing"
)
// 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(t *testing.T) (*KeyStoreCache, *MockDB) {
loader := Loader{
DB: GetMockDB(),
}
cache := New(&loader)
RunMockServer(cache, t)
return cache, loader.DB
}
func main() {
run(nil)
}