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

Side by Side Diff: memory/memcache.go

Issue 1243323002: Refactor a bit. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: fix golint 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
« no previous file with comments | « memory/globalinfo.go ('k') | memory/memcache_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "sync"
9 "time"
10
11 "golang.org/x/net/context"
12
13 "github.com/luci/gae"
14 "github.com/luci/gae/dummy"
15
16 "github.com/luci/luci-go/common/clock"
17 )
18
19 type mcItem struct {
20 key string
21 value []byte
22 object interface{}
23 flags uint32
24 expiration time.Duration
25
26 CasID uint64
27 }
28
29 var _ gae.MCItem = (*mcItem)(nil)
30
31 func (m *mcItem) Key() string { return m.key }
32 func (m *mcItem) Value() []byte { return m.value }
33 func (m *mcItem) Object() interface{} { return m.object }
34 func (m *mcItem) Flags() uint32 { return m.flags }
35 func (m *mcItem) Expiration() time.Duration { return m.expiration }
36
37 func (m *mcItem) SetKey(key string) gae.MCItem {
38 m.key = key
39 return m
40 }
41 func (m *mcItem) SetValue(val []byte) gae.MCItem {
42 m.value = val
43 return m
44 }
45 func (m *mcItem) SetObject(obj interface{}) gae.MCItem {
46 m.object = obj
47 return m
48 }
49 func (m *mcItem) SetFlags(flg uint32) gae.MCItem {
50 m.flags = flg
51 return m
52 }
53 func (m *mcItem) SetExpiration(exp time.Duration) gae.MCItem {
54 m.expiration = exp
55 return m
56 }
57
58 func (m *mcItem) duplicate() *mcItem {
59 ret := mcItem{}
60 ret = *m
61 ret.value = make([]byte, len(m.value))
62 copy(ret.value, m.value)
63 return &ret
64 }
65
66 type memcacheData struct {
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 _ gae.Memcache = (*memcacheImpl)(nil)
82
83 // useMC adds a gae.Memcache implementation to context, accessible
84 // by gae.GetMC(c)
85 func useMC(c context.Context) context.Context {
86 lck := sync.Mutex{}
87 mcdMap := map[string]*memcacheData{}
88
89 return gae.SetMCFactory(c, func(ic context.Context) gae.Memcache {
90 lck.Lock()
91 defer lck.Unlock()
92
93 ns := curGID(ic).namespace
94 mcd, ok := mcdMap[ns]
95 if !ok {
96 mcd = &memcacheData{items: map[string]*mcItem{}}
97 mcdMap[ns] = mcd
98 }
99
100 return &memcacheImpl{
101 dummy.MC(),
102 mcd,
103 ic,
104 }
105 })
106 }
107
108 func (m *memcacheImpl) mkItemLocked(i gae.MCItem) (ret *mcItem) {
109 m.data.casID++
110
111 var exp time.Duration
112 if i.Expiration() != 0 {
113 exp = time.Duration(clock.Now(m.ctx).Add(i.Expiration()).UnixNan o())
114 }
115 newItem := mcItem{
116 key: i.Key(),
117 flags: i.Flags(),
118 expiration: exp,
119 value: i.Value(),
120 CasID: m.data.casID,
121 }
122 return newItem.duplicate()
123 }
124
125 func (m *memcacheImpl) NewItem(key string) gae.MCItem {
126 return &mcItem{key: key}
127 }
128
129 // Add implements context.MCSingleReadWriter.Add.
130 func (m *memcacheImpl) Add(i gae.MCItem) error {
131 m.data.lock.Lock()
132 defer m.data.lock.Unlock()
133
134 if _, ok := m.retrieveLocked(i.Key()); !ok {
135 m.data.items[i.Key()] = m.mkItemLocked(i)
136 return nil
137 }
138 return gae.ErrMCNotStored
139 }
140
141 // CompareAndSwap implements context.MCSingleReadWriter.CompareAndSwap.
142 func (m *memcacheImpl) CompareAndSwap(item gae.MCItem) error {
143 m.data.lock.Lock()
144 defer m.data.lock.Unlock()
145
146 if cur, ok := m.retrieveLocked(item.Key()); ok {
147 casid := uint64(0)
148 if mi, ok := item.(*mcItem); ok && mi != nil {
149 casid = mi.CasID
150 }
151
152 if cur.CasID == casid {
153 m.data.items[item.Key()] = m.mkItemLocked(item)
154 } else {
155 return gae.ErrMCCASConflict
156 }
157 } else {
158 return gae.ErrMCNotStored
159 }
160 return nil
161 }
162
163 // Set implements context.MCSingleReadWriter.Set.
164 func (m *memcacheImpl) Set(i gae.MCItem) error {
165 m.data.lock.Lock()
166 defer m.data.lock.Unlock()
167 m.data.items[i.Key()] = m.mkItemLocked(i)
168 return nil
169 }
170
171 // Get implements context.MCSingleReadWriter.Get.
172 func (m *memcacheImpl) Get(key string) (itm gae.MCItem, err error) {
173 m.data.lock.Lock()
174 defer m.data.lock.Unlock()
175 if val, ok := m.retrieveLocked(key); ok {
176 itm = val.duplicate().SetExpiration(0)
177 } else {
178 err = gae.ErrMCCacheMiss
179 }
180 return
181 }
182
183 // Delete implements context.MCSingleReadWriter.Delete.
184 func (m *memcacheImpl) Delete(key string) error {
185 m.data.lock.Lock()
186 defer m.data.lock.Unlock()
187
188 if _, ok := m.retrieveLocked(key); ok {
189 delete(m.data.items, key)
190 return nil
191 }
192 return gae.ErrMCCacheMiss
193 }
194
195 func (m *memcacheImpl) retrieveLocked(key string) (*mcItem, bool) {
196 ret, ok := m.data.items[key]
197 if ok && ret.Expiration() != 0 && ret.Expiration() < time.Duration(clock .Now(m.ctx).UnixNano()) {
198 ret = nil
199 ok = false
200 delete(m.data.items, key)
201 }
202 return ret, ok
203 }
OLDNEW
« no previous file with comments | « memory/globalinfo.go ('k') | memory/memcache_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698