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

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: 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 » return &mcItem{key, value, m.flags, 0, m.casID}
dnj 2015/08/04 17:55:42 Shouldn't you use "m.expiration.UTC().UnixNano() /
iannucci 2015/08/04 18:13:54 Nah, the memcache api defines Expiration has havin
64 } 67 }
65 68
66 type memcacheData struct { 69 type memcacheData struct {
67 lock sync.RWMutex 70 lock sync.RWMutex
68 » items map[string]*mcItem 71 » items map[string]*mcDataItem
69 casID uint64 72 casID uint64
70 73
71 stats mc.Statistics 74 stats mc.Statistics
72 } 75 }
73 76
74 func (m *memcacheData) mkItemLocked(now time.Time, i mc.Item) (ret *mcItem) { 77 func (m *memcacheData) mkDataItemLocked(now time.Time, i mc.Item) (ret *mcDataIt em) {
75 m.casID++ 78 m.casID++
76 79
77 » var exp time.Duration 80 » var exp time.Time
dnj 2015/08/04 17:55:43 maruel@ prefers: exp := time.Time{} This seems to
iannucci 2015/08/04 18:13:54 Weird. I usually do that too.
78 if i.Expiration() != 0 { 81 if i.Expiration() != 0 {
79 » » exp = time.Duration(now.Add(i.Expiration()).UnixNano()) 82 » » exp = now.Add(i.Expiration()).Truncate(time.Second)
80 } 83 }
81 value := make([]byte, len(i.Value())) 84 value := make([]byte, len(i.Value()))
82 copy(value, i.Value()) 85 copy(value, i.Value())
83 » return &mcItem{ 86 » return &mcDataItem{
84 » » key: i.Key(),
85 flags: i.Flags(), 87 flags: i.Flags(),
86 expiration: exp, 88 expiration: exp,
87 value: value, 89 value: value,
88 » » CasID: m.casID, 90 » » casID: m.casID,
89 } 91 }
90 } 92 }
91 93
92 func (m *memcacheData) setItemLocked(now time.Time, i mc.Item) { 94 func (m *memcacheData) setItemLocked(now time.Time, i mc.Item) {
93 if cur, ok := m.items[i.Key()]; ok { 95 if cur, ok := m.items[i.Key()]; ok {
94 m.stats.Items-- 96 m.stats.Items--
95 m.stats.Bytes -= uint64(len(cur.value)) 97 m.stats.Bytes -= uint64(len(cur.value))
96 } 98 }
97 m.stats.Items++ 99 m.stats.Items++
98 m.stats.Bytes += uint64(len(i.Value())) 100 m.stats.Bytes += uint64(len(i.Value()))
99 » m.items[i.Key()] = m.mkItemLocked(now, i) 101 » m.items[i.Key()] = m.mkDataItemLocked(now, i)
100 } 102 }
101 103
102 func (m *memcacheData) delItemLocked(k string) { 104 func (m *memcacheData) delItemLocked(k string) {
103 if itm, ok := m.items[k]; ok { 105 if itm, ok := m.items[k]; ok {
104 m.stats.Items-- 106 m.stats.Items--
105 m.stats.Bytes -= uint64(len(itm.value)) 107 m.stats.Bytes -= uint64(len(itm.value))
106 delete(m.items, k) 108 delete(m.items, k)
107 } 109 }
108 } 110 }
109 111
110 func (m *memcacheData) reset() { 112 func (m *memcacheData) reset() {
111 m.stats = mc.Statistics{} 113 m.stats = mc.Statistics{}
112 » m.items = map[string]*mcItem{} 114 » m.items = map[string]*mcDataItem{}
113 } 115 }
114 116
115 func (m *memcacheData) hasItemLocked(now time.Time, key string) bool { 117 func (m *memcacheData) hasItemLocked(now time.Time, key string) bool {
116 ret, ok := m.items[key] 118 ret, ok := m.items[key]
117 » if ok && ret.Expiration() != 0 && ret.Expiration() < time.Duration(now.U nixNano()) { 119 » if ok && !ret.expiration.IsZero() && ret.expiration.Before(now) {
118 m.delItemLocked(key) 120 m.delItemLocked(key)
119 return false 121 return false
120 } 122 }
121 return ok 123 return ok
122 } 124 }
123 125
124 func (m *memcacheData) retrieveLocked(now time.Time, key string) (*mcItem, error ) { 126 func (m *memcacheData) retrieveLocked(now time.Time, key string) (*mcDataItem, e rror) {
125 if !m.hasItemLocked(now, key) { 127 if !m.hasItemLocked(now, key) {
126 m.stats.Misses++ 128 m.stats.Misses++
127 return nil, mc.ErrCacheMiss 129 return nil, mc.ErrCacheMiss
128 } 130 }
129 131
130 ret := m.items[key] 132 ret := m.items[key]
131 m.stats.Hits++ 133 m.stats.Hits++
132 m.stats.ByteHits += uint64(len(ret.value)) 134 m.stats.ByteHits += uint64(len(ret.value))
133 return ret, nil 135 return ret, nil
134 } 136 }
(...skipping 13 matching lines...) Expand all
148 lck := sync.Mutex{} 150 lck := sync.Mutex{}
149 mcdMap := map[string]*memcacheData{} 151 mcdMap := map[string]*memcacheData{}
150 152
151 return mc.SetRawFactory(c, func(ic context.Context) mc.RawInterface { 153 return mc.SetRawFactory(c, func(ic context.Context) mc.RawInterface {
152 lck.Lock() 154 lck.Lock()
153 defer lck.Unlock() 155 defer lck.Unlock()
154 156
155 ns := curGID(ic).namespace 157 ns := curGID(ic).namespace
156 mcd, ok := mcdMap[ns] 158 mcd, ok := mcdMap[ns]
157 if !ok { 159 if !ok {
158 » » » mcd = &memcacheData{items: map[string]*mcItem{}} 160 » » » mcd = &memcacheData{items: map[string]*mcDataItem{}}
159 mcdMap[ns] = mcd 161 mcdMap[ns] = mcd
160 } 162 }
161 163
162 return &memcacheImpl{ 164 return &memcacheImpl{
163 mcd, 165 mcd,
164 ic, 166 ic,
165 } 167 }
166 }) 168 })
167 } 169 }
168 170
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 doCBs(items, cb, func(itm mc.Item) error { 208 doCBs(items, cb, func(itm mc.Item) error {
207 m.data.lock.Lock() 209 m.data.lock.Lock()
208 defer m.data.lock.Unlock() 210 defer m.data.lock.Unlock()
209 211
210 if cur, err := m.data.retrieveLocked(now, itm.Key()); err == nil { 212 if cur, err := m.data.retrieveLocked(now, itm.Key()); err == nil {
211 casid := uint64(0) 213 casid := uint64(0)
212 if mi, ok := itm.(*mcItem); ok && mi != nil { 214 if mi, ok := itm.(*mcItem); ok && mi != nil {
213 casid = mi.CasID 215 casid = mi.CasID
214 } 216 }
215 217
216 » » » if cur.CasID == casid { 218 » » » if cur.casID == casid {
217 m.data.setItemLocked(now, itm) 219 m.data.setItemLocked(now, itm)
218 } else { 220 } else {
219 return mc.ErrCASConflict 221 return mc.ErrCASConflict
220 } 222 }
221 return nil 223 return nil
222 } 224 }
223 return mc.ErrNotStored 225 return mc.ErrNotStored
224 }) 226 })
225 return nil 227 return nil
226 } 228 }
(...skipping 16 matching lines...) Expand all
243 errs := make([]error, len(keys)) 245 errs := make([]error, len(keys))
244 246
245 for i, k := range keys { 247 for i, k := range keys {
246 itms[i], errs[i] = func() (mc.Item, error) { 248 itms[i], errs[i] = func() (mc.Item, error) {
247 m.data.lock.RLock() 249 m.data.lock.RLock()
248 defer m.data.lock.RUnlock() 250 defer m.data.lock.RUnlock()
249 val, err := m.data.retrieveLocked(now, k) 251 val, err := m.data.retrieveLocked(now, k)
250 if err != nil { 252 if err != nil {
251 return nil, err 253 return nil, err
252 } 254 }
253 » » » return val.duplicate(true).SetExpiration(0), nil 255 » » » return val.toUserItem(k), nil
254 }() 256 }()
255 } 257 }
256 258
257 for i, itm := range itms { 259 for i, itm := range itms {
258 cb(itm, errs[i]) 260 cb(itm, errs[i])
259 } 261 }
260 262
261 return nil 263 return nil
262 } 264 }
263 265
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 return cur, nil 332 return cur, nil
331 } 333 }
332 334
333 func (m *memcacheImpl) Stats() (*mc.Statistics, error) { 335 func (m *memcacheImpl) Stats() (*mc.Statistics, error) {
334 m.data.lock.RLock() 336 m.data.lock.RLock()
335 defer m.data.lock.RUnlock() 337 defer m.data.lock.RUnlock()
336 338
337 ret := m.data.stats 339 ret := m.data.stats
338 return &ret, nil 340 return &ret, nil
339 } 341 }
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