This repository has been archived by the owner on Dec 10, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
/
cache.go
125 lines (101 loc) · 2.44 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
package cache
import (
"errors"
"log"
"reflect"
"sync/atomic"
"time"
"github.com/danjac/podbaby/cmd/Godeps/_workspace/src/gopkg.in/go-redis/cache.v1/lrucache"
"github.com/danjac/podbaby/cmd/Godeps/_workspace/src/gopkg.in/redis.v3"
)
const defaultExpiration = 3 * 24 * time.Hour
var (
ErrCacheMiss = errors.New("rediscache: cache miss")
)
type Codec struct {
Ring *redis.Ring
// Local LRU cache for hot items.
Cache *lrucache.Cache
Marshal func(interface{}) ([]byte, error)
Unmarshal func([]byte, interface{}) error
hits, misses int64
}
type Item struct {
Key string
Object interface{}
// Expiration is the cache expiration time.
// Zero means the Item has no expiration time.
Expiration time.Duration
// Disables local LRU cache when set to true.
DisableLocalCache bool
}
func (cd *Codec) Set(item *Item) error {
if item.Expiration != 0 && item.Expiration < time.Second {
panic("Expiration can't be less than 1 second")
}
if !item.DisableLocalCache && cd.Cache != nil {
cd.Cache.Set(item.Key, item.Object)
}
b, err := cd.Marshal(item.Object)
if err != nil {
log.Printf("cache: Marshal failed: %s", err)
return err
}
_, err = cd.Ring.Set(item.Key, b, item.Expiration).Result()
if err != nil {
log.Printf("cache: Set %s failed: %s", item.Key, err)
}
return err
}
func (cd *Codec) Get(key string, v interface{}) error {
if cd.Cache != nil {
elem, ok := cd.Cache.Get(key)
if ok {
ev := reflect.ValueOf(elem)
if ev.Type().Kind() == reflect.Ptr {
ev = ev.Elem()
}
reflect.ValueOf(v).Elem().Set(ev)
return nil
}
}
b, err := cd.Ring.Get(key).Bytes()
if err == redis.Nil {
atomic.AddInt64(&cd.misses, 1)
return ErrCacheMiss
} else if err != nil {
log.Printf("cache: Get %s failed: %s", key, err)
atomic.AddInt64(&cd.hits, 1)
return err
}
if err := cd.Unmarshal(b, v); err != nil {
log.Printf("cache: Unmarshal failed: %s", err)
atomic.AddInt64(&cd.hits, 1)
return err
}
if cd.Cache != nil {
cd.Cache.Set(key, v)
}
atomic.AddInt64(&cd.hits, 1)
return nil
}
func (cd *Codec) Delete(key string) error {
if cd.Cache != nil {
cd.Cache.Delete(key)
}
deleted, err := cd.Ring.Del(key).Result()
if err != nil {
log.Printf("cache: Del %s failed: %s", key, err)
return err
}
if deleted == 0 {
return ErrCacheMiss
}
return nil
}
func (cd *Codec) Hits() int {
return int(atomic.LoadInt64(&cd.hits))
}
func (cd *Codec) Misses() int {
return int(atomic.LoadInt64(&cd.misses))
}