| OLD | NEW |
| 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 "sync" | 8 "sync" |
| 9 "sync/atomic" | 9 "sync/atomic" |
| 10 "testing" | 10 "testing" |
| 11 | 11 |
| 12 » "github.com/luci/gae/service/datastore" | 12 » ds "github.com/luci/gae/service/datastore" |
| 13 |
| 13 "golang.org/x/net/context" | 14 "golang.org/x/net/context" |
| 14 ) | 15 ) |
| 15 | 16 |
| 16 func TestRaceGetPut(t *testing.T) { | 17 func TestRaceGetPut(t *testing.T) { |
| 17 t.Parallel() | 18 t.Parallel() |
| 18 | 19 |
| 19 value := int32(0) | 20 value := int32(0) |
| 20 num := int32(0) | 21 num := int32(0) |
| 21 | 22 |
| 22 » ds := datastore.Get(Use(context.Background())) | 23 » c := Use(context.Background()) |
| 23 | 24 |
| 24 wg := sync.WaitGroup{} | 25 wg := sync.WaitGroup{} |
| 25 | 26 |
| 26 for i := 0; i < 100; i++ { | 27 for i := 0; i < 100; i++ { |
| 27 wg.Add(1) | 28 wg.Add(1) |
| 28 go func() { | 29 go func() { |
| 29 defer wg.Done() | 30 defer wg.Done() |
| 30 | 31 |
| 31 » » » err := ds.RunInTransaction(func(c context.Context) error
{ | 32 » » » err := ds.RunInTransaction(c, func(c context.Context) er
ror { |
| 32 atomic.AddInt32(&num, 1) | 33 atomic.AddInt32(&num, 1) |
| 33 | 34 |
| 34 » » » » ds := datastore.Get(c) | 35 » » » » obj := pmap("$key", ds.MakeKey(c, "Obj", 1)) |
| 35 | 36 » » » » if err := ds.Get(c, obj); err != nil && err != d
s.ErrNoSuchEntity { |
| 36 » » » » obj := pmap("$key", ds.MakeKey("Obj", 1)) | |
| 37 » » » » if err := ds.Get(obj); err != nil && err != data
store.ErrNoSuchEntity { | |
| 38 t.Fatal("error get", err) | 37 t.Fatal("error get", err) |
| 39 } | 38 } |
| 40 cur := int64(0) | 39 cur := int64(0) |
| 41 if ps := obj.Slice("Value"); len(ps) > 0 { | 40 if ps := obj.Slice("Value"); len(ps) > 0 { |
| 42 cur = ps[0].Value().(int64) | 41 cur = ps[0].Value().(int64) |
| 43 } | 42 } |
| 44 | 43 |
| 45 cur++ | 44 cur++ |
| 46 obj["Value"] = prop(cur) | 45 obj["Value"] = prop(cur) |
| 47 | 46 |
| 48 » » » » return ds.Put(obj) | 47 » » » » return ds.Put(c, obj) |
| 49 » » » }, &datastore.TransactionOptions{Attempts: 200}) | 48 » » » }, &ds.TransactionOptions{Attempts: 200}) |
| 50 | 49 |
| 51 if err != nil { | 50 if err != nil { |
| 52 t.Fatal("error during transaction", err) | 51 t.Fatal("error during transaction", err) |
| 53 } | 52 } |
| 54 | 53 |
| 55 atomic.AddInt32(&value, 1) | 54 atomic.AddInt32(&value, 1) |
| 56 }() | 55 }() |
| 57 } | 56 } |
| 58 wg.Wait() | 57 wg.Wait() |
| 59 | 58 |
| 60 » obj := pmap("$key", ds.MakeKey("Obj", 1)) | 59 » obj := pmap("$key", ds.MakeKey(c, "Obj", 1)) |
| 61 » if ds.Get(obj) != nil { | 60 » if ds.Get(c, obj) != nil { |
| 62 t.FailNow() | 61 t.FailNow() |
| 63 } | 62 } |
| 64 t.Logf("Ran %d inner functions", num) | 63 t.Logf("Ran %d inner functions", num) |
| 65 if int64(value) != obj.Slice("Value")[0].Value().(int64) { | 64 if int64(value) != obj.Slice("Value")[0].Value().(int64) { |
| 66 t.Fatalf("value wrong value %d v %d", value, obj.Slice("Value")[
0].Value().(int64)) | 65 t.Fatalf("value wrong value %d v %d", value, obj.Slice("Value")[
0].Value().(int64)) |
| 67 } | 66 } |
| 68 } | 67 } |
| 69 | 68 |
| 70 func TestRaceNonConflictingPuts(t *testing.T) { | 69 func TestRaceNonConflictingPuts(t *testing.T) { |
| 71 t.Parallel() | 70 t.Parallel() |
| 72 | 71 |
| 73 » ds := datastore.Get(Use(context.Background())) | 72 » c := Use(context.Background()) |
| 74 | 73 |
| 75 num := int32(0) | 74 num := int32(0) |
| 76 | 75 |
| 77 wg := sync.WaitGroup{} | 76 wg := sync.WaitGroup{} |
| 78 | 77 |
| 79 for i := 0; i < 100; i++ { | 78 for i := 0; i < 100; i++ { |
| 80 wg.Add(1) | 79 wg.Add(1) |
| 81 go func() { | 80 go func() { |
| 82 defer wg.Done() | 81 defer wg.Done() |
| 83 | 82 |
| 84 » » » err := ds.RunInTransaction(func(c context.Context) error
{ | 83 » » » err := ds.RunInTransaction(c, func(c context.Context) er
ror { |
| 85 » » » » ds := datastore.Get(c) | 84 » » » » return ds.Put(c, pmap( |
| 86 » » » » return ds.Put(pmap( | |
| 87 "$kind", "Thing", Next, | 85 "$kind", "Thing", Next, |
| 88 "Value", 100)) | 86 "Value", 100)) |
| 89 }, nil) | 87 }, nil) |
| 90 if err != nil { | 88 if err != nil { |
| 91 t.Fatal("error during transaction", err) | 89 t.Fatal("error during transaction", err) |
| 92 } | 90 } |
| 93 atomic.AddInt32(&num, 1) | 91 atomic.AddInt32(&num, 1) |
| 94 }() | 92 }() |
| 95 } | 93 } |
| 96 wg.Wait() | 94 wg.Wait() |
| 97 | 95 |
| 98 if num != 100 { | 96 if num != 100 { |
| 99 t.Fatal("expected 100 runs, got", num) | 97 t.Fatal("expected 100 runs, got", num) |
| 100 } | 98 } |
| 101 } | 99 } |
| OLD | NEW |