Index: impl/memory/context.go |
diff --git a/impl/memory/context.go b/impl/memory/context.go |
index bb784ec540c1603c2194a1f5da2f36e42106285a..ea761bd538b0c8b70e80bbd0ed121ad5a43fc1df 100644 |
--- a/impl/memory/context.go |
+++ b/impl/memory/context.go |
@@ -135,28 +135,52 @@ var memContextKey memContextKeyType |
// test-access API for TaskQueue better (instead of trying to reconstitute the |
// state of the task queue from a bunch of datastore accesses). |
func (d *dsImpl) RunInTransaction(f func(context.Context) error, o *ds.TransactionOptions) error { |
- curMC := cur(d.c) |
+ errNope := errors.New("nope") |
- txnMC := curMC.mkTxn(o) |
+ // Keep in separate function for defers. |
+ loopBody := func(applyForReal bool) error { |
+ curMC := cur(d.c) |
+ |
+ txnMC := curMC.mkTxn(o) |
+ |
+ defer func() { |
+ txnMC.Lock() |
+ defer txnMC.Unlock() |
+ |
+ txnMC.endTxn() |
+ }() |
+ |
+ if err := f(context.WithValue(d.c, memContextKey, txnMC)); err != nil { |
+ return err |
+ } |
- defer func() { |
txnMC.Lock() |
defer txnMC.Unlock() |
- txnMC.endTxn() |
- }() |
+ if !applyForReal { |
+ // Be defensive and expect that f may return ErrConcurrentTransaction. So |
+ // use some other error to signal that we skipped commit. |
+ return errNope |
+ } |
- if err := f(context.WithValue(d.c, memContextKey, txnMC)); err != nil { |
- return err |
+ if curMC.canApplyTxn(txnMC) { |
+ curMC.applyTxn(d.c, txnMC) |
+ } else { |
+ return ds.ErrConcurrentTransaction |
+ } |
+ return nil |
} |
- txnMC.Lock() |
- defer txnMC.Unlock() |
- |
- if curMC.canApplyTxn(txnMC) { |
- curMC.applyTxn(d.c, txnMC) |
- } else { |
- return ds.ErrConcurrentTransaction |
+ // From GAE docs for TransactionOptions: "If omitted, it defaults to 3." |
+ maxAttempts := 3 |
+ if o != nil && o.Attempts != 0 { |
+ maxAttempts = o.Attempts |
+ } |
+ for attempt := 0; attempt < maxAttempts; attempt++ { |
+ err := loopBody(attempt >= d.txnFakeRetry) |
+ if err != errNope { |
+ return err |
+ } |
} |
- return nil |
+ return ds.ErrConcurrentTransaction |
iannucci
2015/09/11 22:31:11
Can we return a different error when the retries d
Vadim Sh.
2015/09/14 01:07:20
Real GAE returns ErrConcurrentTransaction: https:/
|
} |