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

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

Issue 1152383003: Simple memory testing for gae/wrapper (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@better_context_lite
Patch Set: add go-slab dependency 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
(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 "infra/gae/libs/wrapper"
9 "infra/gae/libs/wrapper/gae/commonErrors"
10 "infra/gae/libs/wrapper/unsafe"
11 "sync"
12 "time"
13
14 "golang.org/x/net/context"
15
16 "appengine/memcache"
17 )
18
19 type memcacheData struct {
20 lock sync.Mutex
21 items map[string]*unsafe.Item
22 casID uint64
23 }
24
25 // memcacheImpl binds the current connection's memcache data to an
26 // implementation of {wrapper.Memcache, wrapper.Testable}.
27 type memcacheImpl struct {
28 wrapper.Memcache
29 wrapper.BrokenFeatures
30
31 // TODO(riannucci): bind+use namespace too
32
33 data *memcacheData
34 timeNow func() time.Time
35 }
36
37 var (
38 _ = wrapper.Memcache((*memcacheImpl)(nil))
39 _ = wrapper.Testable((*memcacheImpl)(nil))
40 )
41
42 // UseMC adds a wrapper.Memcache implementation to context, accessible
43 // by wrapper.GetMC(c)
44 func UseMC(c context.Context) context.Context {
45 lck := sync.Mutex{}
46 mcdMap := map[string]*memcacheData{}
47
48 return wrapper.SetMCFactory(c, func(ic context.Context) wrapper.Memcache {
49 lck.Lock()
50 defer lck.Unlock()
51
52 ns := curGID(ic).namespace
53 mcd, ok := mcdMap[ns]
54 if !ok {
55 mcd = &memcacheData{items: map[string]*unsafe.Item{}}
56 mcdMap[ns] = mcd
57 }
58
59 return &memcacheImpl{
60 wrapper.DummyMC(),
61 wrapper.BrokenFeatures{DefaultError: commonErrors.ErrSer verErrorMC},
62 mcd,
63 func() time.Time { return wrapper.GetTimeNow(ic) },
64 }
65 })
66 }
67
68 func (m *memcacheImpl) mkItemLocked(i *memcache.Item) *unsafe.Item {
69 m.data.casID++
70 var exp time.Duration
71 if i.Expiration != 0 {
72 exp = time.Duration(m.timeNow().Add(i.Expiration).UnixNano())
73 }
74 newItem := unsafe.Item{
75 Key: i.Key,
76 Value: make([]byte, len(i.Value)),
77 Flags: i.Flags,
78 Expiration: exp,
79 CasID: m.data.casID,
80 }
81 copy(newItem.Value, i.Value)
82 return &newItem
83 }
84
85 func copyBack(i *unsafe.Item) *memcache.Item {
86 ret := &memcache.Item{
87 Key: i.Key,
88 Value: make([]byte, len(i.Value)),
89 Flags: i.Flags,
90 }
91 copy(ret.Value, i.Value)
92 unsafe.MCSetCasID(ret, i.CasID)
93
94 return ret
95 }
96
97 func (m *memcacheImpl) retrieve(key string) (*unsafe.Item, bool) {
98 ret, ok := m.data.items[key]
99 if ok && ret.Expiration != 0 && ret.Expiration < time.Duration(m.timeNow ().UnixNano()) {
100 ret = nil
101 ok = false
102 delete(m.data.items, key)
103 }
104 return ret, ok
105 }
106
107 // Add implements context.MCSingleReadWriter.Add.
108 func (m *memcacheImpl) Add(i *memcache.Item) error {
109 if err := m.IsBroken(); err != nil {
110 return err
111 }
112
113 m.data.lock.Lock()
114 defer m.data.lock.Unlock()
115
116 if _, ok := m.retrieve(i.Key); !ok {
117 m.data.items[i.Key] = m.mkItemLocked(i)
118 return nil
119 }
120 return memcache.ErrNotStored
121 }
122
123 // CompareAndSwap implements context.MCSingleReadWriter.CompareAndSwap.
124 func (m *memcacheImpl) CompareAndSwap(item *memcache.Item) error {
125 if err := m.IsBroken(); err != nil {
126 return err
127 }
128
129 m.data.lock.Lock()
130 defer m.data.lock.Unlock()
131
132 if cur, ok := m.retrieve(item.Key); ok {
133 if cur.CasID == unsafe.MCGetCasID(item) {
134 m.data.items[item.Key] = m.mkItemLocked(item)
135 } else {
136 return memcache.ErrCASConflict
137 }
138 } else {
139 return memcache.ErrNotStored
140 }
141 return nil
142 }
143
144 // Set implements context.MCSingleReadWriter.Set.
145 func (m *memcacheImpl) Set(i *memcache.Item) error {
146 if err := m.IsBroken(); err != nil {
147 return err
148 }
149
150 m.data.lock.Lock()
151 defer m.data.lock.Unlock()
152
153 m.data.items[i.Key] = m.mkItemLocked(i)
154 return nil
155 }
156
157 // Get implements context.MCSingleReadWriter.Get.
158 func (m *memcacheImpl) Get(key string) (*memcache.Item, error) {
159 if err := m.IsBroken(); err != nil {
160 return nil, err
161 }
162
163 m.data.lock.Lock()
164 defer m.data.lock.Unlock()
165
166 if val, ok := m.retrieve(key); ok {
167 return copyBack(val), nil
168 }
169 return nil, memcache.ErrCacheMiss
170 }
171
172 // Delete implements context.MCSingleReadWriter.Delete.
173 func (m *memcacheImpl) Delete(key string) error {
174 if err := m.IsBroken(); err != nil {
175 return err
176 }
177
178 m.data.lock.Lock()
179 defer m.data.lock.Unlock()
180
181 if _, ok := m.retrieve(key); ok {
182 delete(m.data.items, key)
183 return nil
184 }
185 return memcache.ErrCacheMiss
186 }
OLDNEW
« no previous file with comments | « go/src/infra/gae/libs/wrapper/memory/key_test.go ('k') | go/src/infra/gae/libs/wrapper/memory/memcache_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698