diff options
Diffstat (limited to 'vendor/google.golang.org/appengine/datastore/transaction.go')
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/transaction.go | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/vendor/google.golang.org/appengine/datastore/transaction.go b/vendor/google.golang.org/appengine/datastore/transaction.go new file mode 100644 index 0000000..2ae8428 --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/transaction.go | |||
@@ -0,0 +1,96 @@ | |||
1 | // Copyright 2011 Google Inc. All rights reserved. | ||
2 | // Use of this source code is governed by the Apache 2.0 | ||
3 | // license that can be found in the LICENSE file. | ||
4 | |||
5 | package datastore | ||
6 | |||
7 | import ( | ||
8 | "errors" | ||
9 | |||
10 | "golang.org/x/net/context" | ||
11 | |||
12 | "google.golang.org/appengine/internal" | ||
13 | pb "google.golang.org/appengine/internal/datastore" | ||
14 | ) | ||
15 | |||
16 | func init() { | ||
17 | internal.RegisterTransactionSetter(func(x *pb.Query, t *pb.Transaction) { | ||
18 | x.Transaction = t | ||
19 | }) | ||
20 | internal.RegisterTransactionSetter(func(x *pb.GetRequest, t *pb.Transaction) { | ||
21 | x.Transaction = t | ||
22 | }) | ||
23 | internal.RegisterTransactionSetter(func(x *pb.PutRequest, t *pb.Transaction) { | ||
24 | x.Transaction = t | ||
25 | }) | ||
26 | internal.RegisterTransactionSetter(func(x *pb.DeleteRequest, t *pb.Transaction) { | ||
27 | x.Transaction = t | ||
28 | }) | ||
29 | } | ||
30 | |||
31 | // ErrConcurrentTransaction is returned when a transaction is rolled back due | ||
32 | // to a conflict with a concurrent transaction. | ||
33 | var ErrConcurrentTransaction = errors.New("datastore: concurrent transaction") | ||
34 | |||
35 | // RunInTransaction runs f in a transaction. It calls f with a transaction | ||
36 | // context tc that f should use for all App Engine operations. | ||
37 | // | ||
38 | // If f returns nil, RunInTransaction attempts to commit the transaction, | ||
39 | // returning nil if it succeeds. If the commit fails due to a conflicting | ||
40 | // transaction, RunInTransaction retries f, each time with a new transaction | ||
41 | // context. It gives up and returns ErrConcurrentTransaction after three | ||
42 | // failed attempts. The number of attempts can be configured by specifying | ||
43 | // TransactionOptions.Attempts. | ||
44 | // | ||
45 | // If f returns non-nil, then any datastore changes will not be applied and | ||
46 | // RunInTransaction returns that same error. The function f is not retried. | ||
47 | // | ||
48 | // Note that when f returns, the transaction is not yet committed. Calling code | ||
49 | // must be careful not to assume that any of f's changes have been committed | ||
50 | // until RunInTransaction returns nil. | ||
51 | // | ||
52 | // Since f may be called multiple times, f should usually be idempotent. | ||
53 | // datastore.Get is not idempotent when unmarshaling slice fields. | ||
54 | // | ||
55 | // Nested transactions are not supported; c may not be a transaction context. | ||
56 | func RunInTransaction(c context.Context, f func(tc context.Context) error, opts *TransactionOptions) error { | ||
57 | xg := false | ||
58 | if opts != nil { | ||
59 | xg = opts.XG | ||
60 | } | ||
61 | readOnly := false | ||
62 | if opts != nil { | ||
63 | readOnly = opts.ReadOnly | ||
64 | } | ||
65 | attempts := 3 | ||
66 | if opts != nil && opts.Attempts > 0 { | ||
67 | attempts = opts.Attempts | ||
68 | } | ||
69 | var t *pb.Transaction | ||
70 | var err error | ||
71 | for i := 0; i < attempts; i++ { | ||
72 | if t, err = internal.RunTransactionOnce(c, f, xg, readOnly, t); err != internal.ErrConcurrentTransaction { | ||
73 | return err | ||
74 | } | ||
75 | } | ||
76 | return ErrConcurrentTransaction | ||
77 | } | ||
78 | |||
79 | // TransactionOptions are the options for running a transaction. | ||
80 | type TransactionOptions struct { | ||
81 | // XG is whether the transaction can cross multiple entity groups. In | ||
82 | // comparison, a single group transaction is one where all datastore keys | ||
83 | // used have the same root key. Note that cross group transactions do not | ||
84 | // have the same behavior as single group transactions. In particular, it | ||
85 | // is much more likely to see partially applied transactions in different | ||
86 | // entity groups, in global queries. | ||
87 | // It is valid to set XG to true even if the transaction is within a | ||
88 | // single entity group. | ||
89 | XG bool | ||
90 | // Attempts controls the number of retries to perform when commits fail | ||
91 | // due to a conflicting transaction. If omitted, it defaults to 3. | ||
92 | Attempts int | ||
93 | // ReadOnly controls whether the transaction is a read only transaction. | ||
94 | // Read only transactions are potentially more efficient. | ||
95 | ReadOnly bool | ||
96 | } | ||