-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmemory.go
173 lines (145 loc) · 4.28 KB
/
memory.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
MIT License
Copyright (c) 2023 Frank Oh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package echo_http_cache
import (
"sync"
"time"
)
// Algorithm is the string type for caching algorithms labels.
type Algorithm string
const (
// LRU is the constant for Least Recently Used.
LRU Algorithm = "LRU"
// MRU is the constant for Most Recently Used.
MRU Algorithm = "MRU"
// LFU is the constant for Least Frequently Used.
LFU Algorithm = "LFU"
// MFU is the constant for Most Frequently Used.
MFU Algorithm = "MFU"
)
type (
// CacheMemoryStore is the built-in store implementation for Cache
CacheMemoryStore struct {
mutex sync.RWMutex
capacity int
algorithm Algorithm
store map[uint64][]byte
}
)
func NewCacheMemoryStore() (store *CacheMemoryStore) {
return NewCacheMemoryStoreWithConfig(CacheMemoryStoreConfig{
Capacity: 10,
Algorithm: LFU,
})
}
func NewCacheMemoryStoreWithConfig(config CacheMemoryStoreConfig) (store *CacheMemoryStore) {
store = &CacheMemoryStore{}
store.capacity = config.Capacity
store.algorithm = config.Algorithm
if config.Capacity == 0 {
store.capacity = DefaultCacheMemoryStoreConfig.Capacity
}
if config.Algorithm == "" {
store.algorithm = DefaultCacheMemoryStoreConfig.Algorithm
}
store.mutex = sync.RWMutex{}
store.store = make(map[uint64][]byte, store.capacity)
return store
}
// CacheMemoryStoreConfig represents configuration for CacheMemoryStoreConfig
type CacheMemoryStoreConfig struct {
Capacity int
Algorithm Algorithm
}
// DefaultCacheMemoryStoreConfig provides default configuration values for CacheMemoryStoreConfig
var DefaultCacheMemoryStoreConfig = CacheMemoryStoreConfig{
Capacity: 10,
Algorithm: LRU,
}
// Get implements the cache Adapter interface Get method.
func (store *CacheMemoryStore) Get(key uint64) ([]byte, bool) {
store.mutex.RLock()
response, ok := store.store[key]
store.mutex.RUnlock()
if ok {
return response, true
}
return nil, false
}
// Set implements the cache Adapter interface Set method.
func (store *CacheMemoryStore) Set(key uint64, response []byte, _ time.Time) {
store.mutex.RLock()
length := len(store.store)
store.mutex.RUnlock()
if length > 0 && length == store.capacity {
store.evict()
}
store.mutex.Lock()
store.store[key] = response
store.mutex.Unlock()
}
// Release implements the Adapter interface Release method.
func (store *CacheMemoryStore) Release(key uint64) {
store.mutex.RLock()
_, ok := store.store[key]
store.mutex.RUnlock()
if ok {
store.mutex.Lock()
delete(store.store, key)
store.mutex.Unlock()
}
}
func (store *CacheMemoryStore) evict() {
selectedKey := uint64(0)
lastAccess := time.Now()
frequency := 2147483647
if store.algorithm == MRU {
lastAccess = time.Time{}
} else if store.algorithm == MFU {
frequency = 0
}
for k, v := range store.store {
r := toCacheResponse(v)
switch store.algorithm {
case LRU:
if r.LastAccess.Before(lastAccess) {
selectedKey = k
lastAccess = r.LastAccess
}
case MRU:
if r.LastAccess.After(lastAccess) ||
r.LastAccess.Equal(lastAccess) {
selectedKey = k
lastAccess = r.LastAccess
}
case LFU:
if r.Frequency < frequency {
selectedKey = k
frequency = r.Frequency
}
case MFU:
if r.Frequency >= frequency {
selectedKey = k
frequency = r.Frequency
}
}
}
store.Release(selectedKey)
}