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

Side by Side Diff: go/src/infra/gae/libs/wrapper/memory/context.go

Issue 1152383003: Simple memory testing for gae/wrapper (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@better_context_lite
Patch Set: fixes Created 5 years, 7 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 package memory
6
7 import (
8 "fmt"
9 "math/rand"
10 "sync"
11
12 "golang.org/x/net/context"
13
14 "appengine/datastore"
15
16 "infra/gae/libs/wrapper"
17 )
18
19 type memContextObj interface {
20 sync.Locker
21 canApplyTxn(m memContextObj) bool
22 applyTxn(rnd *rand.Rand, m memContextObj)
23
24 endTxn()
25 mkTxn(*datastore.TransactionOptions) (memContextObj, error)
26 }
27
28 type memContext []memContextObj
29
30 func newMemContext() memContext {
31 return memContext{
32 newTaskQueueData(),
33 newDataStoreData(),
34 }
35 }
36
37 var memContextIndices = map[string]int{
38 "TQ": 0,
39 "DS": 1,
40 }
41
42 func (m memContext) Get(item string) memContextObj {
43 if i, ok := memContextIndices[item]; !ok {
44 panic(fmt.Errorf("wrapper/memory: cannot get context item %q", i tem))
M-A Ruel 2015/05/25 18:21:08 Why not return nil?
iannucci 2015/05/27 19:33:30 Because it's meaningless. This object is only ever
45 } else {
46 return m[i]
47 }
48 }
49
50 func (m memContext) Lock() {
51 for _, itm := range m {
52 itm.Lock()
53 }
54 }
55
56 func (m memContext) Unlock() {
57 for i := len(m) - 1; i >= 0; i-- {
58 m[i].Unlock()
59 }
60 }
61
62 func (m memContext) endTxn() {
63 for _, itm := range m {
64 itm.endTxn()
65 }
66 }
67
68 func (m memContext) mkTxn(o *datastore.TransactionOptions) (ret memContext, err error) {
69 for _, itm := range m {
70 newItm, err := itm.mkTxn(o)
M-A Ruel 2015/05/25 18:21:08 You alias err here. I'd prefer to not use named re
iannucci 2015/05/27 19:33:30 done, ditched append too since we don't really nee
71 if err != nil {
72 return nil, err
73 }
74 ret = append(ret, newItm)
75 }
76 return ret, nil
77 }
78
79 func (m memContext) canApplyTxn(txnCtx memContext) bool {
80 for i := range m {
M-A Ruel 2015/05/25 18:21:08 Why happens if len(txnCtr) < len(m), panic. :)
iannucci 2015/05/27 19:33:30 yes, that's intentional.
81 if !m[i].canApplyTxn(txnCtx[i]) {
82 return false
83 }
84 }
85 return true
86 }
87
88 func (m memContext) applyTxn(rnd *rand.Rand, txnCtx memContext) {
89 for i := range m {
M-A Ruel 2015/05/25 18:21:08 same
iannucci 2015/05/27 19:33:30 still intentional :)
90 m[i].applyTxn(rnd, txnCtx[i])
91 }
92 }
93
94 // Enable adds a new memory context to c. This new memory context will have
95 // a zeroed state.
96 func Enable(c context.Context) context.Context {
97 return context.WithValue(
98 context.WithValue(c, memContextKey, newMemContext()),
99 giContextKey, newGlobalInfoData())
100 }
101
102 // Use calls ALL of this packages Use* methods on c. This enables all
103 // gae/wrapper Get* api's.
104 func Use(c context.Context) context.Context {
105 return UseTQ(UseDS(UseMC(UseGI(c))))
106 }
107
108 func cur(c context.Context) (p memContext) {
109 p, _ = c.Value(memContextKey).(memContext)
110 return
111 }
112
113 type memContextKeyType int
114
115 var memContextKey memContextKeyType
116
117 // weird stuff
118
119 // RunInTransaction is here because it's really a service-wide transaction, not
120 // just in the datastore. TaskQueue behaves differently in a transaction in
121 // a couple ways, for example.
122 //
123 // It really should have been appengine.Context.RunInTransaction(func(tc...)),
124 // but because it's not, this method is on dsImpl instead to mirror the official
125 // API.
126 //
127 // The fake implementation also differs from the real implementation because the
128 // fake TaskQueue is NOT backed by the fake Datastore. This is done to make the
129 // test-access API for TaskQueue better (instead of trying to reconstitute the
130 // state of the task queue from a bunch of datastore accesses).
131 func (d *dsImpl) RunInTransaction(f func(context.Context) error, o *datastore.Tr ansactionOptions) (err error) {
132 curMC := cur(d.c)
133
134 txnMC, err := curMC.mkTxn(o)
M-A Ruel 2015/05/25 18:21:08 You alias err here, so don't name the return varia
iannucci 2015/05/27 19:33:30 no I don't (http://play.golang.org/p/ZQcAvmI7WQ),
135 if err != nil {
136 return err
137 }
138
139 defer func() {
140 txnMC.Lock()
141 defer txnMC.Unlock()
142
143 txnMC.endTxn()
144 }()
145
146 err = f(context.WithValue(d.c, memContextKey, txnMC))
147 if err != nil {
M-A Ruel 2015/05/25 18:21:08 if err = f(context.WithValue(d.c, memContextKey, t
iannucci 2015/05/27 19:33:30 done
148 return err
149 }
150
151 return func() error {
M-A Ruel 2015/05/25 18:21:08 I don't see why.
iannucci 2015/05/27 19:33:30 used to have code after the function and needed to
152 txnMC.Lock()
153 defer txnMC.Unlock()
154
155 if curMC.canApplyTxn(txnMC) {
156 curMC.applyTxn(wrapper.GetMathRand(d.c), txnMC)
157 } else {
158 return datastore.ErrConcurrentTransaction
159 }
160 return nil
161 }()
162 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698