forked from orca-zhang/lrucache
-
Notifications
You must be signed in to change notification settings - Fork 0
/
synccache.go
99 lines (90 loc) · 2.11 KB
/
synccache.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
package lrucache
import (
"hash/crc32"
"sync"
"time"
)
// hashCode hashes a string to a unique hashcode.
//
// crc32 returns a uint32, but for our use we need
// and non negative integer. Here we cast to an integer
// and invert it if the result is negative.
func hashCode(s string) (hc int) {
hc = int(crc32.ChecksumIEEE([]byte(s)))
if hc >= 0 {
return hc
}
if -hc >= 0 {
return -hc
}
// hc == MinInt
return hc
}
// SyncCache - concurrent cache structure
type SyncCache struct {
locks []sync.Mutex
caches []*LRUCache
mask int
timeout int64
}
type scValue struct {
Value interface{}
ts int64
}
func nextPowOf2(cap int) int {
if cap < 2 {
return 2
}
if cap&(cap-1) == 0 {
return cap
}
cap |= cap >> 1
cap |= cap >> 2
cap |= cap >> 4
cap |= cap >> 8
cap |= cap >> 16
return cap + 1
}
// NewSyncCache - create sync cache
// `capacity` is lru cache length of each bucket
// store `capacity * bucket` count of element in SyncCache at most
// `timeout` is in seconds
func NewSyncCache(capacity int, bucket int, timeout int64) *SyncCache {
size := nextPowOf2(bucket)
sc := SyncCache{make([]sync.Mutex, size), make([]*LRUCache, size), size - 1, timeout}
for i := range sc.caches {
sc.caches[i] = New(capacity)
}
return &sc
}
// Put - put a cache item into sync cache
func (sc *SyncCache) Put(key string, value interface{}) {
idx := hashCode(key) & sc.mask
sc.locks[idx].Lock()
sc.caches[idx].Put(key, &scValue{value, time.Now().Unix()})
sc.locks[idx].Unlock()
}
// Get - get value of key from sync cache with result
func (sc *SyncCache) Get(key string) (interface{}, bool) {
idx := hashCode(key) & sc.mask
sc.locks[idx].Lock()
v, b := sc.caches[idx].Get(key)
if !b {
sc.locks[idx].Unlock()
return nil, false
}
if time.Now().Unix()-v.(*scValue).ts >= sc.timeout {
sc.caches[idx].Delete(key)
sc.locks[idx].Unlock()
return nil, false
}
sc.locks[idx].Unlock()
return v.(*scValue).Value, b
}
// Delete - delete item by key from sync cache
func (sc *SyncCache) Delete(key string) {
idx := hashCode(key) & sc.mask
sc.locks[idx].Lock()
sc.caches[idx].Delete(key)
sc.locks[idx].Unlock()
}