This repository has been archived by the owner on Apr 9, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
/
local_cache.go
122 lines (105 loc) · 2.08 KB
/
local_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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package stormpath
import (
"sync"
"time"
)
type cacheItem struct {
sync.RWMutex
data []byte
expires *time.Time
}
func (item *cacheItem) touch(duration time.Duration) {
item.Lock()
expiration := time.Now().Add(duration)
item.expires = &expiration
item.Unlock()
}
func (item *cacheItem) expired() bool {
var value bool
item.RLock()
if item.expires == nil {
value = true
} else {
value = item.expires.Before(time.Now())
}
item.RUnlock()
return value
}
type LocalCache struct {
mutex sync.RWMutex
ttl time.Duration
tti time.Duration
items map[string]*cacheItem
}
func (cache *LocalCache) Set(key string, data []byte) {
cache.mutex.Lock()
defer cache.mutex.Unlock()
item := &cacheItem{data: data}
item.touch(cache.ttl)
cache.items[key] = item
}
func (cache *LocalCache) Get(key string) []byte {
cache.mutex.Lock()
defer cache.mutex.Unlock()
item, exists := cache.items[key]
if exists && !item.expired() {
item.touch(cache.tti)
return item.data
}
return []byte{}
}
func (cache *LocalCache) Del(key string) {
cache.mutex.Lock()
defer cache.mutex.Unlock()
delete(cache.items, key)
}
func (cache *LocalCache) Exists(key string) bool {
_, exists := cache.items[key]
return exists
}
// Count returns the number of items in the cache
// (helpful for tracking memory leaks)
func (cache *LocalCache) Count() int {
cache.mutex.RLock()
count := len(cache.items)
cache.mutex.RUnlock()
return count
}
func (cache *LocalCache) cleanup() {
cache.mutex.Lock()
for key, item := range cache.items {
if item.expired() {
delete(cache.items, key)
}
}
cache.mutex.Unlock()
}
func (cache *LocalCache) startCleanupTimer() {
ttlTicker := time.Tick(cache.ttl)
go (func() {
for {
select {
case <-ttlTicker:
cache.cleanup()
}
}
})()
ttiTicker := time.Tick(cache.tti)
go (func() {
for {
select {
case <-ttiTicker:
cache.cleanup()
}
}
})()
}
func NewLocalCache(ttl time.Duration, tti time.Duration) *LocalCache {
cache := &LocalCache{
ttl: ttl,
tti: tti,
items: map[string]*cacheItem{},
}
cache.startCleanupTimer()
return cache
}