-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathncache.go
More file actions
112 lines (96 loc) · 2.51 KB
/
Copy pathncache.go
File metadata and controls
112 lines (96 loc) · 2.51 KB
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
103
104
105
106
107
108
109
110
111
112
package ncache
import (
"os"
"bytes"
"sync"
"errors"
"time"
"container/list"
)
type Cache struct {
size int // Size of cache (in MB)
tracker int // Counter for tracking current size of cache
index *list.List // List of pointers to the keys
data map[interface{}]*list.Element // Hash map with the actual data
poll time.Duration
ttl int
lock sync.RWMutex
}
type key struct {
key interface{}
value interface{}
size int
birthday time.Time
popularity int
}
func New (size int, poll time.Duration, ttl int) (*Cache, error) {
if size <= 0 {
return nil, errors.New("Invalid cache size")
}
mapsize := (size * 1024 * 1024) / os.Getpagesize()
c := &Cache{
size: (size*1024*1024),
tracker: 0,
index: list.New(),
data: make(map[interface{}]*list.Element, mapsize),
poll: poll,
ttl: ttl,
}
go c.evictor(0)
return c, nil
}
func (c *Cache) Set (keyname string, value *bytes.Buffer) (success bool) {
keysize := value.Len()
if (c.tracker + keysize) >= c.size {
c.evictor(keysize)
}
c.lock.Lock()
defer c.lock.Unlock()
c.tracker += keysize
k := &key{keyname, value, value.Len(), time.Now(), 0}
c.data[keyname] = c.index.PushFront(k)
return true
}
func (c *Cache) Get (keyname string) (value interface{}, found bool) {
c.lock.RLock()
defer c.lock.RUnlock()
k, found := c.data[keyname]
if found {
return k.Value.(*key).value, true
}
return nil, false
}
func (c *Cache) freespace () (free int) {
return (c.size - c.tracker)
}
func (c *Cache) removeElement (keyname *list.Element) {
c.lock.Lock()
defer c.lock.Unlock()
c.index.Remove(keyname)
k := keyname.Value.(*key)
delete(c.data, k.key)
c.tracker -= k.size
}
func (c *Cache) removeOldest () {
k := c.index.Back()
if k != nil {
c.removeElement(k)
}
}
func (c *Cache) evictor (size int) {
if size == 0 {
for {
for i := c.index.Front(); i != nil; i = i.Next() {
keyage := time.Now().Sub(i.Value.(*key).birthday).Seconds()
if int(keyage) >= c.ttl {
c.removeElement(i)
}
}
time.Sleep(c.poll * time.Second)
}
} else {
for c.freespace() < size {
c.removeOldest()
}
}
}