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

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

Issue 986553002: A simple memcache lock for appengine. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@meta
Patch Set: remove unnecessary log, use blackhole logger Created 5 years, 6 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package memory 5 package memory
6 6
7 import ( 7 import (
8 "infra/gae/libs/wrapper" 8 "infra/gae/libs/wrapper"
9 "infra/gae/libs/wrapper/gae/commonErrors" 9 "infra/gae/libs/wrapper/gae/commonErrors"
10 "infra/gae/libs/wrapper/unsafe" 10 "infra/gae/libs/wrapper/unsafe"
11 "sync" 11 "sync"
12 "time" 12 "time"
13 13
14 "golang.org/x/net/context" 14 "golang.org/x/net/context"
15 15
16 "appengine/memcache" 16 "appengine/memcache"
17 ) 17 )
18 18
19 type memcacheData struct { 19 type memcacheData struct {
20 wrapper.BrokenFeatures
21
20 lock sync.Mutex 22 lock sync.Mutex
21 items map[string]*unsafe.Item 23 items map[string]*unsafe.Item
22 casID uint64 24 casID uint64
23 } 25 }
24 26
25 // memcacheImpl binds the current connection's memcache data to an 27 // memcacheImpl binds the current connection's memcache data to an
26 // implementation of {wrapper.Memcache, wrapper.Testable}. 28 // implementation of {wrapper.Memcache, wrapper.Testable}.
27 type memcacheImpl struct { 29 type memcacheImpl struct {
28 wrapper.Memcache 30 wrapper.Memcache
29 wrapper.BrokenFeatures
30
31 // TODO(riannucci): bind+use namespace too
iannucci 2015/05/31 09:34:04 this comment was wrong (we already bind the namesp
32 31
33 data *memcacheData 32 data *memcacheData
34 timeNow func() time.Time 33 timeNow func() time.Time
35 } 34 }
36 35
37 var ( 36 var (
38 _ = wrapper.Memcache((*memcacheImpl)(nil)) 37 _ = wrapper.Memcache((*memcacheImpl)(nil))
39 _ = wrapper.Testable((*memcacheImpl)(nil)) 38 _ = wrapper.Testable((*memcacheImpl)(nil))
40 ) 39 )
41 40
42 // useMC adds a wrapper.Memcache implementation to context, accessible 41 // useMC adds a wrapper.Memcache implementation to context, accessible
43 // by wrapper.GetMC(c) 42 // by wrapper.GetMC(c)
44 func useMC(c context.Context) context.Context { 43 func useMC(c context.Context) context.Context {
45 lck := sync.Mutex{} 44 lck := sync.Mutex{}
46 mcdMap := map[string]*memcacheData{} 45 mcdMap := map[string]*memcacheData{}
47 46
48 return wrapper.SetMCFactory(c, func(ic context.Context) wrapper.Memcache { 47 return wrapper.SetMCFactory(c, func(ic context.Context) wrapper.Memcache {
49 lck.Lock() 48 lck.Lock()
50 defer lck.Unlock() 49 defer lck.Unlock()
51 50
52 ns := curGID(ic).namespace 51 ns := curGID(ic).namespace
53 mcd, ok := mcdMap[ns] 52 mcd, ok := mcdMap[ns]
54 if !ok { 53 if !ok {
55 » » » mcd = &memcacheData{items: map[string]*unsafe.Item{}} 54 » » » mcd = &memcacheData{
55 » » » » BrokenFeatures: wrapper.BrokenFeatures{
56 » » » » » DefaultError: commonErrors.ErrServerErro rMC},
57 » » » » items: map[string]*unsafe.Item{}}
56 mcdMap[ns] = mcd 58 mcdMap[ns] = mcd
57 } 59 }
58 60
59 return &memcacheImpl{ 61 return &memcacheImpl{
60 wrapper.DummyMC(), 62 wrapper.DummyMC(),
61 wrapper.BrokenFeatures{DefaultError: commonErrors.ErrSer verErrorMC},
62 mcd, 63 mcd,
63 func() time.Time { return wrapper.GetTimeNow(ic) }, 64 func() time.Time { return wrapper.GetTimeNow(ic) },
64 } 65 }
65 }) 66 })
66 } 67 }
67 68
68 func (m *memcacheImpl) mkItemLocked(i *memcache.Item) *unsafe.Item { 69 func (m *memcacheImpl) mkItemLocked(i *memcache.Item) *unsafe.Item {
69 m.data.casID++ 70 m.data.casID++
70 var exp time.Duration 71 var exp time.Duration
71 if i.Expiration != 0 { 72 if i.Expiration != 0 {
(...skipping 25 matching lines...) Expand all
97 func (m *memcacheImpl) retrieve(key string) (*unsafe.Item, bool) { 98 func (m *memcacheImpl) retrieve(key string) (*unsafe.Item, bool) {
98 ret, ok := m.data.items[key] 99 ret, ok := m.data.items[key]
99 if ok && ret.Expiration != 0 && ret.Expiration < time.Duration(m.timeNow ().UnixNano()) { 100 if ok && ret.Expiration != 0 && ret.Expiration < time.Duration(m.timeNow ().UnixNano()) {
100 ret = nil 101 ret = nil
101 ok = false 102 ok = false
102 delete(m.data.items, key) 103 delete(m.data.items, key)
103 } 104 }
104 return ret, ok 105 return ret, ok
105 } 106 }
106 107
108 func (m *memcacheImpl) BreakFeatures(err error, features ...string) {
109 m.data.BreakFeatures(err, features...)
110 }
111
112 func (m *memcacheImpl) UnbreakFeatures(features ...string) {
113 m.data.UnbreakFeatures(features...)
114 }
115
107 // Add implements context.MCSingleReadWriter.Add. 116 // Add implements context.MCSingleReadWriter.Add.
108 func (m *memcacheImpl) Add(i *memcache.Item) error { 117 func (m *memcacheImpl) Add(i *memcache.Item) error {
109 » if err := m.IsBroken(); err != nil { 118 » if err := m.data.IsBroken(); err != nil {
110 return err 119 return err
111 } 120 }
112 121
113 m.data.lock.Lock() 122 m.data.lock.Lock()
114 defer m.data.lock.Unlock() 123 defer m.data.lock.Unlock()
115 124
116 if _, ok := m.retrieve(i.Key); !ok { 125 if _, ok := m.retrieve(i.Key); !ok {
117 m.data.items[i.Key] = m.mkItemLocked(i) 126 m.data.items[i.Key] = m.mkItemLocked(i)
118 return nil 127 return nil
119 } 128 }
120 return memcache.ErrNotStored 129 return memcache.ErrNotStored
121 } 130 }
122 131
123 // CompareAndSwap implements context.MCSingleReadWriter.CompareAndSwap. 132 // CompareAndSwap implements context.MCSingleReadWriter.CompareAndSwap.
124 func (m *memcacheImpl) CompareAndSwap(item *memcache.Item) error { 133 func (m *memcacheImpl) CompareAndSwap(item *memcache.Item) error {
125 » if err := m.IsBroken(); err != nil { 134 » if err := m.data.IsBroken(); err != nil {
126 return err 135 return err
127 } 136 }
128 137
129 m.data.lock.Lock() 138 m.data.lock.Lock()
130 defer m.data.lock.Unlock() 139 defer m.data.lock.Unlock()
131 140
132 if cur, ok := m.retrieve(item.Key); ok { 141 if cur, ok := m.retrieve(item.Key); ok {
133 if cur.CasID == unsafe.MCGetCasID(item) { 142 if cur.CasID == unsafe.MCGetCasID(item) {
134 m.data.items[item.Key] = m.mkItemLocked(item) 143 m.data.items[item.Key] = m.mkItemLocked(item)
135 } else { 144 } else {
136 return memcache.ErrCASConflict 145 return memcache.ErrCASConflict
137 } 146 }
138 } else { 147 } else {
139 return memcache.ErrNotStored 148 return memcache.ErrNotStored
140 } 149 }
141 return nil 150 return nil
142 } 151 }
143 152
144 // Set implements context.MCSingleReadWriter.Set. 153 // Set implements context.MCSingleReadWriter.Set.
145 func (m *memcacheImpl) Set(i *memcache.Item) error { 154 func (m *memcacheImpl) Set(i *memcache.Item) error {
146 » if err := m.IsBroken(); err != nil { 155 » if err := m.data.IsBroken(); err != nil {
147 return err 156 return err
148 } 157 }
149 158
150 m.data.lock.Lock() 159 m.data.lock.Lock()
151 defer m.data.lock.Unlock() 160 defer m.data.lock.Unlock()
152 161
153 m.data.items[i.Key] = m.mkItemLocked(i) 162 m.data.items[i.Key] = m.mkItemLocked(i)
154 return nil 163 return nil
155 } 164 }
156 165
157 // Get implements context.MCSingleReadWriter.Get. 166 // Get implements context.MCSingleReadWriter.Get.
158 func (m *memcacheImpl) Get(key string) (*memcache.Item, error) { 167 func (m *memcacheImpl) Get(key string) (*memcache.Item, error) {
159 » if err := m.IsBroken(); err != nil { 168 » if err := m.data.IsBroken(); err != nil {
160 return nil, err 169 return nil, err
161 } 170 }
162 171
163 m.data.lock.Lock() 172 m.data.lock.Lock()
164 defer m.data.lock.Unlock() 173 defer m.data.lock.Unlock()
165 174
166 if val, ok := m.retrieve(key); ok { 175 if val, ok := m.retrieve(key); ok {
167 return copyBack(val), nil 176 return copyBack(val), nil
168 } 177 }
169 return nil, memcache.ErrCacheMiss 178 return nil, memcache.ErrCacheMiss
170 } 179 }
171 180
172 // Delete implements context.MCSingleReadWriter.Delete. 181 // Delete implements context.MCSingleReadWriter.Delete.
173 func (m *memcacheImpl) Delete(key string) error { 182 func (m *memcacheImpl) Delete(key string) error {
174 » if err := m.IsBroken(); err != nil { 183 » if err := m.data.IsBroken(); err != nil {
175 return err 184 return err
176 } 185 }
177 186
178 m.data.lock.Lock() 187 m.data.lock.Lock()
179 defer m.data.lock.Unlock() 188 defer m.data.lock.Unlock()
180 189
181 if _, ok := m.retrieve(key); ok { 190 if _, ok := m.retrieve(key); ok {
182 delete(m.data.items, key) 191 delete(m.data.items, key)
183 return nil 192 return nil
184 } 193 }
185 return memcache.ErrCacheMiss 194 return memcache.ErrCacheMiss
186 } 195 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698