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

Side by Side Diff: impl/memory/memcache.go

Issue 1262173003: Use time.Time for internal memcache memory implementation (Closed) Base URL: https://github.com/luci/gae.git@add_rdscache
Patch Set: address comments Created 5 years, 4 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 | « no previous file | impl/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
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 "encoding/binary" 8 "encoding/binary"
9 "sync" 9 "sync"
10 "time" 10 "time"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 func (m *mcItem) SetFlags(flg uint32) mc.Item { 43 func (m *mcItem) SetFlags(flg uint32) mc.Item {
44 m.flags = flg 44 m.flags = flg
45 return m 45 return m
46 } 46 }
47 func (m *mcItem) SetExpiration(exp time.Duration) mc.Item { 47 func (m *mcItem) SetExpiration(exp time.Duration) mc.Item {
48 m.expiration = exp 48 m.expiration = exp
49 return m 49 return m
50 } 50 }
51 51
52 func (m *mcItem) SetAll(other mc.Item) { 52 func (m *mcItem) SetAll(other mc.Item) {
53 » *m = *other.(*mcItem).duplicate(false) 53 » *m = *other.(*mcItem)
54 } 54 }
55 55
56 func (m *mcItem) duplicate(deep bool) *mcItem { 56 type mcDataItem struct {
57 » ret := mcItem{} 57 » value []byte
58 » ret = *m 58 » flags uint32
59 » if deep { 59 » expiration time.Time
60 » » ret.value = make([]byte, len(m.value)) 60 » casID uint64
61 » » copy(ret.value, m.value) 61 }
62 » } 62
63 » return &ret 63 func (m *mcDataItem) toUserItem(key string) *mcItem {
64 » value := make([]byte, len(m.value))
65 » copy(value, m.value)
66 » // Expiration is defined to be 0 when retrieving items from memcache.
67 » // https://cloud.google.com/appengine/docs/go/memcache/reference#Item
68 » // ¯\_(ツ)_/¯
69 » return &mcItem{key, value, m.flags, 0, m.casID}
64 } 70 }
65 71
66 type memcacheData struct { 72 type memcacheData struct {
67 lock sync.RWMutex 73 lock sync.RWMutex
68 » items map[string]*mcItem 74 » items map[string]*mcDataItem
69 casID uint64 75 casID uint64
70 76
71 stats mc.Statistics 77 stats mc.Statistics
72 } 78 }
73 79
74 func (m *memcacheData) mkItemLocked(now time.Time, i mc.Item) (ret *mcItem) { 80 func (m *memcacheData) mkDataItemLocked(now time.Time, i mc.Item) (ret *mcDataIt em) {
75 m.casID++ 81 m.casID++
76 82
77 » var exp time.Duration 83 » exp := time.Time{}
78 if i.Expiration() != 0 { 84 if i.Expiration() != 0 {
79 » » exp = time.Duration(now.Add(i.Expiration()).UnixNano()) 85 » » exp = now.Add(i.Expiration()).Truncate(time.Second)
80 } 86 }
81 value := make([]byte, len(i.Value())) 87 value := make([]byte, len(i.Value()))
82 copy(value, i.Value()) 88 copy(value, i.Value())
83 » return &mcItem{ 89 » return &mcDataItem{
84 » » key: i.Key(),
85 flags: i.Flags(), 90 flags: i.Flags(),
86 expiration: exp, 91 expiration: exp,
87 value: value, 92 value: value,
88 » » CasID: m.casID, 93 » » casID: m.casID,
89 } 94 }
90 } 95 }
91 96
92 func (m *memcacheData) setItemLocked(now time.Time, i mc.Item) { 97 func (m *memcacheData) setItemLocked(now time.Time, i mc.Item) {
93 if cur, ok := m.items[i.Key()]; ok { 98 if cur, ok := m.items[i.Key()]; ok {
94 m.stats.Items-- 99 m.stats.Items--
95 m.stats.Bytes -= uint64(len(cur.value)) 100 m.stats.Bytes -= uint64(len(cur.value))
96 } 101 }
97 m.stats.Items++ 102 m.stats.Items++
98 m.stats.Bytes += uint64(len(i.Value())) 103 m.stats.Bytes += uint64(len(i.Value()))
99 » m.items[i.Key()] = m.mkItemLocked(now, i) 104 » m.items[i.Key()] = m.mkDataItemLocked(now, i)
100 } 105 }
101 106
102 func (m *memcacheData) delItemLocked(k string) { 107 func (m *memcacheData) delItemLocked(k string) {
103 if itm, ok := m.items[k]; ok { 108 if itm, ok := m.items[k]; ok {
104 m.stats.Items-- 109 m.stats.Items--
105 m.stats.Bytes -= uint64(len(itm.value)) 110 m.stats.Bytes -= uint64(len(itm.value))
106 delete(m.items, k) 111 delete(m.items, k)
107 } 112 }
108 } 113 }
109 114
110 func (m *memcacheData) reset() { 115 func (m *memcacheData) reset() {
111 m.stats = mc.Statistics{} 116 m.stats = mc.Statistics{}
112 » m.items = map[string]*mcItem{} 117 » m.items = map[string]*mcDataItem{}
113 } 118 }
114 119
115 func (m *memcacheData) hasItemLocked(now time.Time, key string) bool { 120 func (m *memcacheData) hasItemLocked(now time.Time, key string) bool {
116 ret, ok := m.items[key] 121 ret, ok := m.items[key]
117 » if ok && ret.Expiration() != 0 && ret.Expiration() < time.Duration(now.U nixNano()) { 122 » if ok && !ret.expiration.IsZero() && ret.expiration.Before(now) {
118 m.delItemLocked(key) 123 m.delItemLocked(key)
119 return false 124 return false
120 } 125 }
121 return ok 126 return ok
122 } 127 }
123 128
124 func (m *memcacheData) retrieveLocked(now time.Time, key string) (*mcItem, error ) { 129 func (m *memcacheData) retrieveLocked(now time.Time, key string) (*mcDataItem, e rror) {
125 if !m.hasItemLocked(now, key) { 130 if !m.hasItemLocked(now, key) {
126 m.stats.Misses++ 131 m.stats.Misses++
127 return nil, mc.ErrCacheMiss 132 return nil, mc.ErrCacheMiss
128 } 133 }
129 134
130 ret := m.items[key] 135 ret := m.items[key]
131 m.stats.Hits++ 136 m.stats.Hits++
132 m.stats.ByteHits += uint64(len(ret.value)) 137 m.stats.ByteHits += uint64(len(ret.value))
133 return ret, nil 138 return ret, nil
134 } 139 }
(...skipping 13 matching lines...) Expand all
148 lck := sync.Mutex{} 153 lck := sync.Mutex{}
149 mcdMap := map[string]*memcacheData{} 154 mcdMap := map[string]*memcacheData{}
150 155
151 return mc.SetRawFactory(c, func(ic context.Context) mc.RawInterface { 156 return mc.SetRawFactory(c, func(ic context.Context) mc.RawInterface {
152 lck.Lock() 157 lck.Lock()
153 defer lck.Unlock() 158 defer lck.Unlock()
154 159
155 ns := curGID(ic).namespace 160 ns := curGID(ic).namespace
156 mcd, ok := mcdMap[ns] 161 mcd, ok := mcdMap[ns]
157 if !ok { 162 if !ok {
158 » » » mcd = &memcacheData{items: map[string]*mcItem{}} 163 » » » mcd = &memcacheData{items: map[string]*mcDataItem{}}
159 mcdMap[ns] = mcd 164 mcdMap[ns] = mcd
160 } 165 }
161 166
162 return &memcacheImpl{ 167 return &memcacheImpl{
163 mcd, 168 mcd,
164 ic, 169 ic,
165 } 170 }
166 }) 171 })
167 } 172 }
168 173
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 doCBs(items, cb, func(itm mc.Item) error { 211 doCBs(items, cb, func(itm mc.Item) error {
207 m.data.lock.Lock() 212 m.data.lock.Lock()
208 defer m.data.lock.Unlock() 213 defer m.data.lock.Unlock()
209 214
210 if cur, err := m.data.retrieveLocked(now, itm.Key()); err == nil { 215 if cur, err := m.data.retrieveLocked(now, itm.Key()); err == nil {
211 casid := uint64(0) 216 casid := uint64(0)
212 if mi, ok := itm.(*mcItem); ok && mi != nil { 217 if mi, ok := itm.(*mcItem); ok && mi != nil {
213 casid = mi.CasID 218 casid = mi.CasID
214 } 219 }
215 220
216 » » » if cur.CasID == casid { 221 » » » if cur.casID == casid {
217 m.data.setItemLocked(now, itm) 222 m.data.setItemLocked(now, itm)
218 } else { 223 } else {
219 return mc.ErrCASConflict 224 return mc.ErrCASConflict
220 } 225 }
221 return nil 226 return nil
222 } 227 }
223 return mc.ErrNotStored 228 return mc.ErrNotStored
224 }) 229 })
225 return nil 230 return nil
226 } 231 }
(...skipping 16 matching lines...) Expand all
243 errs := make([]error, len(keys)) 248 errs := make([]error, len(keys))
244 249
245 for i, k := range keys { 250 for i, k := range keys {
246 itms[i], errs[i] = func() (mc.Item, error) { 251 itms[i], errs[i] = func() (mc.Item, error) {
247 m.data.lock.RLock() 252 m.data.lock.RLock()
248 defer m.data.lock.RUnlock() 253 defer m.data.lock.RUnlock()
249 val, err := m.data.retrieveLocked(now, k) 254 val, err := m.data.retrieveLocked(now, k)
250 if err != nil { 255 if err != nil {
251 return nil, err 256 return nil, err
252 } 257 }
253 » » » return val.duplicate(true).SetExpiration(0), nil 258 » » » return val.toUserItem(k), nil
254 }() 259 }()
255 } 260 }
256 261
257 for i, itm := range itms { 262 for i, itm := range itms {
258 cb(itm, errs[i]) 263 cb(itm, errs[i])
259 } 264 }
260 265
261 return nil 266 return nil
262 } 267 }
263 268
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 return cur, nil 335 return cur, nil
331 } 336 }
332 337
333 func (m *memcacheImpl) Stats() (*mc.Statistics, error) { 338 func (m *memcacheImpl) Stats() (*mc.Statistics, error) {
334 m.data.lock.RLock() 339 m.data.lock.RLock()
335 defer m.data.lock.RUnlock() 340 defer m.data.lock.RUnlock()
336 341
337 ret := m.data.stats 342 ret := m.data.stats
338 return &ret, nil 343 return &ret, nil
339 } 344 }
OLDNEW
« no previous file with comments | « no previous file | impl/memory/memcache_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698