-
Notifications
You must be signed in to change notification settings - Fork 6
/
cache.go
102 lines (87 loc) · 1.79 KB
/
cache.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
95
96
97
98
99
100
101
102
// Copyright 2021 The golang.design Initiative Authors.
// All rights reserved. Use of this source code is governed
// by a MIT license that can be found in the LICENSE file.
//
// Originally written by Changkun Ou <changkun.de> at
// changkun.de/s/redir, adopted by Mai Yang <maiyang.me>.
package main
import (
"container/list"
"sync"
"time"
)
type item struct {
k, v string
}
// lru is a naive thread-safe lru cache
type lru struct {
cap uint
size uint
elems *list.List // of item
mu sync.RWMutex
}
func newLRU(doexpire bool) *lru {
l := &lru{
cap: 32, // could do it with memory quota
size: 0,
elems: list.New(),
mu: sync.RWMutex{},
}
if doexpire {
go l.clear()
}
return l
}
// clear clears the lru after a while, this is just a dirty
// solution to prevent if the database is updated but lru is
// not synced.
func (l *lru) clear() {
t := time.NewTicker(time.Minute * 5)
for range t.C {
l.flush()
}
}
func (l *lru) flush() {
l.mu.Lock()
defer l.mu.Unlock()
for e := l.elems.Front(); e != nil; e = e.Next() {
l.elems.Remove(e)
}
l.size = 0
}
func (l *lru) Len() uint {
l.mu.Lock()
defer l.mu.Unlock()
return l.size
}
func (l *lru) Get(k string) (string, bool) {
l.mu.RLock()
defer l.mu.RUnlock()
for e := l.elems.Front(); e != nil; e = e.Next() {
if e.Value.(*item).k == k {
l.elems.MoveToFront(e)
return e.Value.(*item).v, true
}
}
return "", false
}
func (l *lru) Put(k, v string) {
l.mu.Lock()
defer l.mu.Unlock()
// found from cache
i := &item{k, v}
for e := l.elems.Front(); e != nil; e = e.Next() {
if e.Value.(*item).k == k {
i.v = l.elems.Remove(e).(*item).v
l.elems.PushFront(i)
return
}
}
// check if cache is full
l.elems.PushFront(i)
if l.size+1 > l.cap {
l.elems.Remove(l.elems.Back())
} else {
l.size++
}
}