Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: go/src/infra/gae/libs/gae/memory/memcache.go

Issue 1222903002: Refactor current GAE abstraction library to be free of the SDK* (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: fix clock usage Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package memory
6
7 import (
8 "golang.org/x/net/context"
9 "sync"
10 "time"
11
12 "infra/gae/libs/gae"
13
14 "github.com/luci/luci-go/common/clock"
15 )
16
17 type mcItem struct {
18 key string
19 value []byte
20 object interface{}
21 flags uint32
22 expiration time.Duration
23
24 CasID uint64
25 }
26
27 var _ gae.MCItem = (*mcItem)(nil)
28
29 func (m *mcItem) Key() string { return m.key }
30 func (m *mcItem) Value() []byte { return m.value }
31 func (m *mcItem) Object() interface{} { return m.object }
32 func (m *mcItem) Flags() uint32 { return m.flags }
33 func (m *mcItem) Expiration() time.Duration { return m.expiration }
34
35 func (m *mcItem) SetKey(key string) gae.MCItem {
36 m.key = key
37 return m
38 }
39 func (m *mcItem) SetValue(val []byte) gae.MCItem {
40 m.value = val
41 return m
42 }
43 func (m *mcItem) SetObject(obj interface{}) gae.MCItem {
44 m.object = obj
45 return m
46 }
47 func (m *mcItem) SetFlags(flg uint32) gae.MCItem {
48 m.flags = flg
49 return m
50 }
51 func (m *mcItem) SetExpiration(exp time.Duration) gae.MCItem {
52 m.expiration = exp
53 return m
54 }
55
56 func (m *mcItem) duplicate() *mcItem {
57 ret := mcItem{}
58 ret = *m
59 ret.value = make([]byte, len(m.value))
60 copy(ret.value, m.value)
61 return &ret
62 }
63
64 type memcacheData struct {
65 gae.BrokenFeatures
66
67 lock sync.Mutex
68 items map[string]*mcItem
69 casID uint64
70 }
71
72 // memcacheImpl binds the current connection's memcache data to an
73 // implementation of {gae.Memcache, gae.Testable}.
74 type memcacheImpl struct {
75 gae.Memcache
76
77 data *memcacheData
78 ctx context.Context
79 }
80
81 var (
82 _ = gae.Memcache((*memcacheImpl)(nil))
83 _ = gae.Testable((*memcacheImpl)(nil))
84 )
85
86 // useMC adds a gae.Memcache implementation to context, accessible
87 // by gae.GetMC(c)
88 func useMC(c context.Context) context.Context {
89 lck := sync.Mutex{}
90 mcdMap := map[string]*memcacheData{}
91
92 return gae.SetMCFactory(c, func(ic context.Context) gae.Memcache {
93 lck.Lock()
94 defer lck.Unlock()
95
96 ns := curGID(ic).namespace
97 mcd, ok := mcdMap[ns]
98 if !ok {
99 mcd = &memcacheData{
100 BrokenFeatures: gae.BrokenFeatures{
101 DefaultError: gae.ErrMCServerError},
102 items: map[string]*mcItem{}}
103 mcdMap[ns] = mcd
104 }
105
106 return &memcacheImpl{
107 gae.DummyMC(),
108 mcd,
109 ic,
110 }
111 })
112 }
113
114 func (m *memcacheImpl) mkItemLocked(i gae.MCItem) (ret *mcItem) {
115 m.data.casID++
116
117 var exp time.Duration
118 if i.Expiration() != 0 {
119 exp = time.Duration(clock.Now(m.ctx).Add(i.Expiration()).UnixNan o())
120 }
121 newItem := mcItem{
122 key: i.Key(),
123 flags: i.Flags(),
124 expiration: exp,
125 value: i.Value(),
126 CasID: m.data.casID,
127 }
128 return newItem.duplicate()
129 }
130
131 func (m *memcacheImpl) BreakFeatures(err error, features ...string) {
132 m.data.BreakFeatures(err, features...)
133 }
134
135 func (m *memcacheImpl) UnbreakFeatures(features ...string) {
136 m.data.UnbreakFeatures(features...)
137 }
138
139 func (m *memcacheImpl) NewItem(key string) gae.MCItem {
140 return &mcItem{key: key}
141 }
142
143 // Add implements context.MCSingleReadWriter.Add.
144 func (m *memcacheImpl) Add(i gae.MCItem) error {
145 return m.data.RunIfNotBroken(func() error {
146 m.data.lock.Lock()
147 defer m.data.lock.Unlock()
148
149 if _, ok := m.retrieve(i.Key()); !ok {
150 m.data.items[i.Key()] = m.mkItemLocked(i)
151 return nil
152 }
153 return gae.ErrMCNotStored
154 })
155 }
156
157 // CompareAndSwap implements context.MCSingleReadWriter.CompareAndSwap.
158 func (m *memcacheImpl) CompareAndSwap(item gae.MCItem) error {
159 return m.data.RunIfNotBroken(func() error {
160 m.data.lock.Lock()
161 defer m.data.lock.Unlock()
162
163 if cur, ok := m.retrieve(item.Key()); ok {
164 casid := uint64(0)
165 if mi, ok := item.(*mcItem); ok && mi != nil {
166 casid = mi.CasID
167 }
168
169 if cur.CasID == casid {
170 m.data.items[item.Key()] = m.mkItemLocked(item)
171 } else {
172 return gae.ErrMCCASConflict
173 }
174 } else {
175 return gae.ErrMCNotStored
176 }
177 return nil
178 })
179 }
180
181 // Set implements context.MCSingleReadWriter.Set.
182 func (m *memcacheImpl) Set(i gae.MCItem) error {
183 return m.data.RunIfNotBroken(func() error {
184 m.data.lock.Lock()
185 defer m.data.lock.Unlock()
186 m.data.items[i.Key()] = m.mkItemLocked(i)
187 return nil
188 })
189 }
190
191 // Get implements context.MCSingleReadWriter.Get.
192 func (m *memcacheImpl) Get(key string) (itm gae.MCItem, err error) {
193 err = m.data.RunIfNotBroken(func() (err error) {
194 m.data.lock.Lock()
195 defer m.data.lock.Unlock()
196 if val, ok := m.retrieve(key); ok {
197 itm = val.duplicate().SetExpiration(0)
198 } else {
199 err = gae.ErrMCCacheMiss
200 }
201 return
202 })
203 return
204 }
205
206 // Delete implements context.MCSingleReadWriter.Delete.
207 func (m *memcacheImpl) Delete(key string) error {
208 return m.data.RunIfNotBroken(func() error {
209 m.data.lock.Lock()
210 defer m.data.lock.Unlock()
211
212 if _, ok := m.retrieve(key); ok {
213 delete(m.data.items, key)
214 return nil
215 }
216 return gae.ErrMCCacheMiss
217 })
218 }
219
220 func (m *memcacheImpl) retrieve(key string) (*mcItem, bool) {
221 ret, ok := m.data.items[key]
222 if ok && ret.Expiration() != 0 && ret.Expiration() < time.Duration(clock .Now(m.ctx).UnixNano()) {
223 ret = nil
224 ok = false
225 delete(m.data.items, key)
226 }
227 return ret, ok
228 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698