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

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

Issue 2554793002: impl/memory: Fix memcache stats race. (Closed)
Patch Set: Created 4 years 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 | no next file » | 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 LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 func (m *mcDataItem) toUserItem(key string) *mcItem { 71 func (m *mcDataItem) toUserItem(key string) *mcItem {
72 value := make([]byte, len(m.value)) 72 value := make([]byte, len(m.value))
73 copy(value, m.value) 73 copy(value, m.value)
74 // Expiration is defined to be 0 when retrieving items from memcache. 74 // Expiration is defined to be 0 when retrieving items from memcache.
75 // https://cloud.google.com/appengine/docs/go/memcache/reference#Item 75 // https://cloud.google.com/appengine/docs/go/memcache/reference#Item
76 // ¯\_(ツ)_/¯ 76 // ¯\_(ツ)_/¯
77 return &mcItem{key, value, m.flags, 0, m.casID} 77 return &mcItem{key, value, m.flags, 0, m.casID}
78 } 78 }
79 79
80 type memcacheData struct { 80 type memcacheData struct {
81 » lock sync.RWMutex 81 » lock sync.Mutex
82 items map[string]*mcDataItem 82 items map[string]*mcDataItem
83 casID uint64 83 casID uint64
84 84
85 stats mc.Statistics 85 stats mc.Statistics
86 } 86 }
87 87
88 func (m *memcacheData) mkDataItemLocked(now time.Time, i mc.Item) (ret *mcDataIt em) { 88 func (m *memcacheData) mkDataItemLocked(now time.Time, i mc.Item) (ret *mcDataIt em) {
89 m.casID++ 89 m.casID++
90 90
91 exp := time.Time{} 91 exp := time.Time{}
92 if i.Expiration() != 0 { 92 if i.Expiration() != 0 {
93 exp = now.Add(i.Expiration()).Truncate(time.Second) 93 exp = now.Add(i.Expiration()).Truncate(time.Second)
94 } 94 }
95 value := make([]byte, len(i.Value())) 95 value := make([]byte, len(i.Value()))
96 copy(value, i.Value()) 96 copy(value, i.Value())
97 return &mcDataItem{ 97 return &mcDataItem{
98 flags: i.Flags(), 98 flags: i.Flags(),
99 expiration: exp, 99 expiration: exp,
100 value: value, 100 value: value,
101 casID: m.casID, 101 casID: m.casID,
102 } 102 }
103 } 103 }
104 104
105 func (m *memcacheData) setItemLocked(now time.Time, i mc.Item) { 105 func (m *memcacheData) setItemLocked(now time.Time, i mc.Item) {
106 if cur, ok := m.items[i.Key()]; ok { 106 if cur, ok := m.items[i.Key()]; ok {
107 m.stats.Items-- 107 m.stats.Items--
108 m.stats.Bytes -= uint64(len(cur.value)) 108 m.stats.Bytes -= uint64(len(cur.value))
109 } 109 }
110 m.stats.Items++ 110 m.stats.Items++
dnj 2016/12/06 17:24:06 All mutations to "m.stats" while holding RLock are
111 m.stats.Bytes += uint64(len(i.Value())) 111 m.stats.Bytes += uint64(len(i.Value()))
112 m.items[i.Key()] = m.mkDataItemLocked(now, i) 112 m.items[i.Key()] = m.mkDataItemLocked(now, i)
113 } 113 }
114 114
115 func (m *memcacheData) delItemLocked(k string) { 115 func (m *memcacheData) delItemLocked(k string) {
116 if itm, ok := m.items[k]; ok { 116 if itm, ok := m.items[k]; ok {
117 m.stats.Items-- 117 m.stats.Items--
118 m.stats.Bytes -= uint64(len(itm.value)) 118 m.stats.Bytes -= uint64(len(itm.value))
119 delete(m.items, k) 119 delete(m.items, k)
120 } 120 }
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 } 251 }
252 252
253 func (m *memcacheImpl) GetMulti(keys []string, cb mc.RawItemCB) error { 253 func (m *memcacheImpl) GetMulti(keys []string, cb mc.RawItemCB) error {
254 now := clock.Now(m.ctx) 254 now := clock.Now(m.ctx)
255 255
256 itms := make([]mc.Item, len(keys)) 256 itms := make([]mc.Item, len(keys))
257 errs := make([]error, len(keys)) 257 errs := make([]error, len(keys))
258 258
259 for i, k := range keys { 259 for i, k := range keys {
260 itms[i], errs[i] = func() (mc.Item, error) { 260 itms[i], errs[i] = func() (mc.Item, error) {
261 » » » m.data.lock.RLock() 261 » » » m.data.lock.Lock()
262 » » » defer m.data.lock.RUnlock() 262 » » » defer m.data.lock.Unlock()
263 val, err := m.data.retrieveLocked(now, k) 263 val, err := m.data.retrieveLocked(now, k)
264 if err != nil { 264 if err != nil {
265 return nil, err 265 return nil, err
266 } 266 }
267 return val.toUserItem(k), nil 267 return val.toUserItem(k), nil
268 }() 268 }()
269 } 269 }
270 270
271 for i, itm := range itms { 271 for i, itm := range itms {
272 cb(itm, errs[i]) 272 cb(itm, errs[i])
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 } 338 }
339 339
340 newval := make([]byte, 8) 340 newval := make([]byte, 8)
341 binary.LittleEndian.PutUint64(newval, cur) 341 binary.LittleEndian.PutUint64(newval, cur)
342 m.data.setItemLocked(now, m.NewItem(key).SetValue(newval)) 342 m.data.setItemLocked(now, m.NewItem(key).SetValue(newval))
343 343
344 return cur, nil 344 return cur, nil
345 } 345 }
346 346
347 func (m *memcacheImpl) Stats() (*mc.Statistics, error) { 347 func (m *memcacheImpl) Stats() (*mc.Statistics, error) {
348 » m.data.lock.RLock() 348 » m.data.lock.Lock()
349 » defer m.data.lock.RUnlock() 349 » defer m.data.lock.Unlock()
350 350
351 ret := m.data.stats 351 ret := m.data.stats
352 return &ret, nil 352 return &ret, nil
353 } 353 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698