/
cache_on_storage.go
132 lines (108 loc) · 2.87 KB
/
cache_on_storage.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
package caching
// A storage implementation where a cache is layered on top of a storage. This
// implementation DOES NOT ensure data consistent between cache and storage
// when setting items.
//
// NOTE: Dropbox internally uses a different caching implementation which
// performs two-phase cache invalidation; this ensures the cached data is
// consistent with the stored data.
type CacheOnStorage struct {
cache Storage
storage Storage
}
// This returns a CacheOnStorage, which adds a cache layer on top of the
// storage.
func NewCacheOnStorage(
cache Storage,
storage Storage) Storage {
return &CacheOnStorage{
cache: cache,
storage: storage,
}
}
// See Storage for documentation.
func (s *CacheOnStorage) Get(key interface{}) (interface{}, error) {
if item, err := s.cache.Get(key); err != nil {
return nil, err
} else if item != nil {
return item, nil
}
item, err := s.storage.Get(key)
if err != nil {
return nil, err
}
if err := s.cache.Set(item); err != nil {
// XXX: Maybe make this a non error
return nil, err
}
return item, nil
}
// See Storage for documentation.
func (s *CacheOnStorage) GetMulti(
keys ...interface{}) ([]interface{}, error) {
results, err := s.cache.GetMulti(keys...)
if err != nil {
return nil, err
}
indices := make([]int, 0, len(keys))
uncachedKeys := make([]interface{}, 0, len(keys))
for i, item := range results {
if item == nil {
indices = append(indices, i)
uncachedKeys = append(uncachedKeys, keys[i])
}
}
uncachedItems, err := s.storage.GetMulti(uncachedKeys...)
if err != nil {
return nil, err
}
foundItems := make([]interface{}, 0, len(uncachedItems))
for _, item := range uncachedItems {
if item != nil {
foundItems = append(foundItems, item)
}
}
if err := s.cache.SetMulti(foundItems...); err != nil {
// XXX: Maybe make this a non error
return nil, err
}
for i, index := range indices {
results[index] = uncachedItems[i]
}
return results, nil
}
// See Storage for documentation.
func (s *CacheOnStorage) Set(item interface{}) error {
if err := s.storage.Set(item); err != nil {
return err
}
return s.cache.Set(item)
}
// See Storage for documentation.
func (s *CacheOnStorage) SetMulti(items ...interface{}) error {
if err := s.storage.SetMulti(items...); err != nil {
return err
}
return s.cache.SetMulti(items...)
}
// See Storage for documentation.
func (s *CacheOnStorage) Delete(key interface{}) error {
if err := s.storage.Delete(key); err != nil {
return err
}
return s.cache.Delete(key)
}
// See Storage for documentation.
func (s *CacheOnStorage) DeleteMulti(keys ...interface{}) error {
if err := s.storage.DeleteMulti(keys...); err != nil {
return err
}
return s.cache.DeleteMulti(keys...)
}
// See Storage for documentation.
func (s *CacheOnStorage) Flush() error {
if err := s.storage.Flush(); err != nil {
return err
}
return s.cache.Flush()
}