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 memory | 5 package memory |
6 | 6 |
7 import ( | 7 import ( |
8 "errors" | 8 "errors" |
9 "sync" | 9 "sync" |
10 | 10 |
11 ds "github.com/luci/gae/service/datastore" | 11 ds "github.com/luci/gae/service/datastore" |
12 "golang.org/x/net/context" | 12 "golang.org/x/net/context" |
13 ) | 13 ) |
14 | 14 |
15 var serializationDeterministic = false | 15 var serializationDeterministic = false |
16 | 16 |
17 type memContextObj interface { | 17 type memContextObj interface { |
18 sync.Locker | 18 sync.Locker |
19 canApplyTxn(m memContextObj) bool | 19 canApplyTxn(m memContextObj) bool |
20 applyTxn(c context.Context, m memContextObj) | 20 applyTxn(c context.Context, m memContextObj) |
21 | 21 |
22 endTxn() | 22 endTxn() |
23 mkTxn(*ds.TransactionOptions) memContextObj | 23 mkTxn(*ds.TransactionOptions) memContextObj |
24 } | 24 } |
25 | 25 |
26 type memContext []memContextObj | 26 type memContext []memContextObj |
27 | 27 |
28 var _ = memContextObj((memContext)(nil)) | 28 var _ memContextObj = (*memContext)(nil) |
29 | 29 |
30 func newMemContext(aid string) memContext { | 30 func newMemContext(aid string) *memContext { |
31 » return memContext{ | 31 » return &memContext{ |
32 newTaskQueueData(), | 32 newTaskQueueData(), |
33 newDataStoreData(aid), | 33 newDataStoreData(aid), |
34 } | 34 } |
35 } | 35 } |
36 | 36 |
37 type memContextIdx int | 37 type memContextIdx int |
38 | 38 |
39 const ( | 39 const ( |
40 memContextTQIdx memContextIdx = iota | 40 memContextTQIdx memContextIdx = iota |
41 memContextDSIdx | 41 memContextDSIdx |
42 ) | 42 ) |
43 | 43 |
44 func (m memContext) Get(itm memContextIdx) memContextObj { | 44 func (m *memContext) Get(itm memContextIdx) memContextObj { |
45 » return m[itm] | 45 » return (*m)[itm] |
46 } | 46 } |
47 | 47 |
48 func (m memContext) Lock() { | 48 func (m *memContext) Lock() { |
49 » for _, itm := range m { | 49 » for _, itm := range *m { |
50 itm.Lock() | 50 itm.Lock() |
51 } | 51 } |
52 } | 52 } |
53 | 53 |
54 func (m memContext) Unlock() { | 54 func (m *memContext) Unlock() { |
55 » for i := len(m) - 1; i >= 0; i-- { | 55 » for i := len(*m) - 1; i >= 0; i-- { |
56 » » m[i].Unlock() | 56 » » (*m)[i].Unlock() |
57 } | 57 } |
58 } | 58 } |
59 | 59 |
60 func (m memContext) endTxn() { | 60 func (m *memContext) endTxn() { |
61 » for _, itm := range m { | 61 » for _, itm := range *m { |
62 itm.endTxn() | 62 itm.endTxn() |
63 } | 63 } |
64 } | 64 } |
65 | 65 |
66 func (m memContext) mkTxn(o *ds.TransactionOptions) memContextObj { | 66 func (m *memContext) mkTxn(o *ds.TransactionOptions) memContextObj { |
67 » ret := make(memContext, len(m)) | 67 » ret := make(memContext, len(*m)) |
68 » for i, itm := range m { | 68 » for i, itm := range *m { |
69 ret[i] = itm.mkTxn(o) | 69 ret[i] = itm.mkTxn(o) |
70 } | 70 } |
71 » return ret | 71 » return &ret |
72 } | 72 } |
73 | 73 |
74 func (m memContext) canApplyTxn(txnCtxObj memContextObj) bool { | 74 func (m *memContext) canApplyTxn(txnCtxObj memContextObj) bool { |
75 » txnCtx := txnCtxObj.(memContext) | 75 » txnCtx := *txnCtxObj.(*memContext) |
76 » for i := range m { | 76 » for i := range *m { |
77 » » if !m[i].canApplyTxn(txnCtx[i]) { | 77 » » if !(*m)[i].canApplyTxn(txnCtx[i]) { |
78 return false | 78 return false |
79 } | 79 } |
80 } | 80 } |
81 return true | 81 return true |
82 } | 82 } |
83 | 83 |
84 func (m memContext) applyTxn(c context.Context, txnCtxObj memContextObj) { | 84 func (m *memContext) applyTxn(c context.Context, txnCtxObj memContextObj) { |
85 » txnCtx := txnCtxObj.(memContext) | 85 » txnCtx := *txnCtxObj.(*memContext) |
86 » for i := range m { | 86 » for i := range *m { |
87 » » m[i].applyTxn(c, txnCtx[i]) | 87 » » (*m)[i].applyTxn(c, txnCtx[i]) |
88 } | 88 } |
89 } | 89 } |
90 | 90 |
91 // Use calls UseWithAppID with the appid of "dev~app" | 91 // Use calls UseWithAppID with the appid of "dev~app" |
92 func Use(c context.Context) context.Context { | 92 func Use(c context.Context) context.Context { |
93 return UseWithAppID(c, "dev~app") | 93 return UseWithAppID(c, "dev~app") |
94 } | 94 } |
95 | 95 |
96 // UseWithAppID adds implementations for the following gae interfaces to the | 96 // UseWithAppID adds implementations for the following gae interfaces to the |
97 // context: | 97 // context: |
98 // * gae.Datastore | 98 // * gae.Datastore |
99 // * gae.TaskQueue | 99 // * gae.TaskQueue |
100 // * gae.Memcache | 100 // * gae.Memcache |
101 // * gae.GlobalInfo | 101 // * gae.GlobalInfo |
102 // | 102 // |
103 // The application id wil be set to 'aid', and will not be modifiable in this | 103 // The application id wil be set to 'aid', and will not be modifiable in this |
104 // context. | 104 // context. |
105 // | 105 // |
106 // These can be retrieved with the gae.Get functions. | 106 // These can be retrieved with the gae.Get functions. |
107 // | 107 // |
108 // The implementations are all backed by an in-memory implementation, and start | 108 // The implementations are all backed by an in-memory implementation, and start |
109 // with an empty state. | 109 // with an empty state. |
110 // | 110 // |
111 // Using this more than once per context.Context will cause a panic. | 111 // Using this more than once per context.Context will cause a panic. |
112 func UseWithAppID(c context.Context, aid string) context.Context { | 112 func UseWithAppID(c context.Context, aid string) context.Context { |
113 if c.Value(memContextKey) != nil { | 113 if c.Value(memContextKey) != nil { |
114 panic(errors.New("memory.Use: called twice on the same Context")
) | 114 panic(errors.New("memory.Use: called twice on the same Context")
) |
115 } | 115 } |
116 » c = context.WithValue( | 116 » memctx := newMemContext(aid) |
117 » » context.WithValue(c, memContextKey, newMemContext(aid)), | 117 » c = context.WithValue(c, memContextKey, memctx) |
118 » » giContextKey, &globalInfoData{appid: aid}) | 118 » c = context.WithValue(c, memContextNoTxnKey, memctx) |
| 119 » c = context.WithValue(c, giContextKey, &globalInfoData{appid: aid}) |
| 120 |
119 return useTQ(useRDS(useMC(useGI(c, aid)))) | 121 return useTQ(useRDS(useMC(useGI(c, aid)))) |
120 } | 122 } |
121 | 123 |
122 func cur(c context.Context) (p memContext) { | 124 func cur(c context.Context) (p *memContext) { |
123 » p, _ = c.Value(memContextKey).(memContext) | 125 » p, _ = c.Value(memContextKey).(*memContext) |
| 126 » return |
| 127 } |
| 128 |
| 129 func curNoTxn(c context.Context) (p *memContext) { |
| 130 » p, _ = c.Value(memContextNoTxnKey).(*memContext) |
124 return | 131 return |
125 } | 132 } |
126 | 133 |
127 type memContextKeyType int | 134 type memContextKeyType int |
128 | 135 |
129 var memContextKey memContextKeyType | 136 var ( |
| 137 » memContextKey memContextKeyType |
| 138 » memContextNoTxnKey memContextKeyType = 1 |
| 139 ) |
130 | 140 |
131 // weird stuff | 141 // weird stuff |
132 | 142 |
133 // RunInTransaction is here because it's really a service-wide transaction, not | 143 // RunInTransaction is here because it's really a service-wide transaction, not |
134 // just in the datastore. TaskQueue behaves differently in a transaction in | 144 // just in the datastore. TaskQueue behaves differently in a transaction in |
135 // a couple ways, for example. | 145 // a couple ways, for example. |
136 // | 146 // |
137 // It really should have been appengine.Context.RunInTransaction(func(tc...)), | 147 // It really should have been appengine.Context.RunInTransaction(func(tc...)), |
138 // but because it's not, this method is on dsImpl instead to mirror the official | 148 // but because it's not, this method is on dsImpl instead to mirror the official |
139 // API. | 149 // API. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 if o != nil && o.Attempts != 0 { | 190 if o != nil && o.Attempts != 0 { |
181 attempts = o.Attempts | 191 attempts = o.Attempts |
182 } | 192 } |
183 for attempt := 0; attempt < attempts; attempt++ { | 193 for attempt := 0; attempt < attempts; attempt++ { |
184 if err := loopBody(attempt >= d.data.txnFakeRetry); err != ds.Er
rConcurrentTransaction { | 194 if err := loopBody(attempt >= d.data.txnFakeRetry); err != ds.Er
rConcurrentTransaction { |
185 return err | 195 return err |
186 } | 196 } |
187 } | 197 } |
188 return ds.ErrConcurrentTransaction | 198 return ds.ErrConcurrentTransaction |
189 } | 199 } |
OLD | NEW |