transaction.go 3.4 KB

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