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

Side by Side Diff: go/src/infra/gae/libs/wrapper/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: more fixes 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 "infra/gae/libs/wrapper"
9 "infra/gae/libs/wrapper/gae/commonErrors"
10 "infra/gae/libs/wrapper/unsafe"
11 "infra/libs/clock"
12 "sync"
13 "time"
14
15 "golang.org/x/net/context"
16
17 "appengine/memcache"
18 )
19
20 type memcacheData struct {
21 wrapper.BrokenFeatures
22
23 lock sync.Mutex
24 items map[string]*unsafe.Item
25 casID uint64
26 }
27
28 // memcacheImpl binds the current connection's memcache data to an
29 // implementation of {wrapper.Memcache, wrapper.Testable}.
30 type memcacheImpl struct {
31 wrapper.Memcache
32
33 data *memcacheData
34 ctx context.Context
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{
56 BrokenFeatures: wrapper.BrokenFeatures{
57 DefaultError: commonErrors.ErrServerErro rMC},
58 items: map[string]*unsafe.Item{}}
59 mcdMap[ns] = mcd
60 }
61
62 return &memcacheImpl{
63 wrapper.DummyMC(),
64 mcd,
65 ic,
66 }
67 })
68 }
69
70 func (m *memcacheImpl) mkItemLocked(i *memcache.Item) *unsafe.Item {
71 m.data.casID++
72 var exp time.Duration
73 if i.Expiration != 0 {
74 exp = time.Duration(clock.Now(m.ctx).Add(i.Expiration).UnixNano( ))
75 }
76 newItem := unsafe.Item{
77 Key: i.Key,
78 Value: make([]byte, len(i.Value)),
79 Flags: i.Flags,
80 Expiration: exp,
81 CasID: m.data.casID,
82 }
83 copy(newItem.Value, i.Value)
84 return &newItem
85 }
86
87 func copyBack(i *unsafe.Item) *memcache.Item {
88 ret := &memcache.Item{
89 Key: i.Key,
90 Value: make([]byte, len(i.Value)),
91 Flags: i.Flags,
92 }
93 copy(ret.Value, i.Value)
94 unsafe.MCSetCasID(ret, i.CasID)
95
96 return ret
97 }
98
99 func (m *memcacheImpl) retrieve(key string) (*unsafe.Item, bool) {
100 ret, ok := m.data.items[key]
101 if ok && ret.Expiration != 0 && ret.Expiration < time.Duration(clock.Now (m.ctx).UnixNano()) {
102 ret = nil
103 ok = false
104 delete(m.data.items, key)
105 }
106 return ret, ok
107 }
108
109 func (m *memcacheImpl) BreakFeatures(err error, features ...string) {
110 m.data.BreakFeatures(err, features...)
111 }
112
113 func (m *memcacheImpl) UnbreakFeatures(features ...string) {
114 m.data.UnbreakFeatures(features...)
115 }
116
117 // Add implements context.MCSingleReadWriter.Add.
118 func (m *memcacheImpl) Add(i *memcache.Item) error {
119 if err := m.data.IsBroken(); err != nil {
120 return err
121 }
122
123 m.data.lock.Lock()
124 defer m.data.lock.Unlock()
125
126 if _, ok := m.retrieve(i.Key); !ok {
127 m.data.items[i.Key] = m.mkItemLocked(i)
128 return nil
129 }
130 return memcache.ErrNotStored
131 }
132
133 // CompareAndSwap implements context.MCSingleReadWriter.CompareAndSwap.
134 func (m *memcacheImpl) CompareAndSwap(item *memcache.Item) error {
135 if err := m.data.IsBroken(); err != nil {
136 return err
137 }
138
139 m.data.lock.Lock()
140 defer m.data.lock.Unlock()
141
142 if cur, ok := m.retrieve(item.Key); ok {
143 if cur.CasID == unsafe.MCGetCasID(item) {
144 m.data.items[item.Key] = m.mkItemLocked(item)
145 } else {
146 return memcache.ErrCASConflict
147 }
148 } else {
149 return memcache.ErrNotStored
150 }
151 return nil
152 }
153
154 // Set implements context.MCSingleReadWriter.Set.
155 func (m *memcacheImpl) Set(i *memcache.Item) error {
156 if err := m.data.IsBroken(); err != nil {
157 return err
158 }
159
160 m.data.lock.Lock()
161 defer m.data.lock.Unlock()
162
163 m.data.items[i.Key] = m.mkItemLocked(i)
164 return nil
165 }
166
167 // Get implements context.MCSingleReadWriter.Get.
168 func (m *memcacheImpl) Get(key string) (*memcache.Item, error) {
169 if err := m.data.IsBroken(); err != nil {
170 return nil, err
171 }
172
173 m.data.lock.Lock()
174 defer m.data.lock.Unlock()
175
176 if val, ok := m.retrieve(key); ok {
177 return copyBack(val), nil
178 }
179 return nil, memcache.ErrCacheMiss
180 }
181
182 // Delete implements context.MCSingleReadWriter.Delete.
183 func (m *memcacheImpl) Delete(key string) error {
184 if err := m.data.IsBroken(); err != nil {
185 return err
186 }
187
188 m.data.lock.Lock()
189 defer m.data.lock.Unlock()
190
191 if _, ok := m.retrieve(key); ok {
192 delete(m.data.items, key)
193 return nil
194 }
195 return memcache.ErrCacheMiss
196 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698