-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcache.go
152 lines (128 loc) · 3.57 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package gorsy_cache
import (
"fmt"
"reflect"
"sync"
"time"
)
const (
NoExpiration = -1
DefaultExpiration = 0
NoPurge = -1
DefaultPurgeInterval = 0
)
// cacheCollected collects the specific cache object constructor.
var cacheCollected = make(map[string]func() interface{})
// cacheCounter distinguish anonymous cache store
var cacheCounter int
// Cache represents a interface used by the user to r/w the cache store.
type Cache interface {
getBaseCache() *baseCache
Init()
Get(key interface{}) (interface{}, error)
GetOnlyPresent(key interface{}) (interface{}, bool)
Set(key, value interface{})
SetWithExpire(key, value interface{}, duration time.Duration)
Has(key interface{}) bool
Remove(key interface{}) bool
Keys() []interface{}
CleanExpired() int
Flush()
Len() int
}
// baseCache provides a set of common attributes. A specific cache implementation is required to inherit it.
type baseCache struct {
sync.RWMutex
size int
Name string
// expiration provides a global expiration information for a cache store.
Expiration time.Duration
// PurgeInterval specifies the expired record collection interval.
PurgeInterval time.Duration
LoaderFunc
BeforeEvictedFunc
}
type (
LoaderFunc func(key interface{}) (interface{}, error)
BeforeEvictedFunc func(key, value interface{})
)
// cacheBuilder used to build a specific cache.
type cacheBuilder struct {
cache Cache
bc *baseCache
}
// NewBuilder receive a constant cache name and a cache size, return a specific cache builder.
// A error will be returned if the specific cache is not registered or the cache implementation is invalid.
func NewBuilder(name string, size int) (*cacheBuilder, error) {
f, ok := cacheCollected[name]
if !ok {
return nil, fmt.Errorf("no specific cache was found")
}
c := f()
if err := checkCacheValid(c); err != nil {
return nil, fmt.Errorf("specific cache invalid: %s", err.Error())
}
builder := &cacheBuilder{cache: c.(Cache)}
builder.bc = builder.cache.getBaseCache()
builder.bc.size = size
return builder, nil
}
// Build a cache store by the previous setups.
// Typically it will perform some tasks such as allocating cache space.
func (c *cacheBuilder) Build() Cache {
if c.bc.Name == "" {
c.bc.Name = fmt.Sprintf("cache: %d", cacheCounter)
cacheCounter++
}
if c.bc.Expiration == DefaultExpiration {
c.bc.Expiration = 60
}
if c.bc.PurgeInterval == DefaultPurgeInterval {
c.bc.PurgeInterval = 60
}
c.cache.Init()
if c.bc.PurgeInterval != NoPurge {
_ = StartPurge(&c.cache, c.bc.PurgeInterval)
}
return c.cache
}
func (c *cacheBuilder) SetName(n string) *cacheBuilder {
c.bc.Name = n
return c
}
func (c *cacheBuilder) SetDefaultExpiration(t time.Duration) *cacheBuilder {
c.bc.Expiration = t
return c
}
func (c *cacheBuilder) SetLoaderFunc(f LoaderFunc) *cacheBuilder {
c.bc.LoaderFunc = f
return c
}
func (c *cacheBuilder) SetBeforeEvictedFunc(f BeforeEvictedFunc) *cacheBuilder {
c.bc.BeforeEvictedFunc = f
return c
}
func (c *cacheBuilder) SetPurgeInterval(t time.Duration) *cacheBuilder {
c.bc.PurgeInterval = t
return c
}
func checkCacheValid(c interface{}) error {
if !implementedCache(c) {
return fmt.Errorf("cache has not implement the Cache interface")
}
if !inheritedBaseCache(c) {
return fmt.Errorf("cache has not inherited baseCache")
}
return nil
}
func implementedCache(c interface{}) bool {
_, ok := c.(Cache)
return ok
}
func inheritedBaseCache(c interface{}) bool {
field, ok := reflect.ValueOf(c).Elem().Type().FieldByName("baseCache")
if !ok || fmt.Sprint(field.Type.Name()) != "baseCache" {
return false
}
return true
}