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

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: fixes Created 5 years, 7 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
M-A Ruel 2015/05/28 22:42:38 Why a pointer?
iannucci 2015/05/28 23:00:35 gone
30
31 // TODO(riannucci): bind+use namespace too
32
33 data *memcacheData
34 timeNow func() time.Time
35 }
36
37 // UseMC adds a wrapper.Memcache implementation to context, accessible
38 // by wrapper.GetMC(c)
39 func UseMC(c context.Context) context.Context {
40 lck := sync.Mutex{}
41 mcdMap := map[string]*memcacheData{}
42
43 return wrapper.SetMCFactory(c, func(ic context.Context) wrapper.Memcache {
44 lck.Lock()
45 defer lck.Unlock()
46
47 ns := curGID(ic).namespace
48 mcd, ok := mcdMap[ns]
49 if !ok {
50 mcd = &memcacheData{items: map[string]*unsafe.Item{}}
51 mcdMap[ns] = mcd
52 }
53
54 return &memcacheImpl{
55 wrapper.DummyMC(),
56 &wrapper.BrokenFeatures{DefaultError: commonErrors.ErrSe rverErrorMC},
57 mcd,
58 func() time.Time { return wrapper.GetTimeNow(ic) },
59 }
60 })
61 }
62
63 func (m *memcacheImpl) mkItem(i *memcache.Item) *unsafe.Item {
64 m.data.casID++
M-A Ruel 2015/05/28 22:42:38 Not thread safe.
iannucci 2015/05/28 23:00:35 renamed method, only (supposed) to be called from
65 var exp time.Duration
66 if i.Expiration != 0 {
67 exp = time.Duration(m.timeNow().Add(i.Expiration).UnixNano())
68 }
69 newItem := unsafe.Item{
70 Key: i.Key,
71 Value: make([]byte, len(i.Value)),
72 Flags: i.Flags,
73 Expiration: exp,
74 CasID: m.data.casID,
75 }
76 copy(newItem.Value, i.Value)
77 return &newItem
78 }
79
80 func copyBack(i *unsafe.Item) *memcache.Item {
81 ret := &memcache.Item{
82 Key: i.Key,
83 Value: make([]byte, len(i.Value)),
84 Flags: i.Flags,
85 }
86 copy(ret.Value, i.Value)
87 unsafe.MCSetCasID(ret, i.CasID)
88
89 return ret
90 }
91
92 func (m *memcacheImpl) retrieve(key string) (*unsafe.Item, bool) {
93 ret, ok := m.data.items[key]
94 if ok && ret.Expiration != 0 && ret.Expiration < time.Duration(m.timeNow ().UnixNano()) {
95 ret = nil
96 ok = false
97 delete(m.data.items, key)
98 }
99 return ret, ok
100 }
101
102 // Add implements context.MCSingleReadWriter.Add.
103 func (m *memcacheImpl) Add(i *memcache.Item) error {
104 if err := m.IsBroken(); err != nil {
105 return err
106 }
107
108 m.data.lock.Lock()
109 defer m.data.lock.Unlock()
110
111 if _, ok := m.retrieve(i.Key); !ok {
112 m.data.items[i.Key] = m.mkItem(i)
113 return nil
114 }
115 return memcache.ErrNotStored
116 }
117
118 // CompareAndSwap implements context.MCSingleReadWriter.CompareAndSwap.
119 func (m *memcacheImpl) CompareAndSwap(item *memcache.Item) error {
120 if err := m.IsBroken(); err != nil {
121 return err
122 }
123
124 m.data.lock.Lock()
125 defer m.data.lock.Unlock()
126
127 if cur, ok := m.retrieve(item.Key); ok {
128 if cur.CasID == unsafe.MCGetCasID(item) {
129 m.data.items[item.Key] = m.mkItem(item)
130 } else {
131 return memcache.ErrCASConflict
132 }
133 } else {
134 return memcache.ErrNotStored
135 }
136 return nil
137 }
138
139 // Set implements context.MCSingleReadWriter.Set.
140 func (m *memcacheImpl) Set(i *memcache.Item) error {
141 if err := m.IsBroken(); err != nil {
142 return err
143 }
144
145 m.data.items[i.Key] = m.mkItem(i)
146 return nil
147 }
148
149 // Get implements context.MCSingleReadWriter.Get.
150 func (m *memcacheImpl) Get(key string) (*memcache.Item, error) {
151 if err := m.IsBroken(); err != nil {
152 return nil, err
153 }
154
155 m.data.lock.Lock()
156 defer m.data.lock.Unlock()
157
158 if val, ok := m.retrieve(key); ok {
159 return copyBack(val), nil
160 }
161 return nil, memcache.ErrCacheMiss
162 }
163
164 // Delete implements context.MCSingleReadWriter.Delete.
165 func (m *memcacheImpl) Delete(key string) error {
166 if err := m.IsBroken(); err != nil {
167 return err
168 }
169
170 m.data.lock.Lock()
171 defer m.data.lock.Unlock()
172
173 if _, ok := m.retrieve(key); ok {
174 delete(m.data.items, key)
175 return nil
176 }
177 return memcache.ErrCacheMiss
178 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698