@@ -3,17 +3,25 @@ package cache
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
+ "strings"
6
7
"time"
7
8
8
9
"github.com/gomodule/redigo/redis"
9
10
)
10
11
12
+ // ReferenceKeyForever Forever reference key.
13
+ const ReferenceKeyForever = "forever_ref"
14
+
15
+ // ReferenceKeyStandard Standard reference key.
16
+ const ReferenceKeyStandard = "standard_ref"
17
+
11
18
type RedisStore struct {
12
19
pool * redis.Pool // redis connection pool
20
+ tagSet * TagSet
13
21
prefix string
14
22
}
15
23
16
- // NewStore Create a redis cache store
24
+ // NewRedisStore Create a redis cache store
17
25
func NewRedisStore (pool * redis.Pool , prefix string ) * RedisStore {
18
26
s := RedisStore {}
19
27
return s .SetPool (pool ).SetPrefix (prefix )
@@ -38,6 +46,12 @@ func (s *RedisStore) Put(key string, val interface{}, timeout time.Duration) err
38
46
if err != nil {
39
47
return err
40
48
}
49
+
50
+ err = s .pushStandardKeys (key )
51
+ if err != nil {
52
+ return err
53
+ }
54
+
41
55
c := s .pool .Get ()
42
56
defer c .Close ()
43
57
_ , err = c .Do ("SETEX" , s .prefix + key , int64 (timeout / time .Second ), string (b ))
@@ -46,6 +60,11 @@ func (s *RedisStore) Put(key string, val interface{}, timeout time.Duration) err
46
60
47
61
// Increment the value of an item in the cache.
48
62
func (s * RedisStore ) Increment (key string , value ... int ) (int , error ) {
63
+ err := s .pushStandardKeys (key )
64
+ if err != nil {
65
+ return 0 , err
66
+ }
67
+
49
68
c := s .pool .Get ()
50
69
defer c .Close ()
51
70
@@ -59,6 +78,11 @@ func (s *RedisStore) Increment(key string, value ...int) (int, error) {
59
78
60
79
// Decrement the value of an item in the cache.
61
80
func (s * RedisStore ) Decrement (key string , value ... int ) (int , error ) {
81
+ err := s .pushStandardKeys (key )
82
+ if err != nil {
83
+ return 0 , err
84
+ }
85
+
62
86
c := s .pool .Get ()
63
87
defer c .Close ()
64
88
@@ -70,6 +94,24 @@ func (s *RedisStore) Decrement(key string, value ...int) (int, error) {
70
94
return redis .Int (c .Do ("DECRBY" , s .prefix + key , by ))
71
95
}
72
96
97
+ // Forever Store an item in the cache indefinitely.
98
+ func (s * RedisStore ) Forever (key string , val interface {}) error {
99
+ b , err := json .Marshal (val )
100
+ if err != nil {
101
+ return err
102
+ }
103
+
104
+ err = s .pushForeverKeys (key )
105
+ if err != nil {
106
+ return err
107
+ }
108
+
109
+ c := s .pool .Get ()
110
+ defer c .Close ()
111
+ _ , err = c .Do ("SET" , s .prefix + key , string (b ))
112
+ return err
113
+ }
114
+
73
115
// Exist check cache's existence in redis.
74
116
func (s * RedisStore ) Exist (key string ) bool {
75
117
c := s .pool .Get ()
@@ -100,6 +142,26 @@ func (s *RedisStore) Forget(key string) error {
100
142
101
143
// Remove all items from the cache.
102
144
func (s * RedisStore ) Flush () error {
145
+ if s .tagSet != nil {
146
+ err := s .deleteForeverKeys ()
147
+ if err != nil {
148
+ return err
149
+ }
150
+ err = s .deleteStandardKeys ()
151
+ if err != nil {
152
+ return err
153
+ }
154
+ err = s .tagSet .Reset ()
155
+ if err != nil {
156
+ return err
157
+ }
158
+ return nil
159
+ }
160
+
161
+ return s .flush ()
162
+ }
163
+
164
+ func (s * RedisStore ) flush () error {
103
165
c := s .pool .Get ()
104
166
defer c .Close ()
105
167
@@ -121,12 +183,34 @@ func (s *RedisStore) Flush() error {
121
183
break
122
184
}
123
185
}
124
- for _ , key := range keys {
125
- if _ , err = c .Do ("DEL" , key ); err != nil {
126
- return err
186
+
187
+ length := len (keys )
188
+ if length == 0 {
189
+ return nil
190
+ }
191
+
192
+ var keysChunk []interface {}
193
+ for i , key := range keys {
194
+ keysChunk = append (keysChunk , key )
195
+ if i == length - 1 || len (keysChunk ) == 1000 {
196
+ _ , err = c .Do ("DEL" , keysChunk ... )
197
+ if err != nil {
198
+ return err
199
+ }
127
200
}
128
201
}
129
- return err
202
+
203
+ return nil
204
+ }
205
+
206
+ func (s * RedisStore ) Tags (names ... string ) Store {
207
+ if len (names ) == 0 {
208
+ return s
209
+ }
210
+ ss := s .clone ()
211
+ ss .tagSet = NewTagSet (s , names )
212
+
213
+ return ss
130
214
}
131
215
132
216
func (s * RedisStore ) TTL (key string ) (int64 , error ) {
@@ -156,3 +240,108 @@ func (s *RedisStore) SetPrefix(prefix string) *RedisStore {
156
240
}
157
241
return s
158
242
}
243
+
244
+ func (s * RedisStore ) clone () * RedisStore {
245
+ return & RedisStore {
246
+ pool : s .pool ,
247
+ prefix : s .prefix ,
248
+ }
249
+ }
250
+
251
+ func (s * RedisStore ) pushStandardKeys (key string ) error {
252
+ return s .pushKeys (key , ReferenceKeyStandard )
253
+ }
254
+
255
+ func (s * RedisStore ) pushForeverKeys (key string ) error {
256
+ return s .pushKeys (key , ReferenceKeyForever )
257
+ }
258
+
259
+ func (s * RedisStore ) pushKeys (key , reference string ) error {
260
+ if s .tagSet == nil {
261
+ return nil
262
+ }
263
+
264
+ namespace , err := s .tagSet .GetNamespace ()
265
+ if err != nil {
266
+ return err
267
+ }
268
+
269
+ fullKey := s .prefix + key
270
+ segments := strings .Split (namespace , "|" )
271
+
272
+ c := s .pool .Get ()
273
+ defer c .Close ()
274
+ for _ , segment := range segments {
275
+ _ , err = c .Do ("SADD" , s .referenceKey (segment , reference ), fullKey )
276
+ if err != nil {
277
+ return err
278
+ }
279
+ }
280
+ return nil
281
+ }
282
+
283
+ func (s * RedisStore ) deleteStandardKeys () error {
284
+ return s .deleteKeysByReference (ReferenceKeyStandard )
285
+ }
286
+
287
+ func (s * RedisStore ) deleteForeverKeys () error {
288
+ return s .deleteKeysByReference (ReferenceKeyForever )
289
+ }
290
+
291
+ func (s * RedisStore ) deleteKeysByReference (reference string ) error {
292
+ if s .tagSet == nil {
293
+ return nil
294
+ }
295
+
296
+ namespace , err := s .tagSet .GetNamespace ()
297
+ if err != nil {
298
+ return err
299
+ }
300
+ segments := strings .Split (namespace , "|" )
301
+ c := s .pool .Get ()
302
+ defer c .Close ()
303
+
304
+ for _ , segment := range segments {
305
+ segment = s .referenceKey (segment , reference )
306
+ err = s .deleteKeys (segment )
307
+ if err != nil {
308
+ return err
309
+ }
310
+ _ , err = c .Do ("DEL" , segment )
311
+ if err != nil {
312
+ return err
313
+ }
314
+ }
315
+
316
+ return nil
317
+ }
318
+
319
+ func (s * RedisStore ) deleteKeys (referenceKey string ) error {
320
+ c := s .pool .Get ()
321
+ defer c .Close ()
322
+ keys , err := redis .Strings (c .Do ("SMEMBERS" , referenceKey ))
323
+ if err != nil {
324
+ return err
325
+ }
326
+ var length = len (keys )
327
+ if length == 0 {
328
+ return nil
329
+ }
330
+
331
+ var keysChunk []interface {}
332
+ for i , key := range keys {
333
+ keysChunk = append (keysChunk , key )
334
+ if i == length - 1 || len (keysChunk ) == 1000 {
335
+ _ , err = c .Do ("DEL" , keysChunk ... )
336
+ if err != nil {
337
+ return err
338
+ }
339
+ }
340
+ }
341
+
342
+ return nil
343
+ }
344
+
345
+ func (s * RedisStore ) referenceKey (segment , suffix string ) string {
346
+ return s .prefix + segment + ":" + suffix
347
+ }
0 commit comments