OLD | NEW |
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 dscache | 5 package dscache |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "encoding/binary" | 9 "encoding/binary" |
10 "errors" | 10 "errors" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 | 59 |
60 Convey("Test dscache", t, func() { | 60 Convey("Test dscache", t, func() { |
61 c := mathrand.Set(context.Background(), rand.New(rand.NewSource(
1))) | 61 c := mathrand.Set(context.Background(), rand.New(rand.NewSource(
1))) |
62 clk := testclock.New(zeroTime) | 62 clk := testclock.New(zeroTime) |
63 c = clock.Set(c, clk) | 63 c = clock.Set(c, clk) |
64 c = memory.Use(c) | 64 c = memory.Use(c) |
65 | 65 |
66 dsUnder := datastore.Get(c) | 66 dsUnder := datastore.Get(c) |
67 mc := memcache.Get(c) | 67 mc := memcache.Get(c) |
68 | 68 |
69 itmFor := func(i int, k *datastore.Key) memcache.Item { | |
70 return mc.NewItem(MakeMemcacheKey(i, k)) | |
71 } | |
72 | |
73 shardsForKey := func(k *datastore.Key) int { | 69 shardsForKey := func(k *datastore.Key) int { |
74 last := k.Last() | 70 last := k.Last() |
75 if last.Kind == "shardObj" { | 71 if last.Kind == "shardObj" { |
76 return int(last.IntID) | 72 return int(last.IntID) |
77 } | 73 } |
78 if last.Kind == "noCacheObj" { | 74 if last.Kind == "noCacheObj" { |
79 return 0 | 75 return 0 |
80 } | 76 } |
81 return DefaultShards | 77 return DefaultShards |
82 } | 78 } |
(...skipping 18 matching lines...) Expand all Loading... |
101 } | 97 } |
102 encoded := append([]byte{0}, serialize.ToBytes(p
m)...) | 98 encoded := append([]byte{0}, serialize.ToBytes(p
m)...) |
103 | 99 |
104 o := object{ID: 1, Value: "hi"} | 100 o := object{ID: 1, Value: "hi"} |
105 So(ds.Put(&o), ShouldBeNil) | 101 So(ds.Put(&o), ShouldBeNil) |
106 | 102 |
107 o = object{ID: 1} | 103 o = object{ID: 1} |
108 So(dsUnder.Get(&o), ShouldBeNil) | 104 So(dsUnder.Get(&o), ShouldBeNil) |
109 So(o.Value, ShouldEqual, "hi") | 105 So(o.Value, ShouldEqual, "hi") |
110 | 106 |
111 » » » » itm := itmFor(0, ds.KeyForObj(&o)) | 107 » » » » itm, err := mc.Get(MakeMemcacheKey(0, ds.KeyForO
bj(&o))) |
112 » » » » So(mc.Get(itm), ShouldEqual, memcache.ErrCacheMi
ss) | 108 » » » » So(err, ShouldEqual, memcache.ErrCacheMiss) |
113 | 109 |
114 o = object{ID: 1} | 110 o = object{ID: 1} |
115 So(ds.Get(&o), ShouldBeNil) | 111 So(ds.Get(&o), ShouldBeNil) |
116 So(o.Value, ShouldEqual, "hi") | 112 So(o.Value, ShouldEqual, "hi") |
117 » » » » So(mc.Get(itm), ShouldBeNil) | 113 |
| 114 » » » » itm, err = mc.Get(itm.Key()) |
| 115 » » » » So(err, ShouldBeNil) |
118 So(itm.Value(), ShouldResemble, encoded) | 116 So(itm.Value(), ShouldResemble, encoded) |
119 | 117 |
120 Convey("now we don't need the datastore!", func(
) { | 118 Convey("now we don't need the datastore!", func(
) { |
121 o := object{ID: 1} | 119 o := object{ID: 1} |
122 | 120 |
123 // delete it, bypassing the cache filter
. Don't do this in production | 121 // delete it, bypassing the cache filter
. Don't do this in production |
124 // unless you want a crappy cache. | 122 // unless you want a crappy cache. |
125 So(dsUnder.Delete(ds.KeyForObj(&o)), Sho
uldBeNil) | 123 So(dsUnder.Delete(ds.KeyForObj(&o)), Sho
uldBeNil) |
126 | 124 |
127 » » » » » itm := itmFor(0, ds.KeyForObj(&o)) | 125 » » » » » itm, err := mc.Get(MakeMemcacheKey(0, ds
.KeyForObj(&o))) |
128 » » » » » So(mc.Get(itm), ShouldBeNil) | 126 » » » » » So(err, ShouldBeNil) |
129 So(itm.Value(), ShouldResemble, encoded) | 127 So(itm.Value(), ShouldResemble, encoded) |
130 | 128 |
131 So(ds.Get(&o), ShouldBeNil) | 129 So(ds.Get(&o), ShouldBeNil) |
132 So(o.Value, ShouldEqual, "hi") | 130 So(o.Value, ShouldEqual, "hi") |
133 }) | 131 }) |
134 | 132 |
135 Convey("deleting it properly records that fact,
however", func() { | 133 Convey("deleting it properly records that fact,
however", func() { |
136 o := object{ID: 1} | 134 o := object{ID: 1} |
137 So(ds.Delete(ds.KeyForObj(&o)), ShouldBe
Nil) | 135 So(ds.Delete(ds.KeyForObj(&o)), ShouldBe
Nil) |
138 | 136 |
139 » » » » » itm := itmFor(0, ds.KeyForObj(&o)) | 137 » » » » » itm, err := mc.Get(MakeMemcacheKey(0, ds
.KeyForObj(&o))) |
140 » » » » » So(mc.Get(itm), ShouldEqual, memcache.Er
rCacheMiss) | 138 » » » » » So(err, ShouldEqual, memcache.ErrCacheMi
ss) |
141 So(ds.Get(&o), ShouldEqual, datastore.Er
rNoSuchEntity) | 139 So(ds.Get(&o), ShouldEqual, datastore.Er
rNoSuchEntity) |
142 | 140 |
143 » » » » » So(mc.Get(itm), ShouldBeNil) | 141 » » » » » itm, err = mc.Get(itm.Key()) |
| 142 » » » » » So(err, ShouldBeNil) |
144 So(itm.Value(), ShouldResemble, []byte{}
) | 143 So(itm.Value(), ShouldResemble, []byte{}
) |
145 | 144 |
146 // this one hits memcache | 145 // this one hits memcache |
147 So(ds.Get(&o), ShouldEqual, datastore.Er
rNoSuchEntity) | 146 So(ds.Get(&o), ShouldEqual, datastore.Er
rNoSuchEntity) |
148 }) | 147 }) |
149 }) | 148 }) |
150 | 149 |
151 Convey("compression works", func() { | 150 Convey("compression works", func() { |
152 o := object{ID: 2, Value: `¯\_(ツ)_/¯`} | 151 o := object{ID: 2, Value: `¯\_(ツ)_/¯`} |
153 data := make([]byte, 4000) | 152 data := make([]byte, 4000) |
154 for i := range data { | 153 for i := range data { |
155 const alpha = "ABCDEFGHIJKLMNOPQRSTUVWXY
Zabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()" | 154 const alpha = "ABCDEFGHIJKLMNOPQRSTUVWXY
Zabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()" |
156 data[i] = alpha[i%len(alpha)] | 155 data[i] = alpha[i%len(alpha)] |
157 } | 156 } |
158 o.BigData = data | 157 o.BigData = data |
159 | 158 |
160 So(ds.Put(&o), ShouldBeNil) | 159 So(ds.Put(&o), ShouldBeNil) |
161 So(ds.Get(&o), ShouldBeNil) | 160 So(ds.Get(&o), ShouldBeNil) |
162 | 161 |
163 » » » » itm := itmFor(0, ds.KeyForObj(&o)) | 162 » » » » itm, err := mc.Get(MakeMemcacheKey(0, ds.KeyForO
bj(&o))) |
164 » » » » So(mc.Get(itm), ShouldBeNil) | 163 » » » » So(err, ShouldBeNil) |
165 | 164 |
166 So(itm.Value()[0], ShouldEqual, ZlibCompression) | 165 So(itm.Value()[0], ShouldEqual, ZlibCompression) |
167 So(len(itm.Value()), ShouldEqual, 653) // a bit
smaller than 4k | 166 So(len(itm.Value()), ShouldEqual, 653) // a bit
smaller than 4k |
168 | 167 |
169 // ensure the next Get comes from the cache | 168 // ensure the next Get comes from the cache |
170 So(dsUnder.Delete(ds.KeyForObj(&o)), ShouldBeNil
) | 169 So(dsUnder.Delete(ds.KeyForObj(&o)), ShouldBeNil
) |
171 | 170 |
172 o = object{ID: 2} | 171 o = object{ID: 2} |
173 So(ds.Get(&o), ShouldBeNil) | 172 So(ds.Get(&o), ShouldBeNil) |
174 So(o.Value, ShouldEqual, `¯\_(ツ)_/¯`) | 173 So(o.Value, ShouldEqual, `¯\_(ツ)_/¯`) |
(...skipping 16 matching lines...) Expand all Loading... |
191 o := &object{ID: 1} | 190 o := &object{ID: 1} |
192 So(ds.Get(o), ShouldBeNil) | 191 So(ds.Get(o), ShouldBeNil) |
193 So(o.Value, ShouldEqual, "else") | 192 So(o.Value, ShouldEqual, "else") |
194 o.Value = "txn" | 193 o.Value = "txn" |
195 So(ds.Put(o), ShouldBeNil) | 194 So(ds.Put(o), ShouldBeNil) |
196 | 195 |
197 So(ds.Delete(ds.KeyForObj(&objec
t{ID: 2})), ShouldBeNil) | 196 So(ds.Delete(ds.KeyForObj(&objec
t{ID: 2})), ShouldBeNil) |
198 return nil | 197 return nil |
199 }, &datastore.TransactionOptions{XG: tru
e}), ShouldBeNil) | 198 }, &datastore.TransactionOptions{XG: tru
e}), ShouldBeNil) |
200 | 199 |
201 » » » » » So(mc.Get(itmFor(0, ds.KeyForObj(&object
{ID: 1}))), | 200 » » » » » _, err := mc.Get(MakeMemcacheKey(0, ds.K
eyForObj(&object{ID: 1}))) |
202 » » » » » » ShouldEqual, memcache.ErrCacheMi
ss) | 201 » » » » » So(err, ShouldEqual, memcache.ErrCacheMi
ss) |
203 » » » » » So(mc.Get(itmFor(0, ds.KeyForObj(&object
{ID: 2}))), | 202 » » » » » _, err = mc.Get(MakeMemcacheKey(0, ds.Ke
yForObj(&object{ID: 2}))) |
204 » » » » » » ShouldEqual, memcache.ErrCacheMi
ss) | 203 » » » » » So(err, ShouldEqual, memcache.ErrCacheMi
ss) |
205 o := &object{ID: 1} | 204 o := &object{ID: 1} |
206 So(ds.Get(o), ShouldBeNil) | 205 So(ds.Get(o), ShouldBeNil) |
207 So(o.Value, ShouldEqual, "txn") | 206 So(o.Value, ShouldEqual, "txn") |
208 }) | 207 }) |
209 | 208 |
210 Convey("errors don't invalidate", func() { | 209 Convey("errors don't invalidate", func() { |
211 // populate an object @ ID1 | 210 // populate an object @ ID1 |
212 So(ds.Put(&object{ID: 1, Value: "somethi
ng"}), ShouldBeNil) | 211 So(ds.Put(&object{ID: 1, Value: "somethi
ng"}), ShouldBeNil) |
213 So(ds.Get(&object{ID: 1}), ShouldBeNil) | 212 So(ds.Get(&object{ID: 1}), ShouldBeNil) |
214 So(numMemcacheItems(), ShouldEqual, 1) | 213 So(numMemcacheItems(), ShouldEqual, 1) |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 type model struct { | 274 type model struct { |
276 ID int64 `gae:"$id"` | 275 ID int64 `gae:"$id"` |
277 DSCacheExp int64 `gae:"$dscache.
expiration,7"` | 276 DSCacheExp int64 `gae:"$dscache.
expiration,7"` |
278 | 277 |
279 Value string | 278 Value string |
280 } | 279 } |
281 | 280 |
282 So(ds.Put(&model{ID: 1, Value: "mooo"}),
ShouldBeNil) | 281 So(ds.Put(&model{ID: 1, Value: "mooo"}),
ShouldBeNil) |
283 So(ds.Get(&model{ID: 1}), ShouldBeNil) | 282 So(ds.Get(&model{ID: 1}), ShouldBeNil) |
284 | 283 |
285 » » » » » itm := itmFor(0, ds.KeyForObj(&model{ID:
1})) | 284 » » » » » itm, err := mc.Get(MakeMemcacheKey(0, ds
.KeyForObj(&model{ID: 1}))) |
286 » » » » » So(mc.Get(itm), ShouldBeNil) | 285 » » » » » So(err, ShouldBeNil) |
287 | 286 |
288 clk.Add(10 * time.Second) | 287 clk.Add(10 * time.Second) |
289 » » » » » So(mc.Get(itm), ShouldEqual, memcache.Er
rCacheMiss) | 288 » » » » » _, err = mc.Get(itm.Key()) |
| 289 » » » » » So(err, ShouldEqual, memcache.ErrCacheMi
ss) |
290 }) | 290 }) |
291 }) | 291 }) |
292 | 292 |
293 Convey("screw cases", func() { | 293 Convey("screw cases", func() { |
294 Convey("memcache contains bogus value (simulated
failed AddMulti)", func() { | 294 Convey("memcache contains bogus value (simulated
failed AddMulti)", func() { |
295 o := &object{ID: 1, Value: "spleen"} | 295 o := &object{ID: 1, Value: "spleen"} |
296 So(ds.Put(o), ShouldBeNil) | 296 So(ds.Put(o), ShouldBeNil) |
297 | 297 |
298 sekret := []byte("I am a banana") | 298 sekret := []byte("I am a banana") |
299 » » » » » itm := itmFor(0, ds.KeyForObj(o)).SetVal
ue(sekret) | 299 » » » » » itm := mc.NewItem(MakeMemcacheKey(0, ds.
KeyForObj(o))).SetValue(sekret) |
300 So(mc.Set(itm), ShouldBeNil) | 300 So(mc.Set(itm), ShouldBeNil) |
301 | 301 |
302 o = &object{ID: 1} | 302 o = &object{ID: 1} |
303 So(ds.Get(o), ShouldBeNil) | 303 So(ds.Get(o), ShouldBeNil) |
304 So(o.Value, ShouldEqual, "spleen") | 304 So(o.Value, ShouldEqual, "spleen") |
305 | 305 |
306 » » » » » So(mc.Get(itm), ShouldBeNil) | 306 » » » » » itm, err := mc.Get(itm.Key()) |
| 307 » » » » » So(err, ShouldBeNil) |
307 So(itm.Flags(), ShouldEqual, ItemUKNONWN
) | 308 So(itm.Flags(), ShouldEqual, ItemUKNONWN
) |
308 So(itm.Value(), ShouldResemble, sekret) | 309 So(itm.Value(), ShouldResemble, sekret) |
309 }) | 310 }) |
310 | 311 |
311 Convey("memcache contains bogus value (corrupt e
ntry)", func() { | 312 Convey("memcache contains bogus value (corrupt e
ntry)", func() { |
312 o := &object{ID: 1, Value: "spleen"} | 313 o := &object{ID: 1, Value: "spleen"} |
313 So(ds.Put(o), ShouldBeNil) | 314 So(ds.Put(o), ShouldBeNil) |
314 | 315 |
315 sekret := []byte("I am a banana") | 316 sekret := []byte("I am a banana") |
316 » » » » » itm := (itmFor(0, ds.KeyForObj(o)). | 317 » » » » » itm := (mc.NewItem(MakeMemcacheKey(0, ds
.KeyForObj(o))). |
317 SetValue(sekret). | 318 SetValue(sekret). |
318 SetFlags(uint32(ItemHasData))) | 319 SetFlags(uint32(ItemHasData))) |
319 So(mc.Set(itm), ShouldBeNil) | 320 So(mc.Set(itm), ShouldBeNil) |
320 | 321 |
321 o = &object{ID: 1} | 322 o = &object{ID: 1} |
322 So(ds.Get(o), ShouldBeNil) | 323 So(ds.Get(o), ShouldBeNil) |
323 So(o.Value, ShouldEqual, "spleen") | 324 So(o.Value, ShouldEqual, "spleen") |
324 | 325 |
325 » » » » » So(mc.Get(itm), ShouldBeNil) | 326 » » » » » itm, err := mc.Get(itm.Key()) |
| 327 » » » » » So(err, ShouldBeNil) |
326 So(itm.Flags(), ShouldEqual, ItemHasData
) | 328 So(itm.Flags(), ShouldEqual, ItemHasData
) |
327 So(itm.Value(), ShouldResemble, sekret) | 329 So(itm.Value(), ShouldResemble, sekret) |
328 }) | 330 }) |
329 | 331 |
330 Convey("other entity has the lock", func() { | 332 Convey("other entity has the lock", func() { |
331 o := &object{ID: 1, Value: "spleen"} | 333 o := &object{ID: 1, Value: "spleen"} |
332 So(ds.Put(o), ShouldBeNil) | 334 So(ds.Put(o), ShouldBeNil) |
333 | 335 |
334 sekret := []byte("r@vmarod!#)%9T") | 336 sekret := []byte("r@vmarod!#)%9T") |
335 » » » » » itm := (itmFor(0, ds.KeyForObj(o)). | 337 » » » » » itm := (mc.NewItem(MakeMemcacheKey(0, ds
.KeyForObj(o))). |
336 SetValue(sekret). | 338 SetValue(sekret). |
337 SetFlags(uint32(ItemHasLock))) | 339 SetFlags(uint32(ItemHasLock))) |
338 So(mc.Set(itm), ShouldBeNil) | 340 So(mc.Set(itm), ShouldBeNil) |
339 | 341 |
340 o = &object{ID: 1} | 342 o = &object{ID: 1} |
341 So(ds.Get(o), ShouldBeNil) | 343 So(ds.Get(o), ShouldBeNil) |
342 So(o.Value, ShouldEqual, "spleen") | 344 So(o.Value, ShouldEqual, "spleen") |
343 | 345 |
344 » » » » » So(mc.Get(itm), ShouldBeNil) | 346 » » » » » itm, err := mc.Get(itm.Key()) |
| 347 » » » » » So(err, ShouldBeNil) |
345 So(itm.Flags(), ShouldEqual, ItemHasLock
) | 348 So(itm.Flags(), ShouldEqual, ItemHasLock
) |
346 So(itm.Value(), ShouldResemble, sekret) | 349 So(itm.Value(), ShouldResemble, sekret) |
347 }) | 350 }) |
348 | 351 |
349 Convey("massive entities can't be cached", func(
) { | 352 Convey("massive entities can't be cached", func(
) { |
350 o := &object{ID: 1, Value: "spleen"} | 353 o := &object{ID: 1, Value: "spleen"} |
351 mr := mathrand.Get(c) | 354 mr := mathrand.Get(c) |
352 numRounds := (internalValueSizeLimit / 8
) * 2 | 355 numRounds := (internalValueSizeLimit / 8
) * 2 |
353 buf := bytes.Buffer{} | 356 buf := bytes.Buffer{} |
354 for i := 0; i < numRounds; i++ { | 357 for i := 0; i < numRounds; i++ { |
355 So(binary.Write(&buf, binary.Lit
tleEndian, mr.Int63()), ShouldBeNil) | 358 So(binary.Write(&buf, binary.Lit
tleEndian, mr.Int63()), ShouldBeNil) |
356 } | 359 } |
357 o.BigData = buf.Bytes() | 360 o.BigData = buf.Bytes() |
358 So(ds.Put(o), ShouldBeNil) | 361 So(ds.Put(o), ShouldBeNil) |
359 | 362 |
360 o.BigData = nil | 363 o.BigData = nil |
361 So(ds.Get(o), ShouldBeNil) | 364 So(ds.Get(o), ShouldBeNil) |
362 | 365 |
363 » » » » » itm := itmFor(0, ds.KeyForObj(o)) | 366 » » » » » itm, err := mc.Get(MakeMemcacheKey(0, ds
.KeyForObj(o))) |
364 » » » » » So(mc.Get(itm), ShouldBeNil) | 367 » » » » » So(err, ShouldBeNil) |
365 | 368 |
366 // Is locked until the next put, forcing
all access to the datastore. | 369 // Is locked until the next put, forcing
all access to the datastore. |
367 So(itm.Value(), ShouldResemble, []byte{}
) | 370 So(itm.Value(), ShouldResemble, []byte{}
) |
368 So(itm.Flags(), ShouldEqual, ItemHasLock
) | 371 So(itm.Flags(), ShouldEqual, ItemHasLock
) |
369 | 372 |
370 o.BigData = []byte("hi :)") | 373 o.BigData = []byte("hi :)") |
371 So(ds.Put(o), ShouldBeNil) | 374 So(ds.Put(o), ShouldBeNil) |
372 So(ds.Get(o), ShouldBeNil) | 375 So(ds.Get(o), ShouldBeNil) |
373 | 376 |
374 » » » » » So(mc.Get(itm), ShouldBeNil) | 377 » » » » » itm, err = mc.Get(itm.Key()) |
| 378 » » » » » So(err, ShouldBeNil) |
375 So(itm.Flags(), ShouldEqual, ItemHasData
) | 379 So(itm.Flags(), ShouldEqual, ItemHasData
) |
376 }) | 380 }) |
377 | 381 |
378 Convey("failure on Setting memcache locks is a h
ard stop", func() { | 382 Convey("failure on Setting memcache locks is a h
ard stop", func() { |
379 c, fb := featureBreaker.FilterMC(c, nil) | 383 c, fb := featureBreaker.FilterMC(c, nil) |
380 fb.BreakFeatures(nil, "SetMulti") | 384 fb.BreakFeatures(nil, "SetMulti") |
381 ds := datastore.Get(c) | 385 ds := datastore.Get(c) |
382 So(ds.Put(&object{ID: 1}).Error(), Shoul
dContainSubstring, "SetMulti") | 386 So(ds.Put(&object{ID: 1}).Error(), Shoul
dContainSubstring, "SetMulti") |
383 }) | 387 }) |
384 | 388 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 InstanceEnabledStatic = false | 452 InstanceEnabledStatic = false |
449 defer func() { | 453 defer func() { |
450 InstanceEnabledStatic = true | 454 InstanceEnabledStatic = true |
451 }() | 455 }() |
452 | 456 |
453 c := context.Background() | 457 c := context.Background() |
454 newC := FilterRDS(c, nil) | 458 newC := FilterRDS(c, nil) |
455 So(newC, ShouldEqual, c) | 459 So(newC, ShouldEqual, c) |
456 }) | 460 }) |
457 } | 461 } |
OLD | NEW |