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 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 // | 128 // |
129 // It really should have been appengine.Context.RunInTransaction(func(tc...)), | 129 // It really should have been appengine.Context.RunInTransaction(func(tc...)), |
130 // but because it's not, this method is on dsImpl instead to mirror the official | 130 // but because it's not, this method is on dsImpl instead to mirror the official |
131 // API. | 131 // API. |
132 // | 132 // |
133 // The fake implementation also differs from the real implementation because the | 133 // The fake implementation also differs from the real implementation because the |
134 // fake TaskQueue is NOT backed by the fake Datastore. This is done to make the | 134 // fake TaskQueue is NOT backed by the fake Datastore. This is done to make the |
135 // test-access API for TaskQueue better (instead of trying to reconstitute the | 135 // test-access API for TaskQueue better (instead of trying to reconstitute the |
136 // state of the task queue from a bunch of datastore accesses). | 136 // state of the task queue from a bunch of datastore accesses). |
137 func (d *dsImpl) RunInTransaction(f func(context.Context) error, o *ds.Transacti
onOptions) error { | 137 func (d *dsImpl) RunInTransaction(f func(context.Context) error, o *ds.Transacti
onOptions) error { |
138 » curMC := cur(d.c) | 138 » // Keep in separate function for defers. |
| 139 » loopBody := func(applyForReal bool) error { |
| 140 » » curMC := cur(d.c) |
139 | 141 |
140 » txnMC := curMC.mkTxn(o) | 142 » » txnMC := curMC.mkTxn(o) |
141 | 143 |
142 » defer func() { | 144 » » defer func() { |
| 145 » » » txnMC.Lock() |
| 146 » » » defer txnMC.Unlock() |
| 147 |
| 148 » » » txnMC.endTxn() |
| 149 » » }() |
| 150 |
| 151 » » if err := f(context.WithValue(d.c, memContextKey, txnMC)); err !
= nil { |
| 152 » » » return err |
| 153 » » } |
| 154 |
143 txnMC.Lock() | 155 txnMC.Lock() |
144 defer txnMC.Unlock() | 156 defer txnMC.Unlock() |
145 | 157 |
146 » » txnMC.endTxn() | 158 » » if applyForReal && curMC.canApplyTxn(txnMC) { |
147 » }() | 159 » » » curMC.applyTxn(d.c, txnMC) |
148 | 160 » » } else { |
149 » if err := f(context.WithValue(d.c, memContextKey, txnMC)); err != nil { | 161 » » » return ds.ErrConcurrentTransaction |
150 » » return err | 162 » » } |
| 163 » » return nil |
151 } | 164 } |
152 | 165 |
153 » txnMC.Lock() | 166 » // From GAE docs for TransactionOptions: "If omitted, it defaults to 3." |
154 » defer txnMC.Unlock() | 167 » attempts := 3 |
155 | 168 » if o != nil && o.Attempts != 0 { |
156 » if curMC.canApplyTxn(txnMC) { | 169 » » attempts = o.Attempts |
157 » » curMC.applyTxn(d.c, txnMC) | |
158 » } else { | |
159 » » return ds.ErrConcurrentTransaction | |
160 } | 170 } |
161 » return nil | 171 » for attempt := 0; attempt < attempts; attempt++ { |
| 172 » » if err := loopBody(attempt >= d.txnFakeRetry); err != ds.ErrConc
urrentTransaction { |
| 173 » » » return err |
| 174 » » } |
| 175 » } |
| 176 » return ds.ErrConcurrentTransaction |
162 } | 177 } |
OLD | NEW |