@@ -37,6 +37,14 @@ type transactionSettings struct {
37
37
readOnly bool
38
38
prevID []byte // ID of the transaction to retry
39
39
readTime * timestamppb.Timestamp
40
+
41
+ // When set, skips the initial BeginTransaction RPC call to obtain txn id and
42
+ // uses the piggybacked txn id from first read rpc call.
43
+ // If there are no read operations on transaction, BeginTransaction RPC call is made
44
+ // before rollback or commit
45
+ // Currently, this setting is set but unused
46
+ // TODO: b/291258189 - Use this setting
47
+ beginLater bool
40
48
}
41
49
42
50
// newTransactionSettings creates a transactionSettings with a given TransactionOption slice.
@@ -91,6 +99,7 @@ var ReadOnly TransactionOption
91
99
92
100
func init () {
93
101
ReadOnly = readOnly {}
102
+ BeginLater = beginLater {}
94
103
}
95
104
96
105
type readOnly struct {}
@@ -99,6 +108,25 @@ func (readOnly) apply(s *transactionSettings) {
99
108
s .readOnly = true
100
109
}
101
110
111
+ // BeginLater is a TransactionOption that can be used to improve transaction performance
112
+ // Currently, it is a no-op
113
+ // TODO: b/291258189 - Add implementation
114
+ var BeginLater TransactionOption
115
+
116
+ type beginLater struct {}
117
+
118
+ func (beginLater ) apply (s * transactionSettings ) {
119
+ s .beginLater = true
120
+ }
121
+
122
+ type transactionState int
123
+
124
+ const (
125
+ transactionStateNotStarted transactionState = iota // Currently unused
126
+ transactionStateInProgress
127
+ transactionStateExpired
128
+ )
129
+
102
130
// Transaction represents a set of datastore operations to be committed atomically.
103
131
//
104
132
// Operations are enqueued by calling the Put and Delete methods on Transaction
@@ -114,6 +142,8 @@ type Transaction struct {
114
142
ctx context.Context
115
143
mutations []* pb.Mutation // The mutations to apply.
116
144
pending map [int ]* PendingKey // Map from mutation index to incomplete keys pending transaction completion.
145
+ settings * transactionSettings
146
+ state transactionState
117
147
}
118
148
119
149
// NewTransaction starts a new transaction.
@@ -167,6 +197,8 @@ func (c *Client) newTransaction(ctx context.Context, s *transactionSettings) (_
167
197
client : c ,
168
198
mutations : nil ,
169
199
pending : make (map [int ]* PendingKey ),
200
+ state : transactionStateInProgress ,
201
+ settings : s ,
170
202
}, nil
171
203
}
172
204
@@ -223,7 +255,7 @@ func (t *Transaction) Commit() (c *Commit, err error) {
223
255
t .ctx = trace .StartSpan (t .ctx , "cloud.google.com/go/datastore.Transaction.Commit" )
224
256
defer func () { trace .EndSpan (t .ctx , err ) }()
225
257
226
- if t .id == nil {
258
+ if t .state == transactionStateExpired {
227
259
return nil , errExpiredTransaction
228
260
}
229
261
req := & pb.CommitRequest {
@@ -237,7 +269,7 @@ func (t *Transaction) Commit() (c *Commit, err error) {
237
269
if status .Code (err ) == codes .Aborted {
238
270
return nil , ErrConcurrentTransaction
239
271
}
240
- t .id = nil // mark the transaction as expired
272
+ t .state = transactionStateExpired // mark the transaction as expired
241
273
if err != nil {
242
274
return nil , err
243
275
}
@@ -264,15 +296,14 @@ func (t *Transaction) Rollback() (err error) {
264
296
t .ctx = trace .StartSpan (t .ctx , "cloud.google.com/go/datastore.Transaction.Rollback" )
265
297
defer func () { trace .EndSpan (t .ctx , err ) }()
266
298
267
- if t .id == nil {
299
+ if t .state == transactionStateExpired {
268
300
return errExpiredTransaction
269
301
}
270
- id := t .id
271
- t .id = nil
302
+ t .state = transactionStateExpired
272
303
_ , err = t .client .client .Rollback (t .ctx , & pb.RollbackRequest {
273
304
ProjectId : t .client .dataset ,
274
305
DatabaseId : t .client .databaseID ,
275
- Transaction : id ,
306
+ Transaction : t . id ,
276
307
})
277
308
return err
278
309
}
@@ -303,7 +334,7 @@ func (t *Transaction) GetMulti(keys []*Key, dst interface{}) (err error) {
303
334
t .ctx = trace .StartSpan (t .ctx , "cloud.google.com/go/datastore.Transaction.GetMulti" )
304
335
defer func () { trace .EndSpan (t .ctx , err ) }()
305
336
306
- if t .id == nil {
337
+ if t .state == transactionStateExpired {
307
338
return errExpiredTransaction
308
339
}
309
340
opts := & pb.ReadOptions {
@@ -336,7 +367,7 @@ func (t *Transaction) Put(key *Key, src interface{}) (*PendingKey, error) {
336
367
// element of src in the same order.
337
368
// TODO(jba): rewrite in terms of Mutate.
338
369
func (t * Transaction ) PutMulti (keys []* Key , src interface {}) (ret []* PendingKey , err error ) {
339
- if t .id == nil {
370
+ if t .state == transactionStateExpired {
340
371
return nil , errExpiredTransaction
341
372
}
342
373
mutations , err := putMutations (keys , src )
@@ -376,7 +407,7 @@ func (t *Transaction) Delete(key *Key) error {
376
407
// DeleteMulti is a batch version of Delete.
377
408
// TODO(jba): rewrite in terms of Mutate.
378
409
func (t * Transaction ) DeleteMulti (keys []* Key ) (err error ) {
379
- if t .id == nil {
410
+ if t .state == transactionStateExpired {
380
411
return errExpiredTransaction
381
412
}
382
413
mutations , err := deleteMutations (keys )
@@ -396,7 +427,7 @@ func (t *Transaction) DeleteMulti(keys []*Key) (err error) {
396
427
//
397
428
// For an example, see Client.Mutate.
398
429
func (t * Transaction ) Mutate (muts ... * Mutation ) ([]* PendingKey , error ) {
399
- if t .id == nil {
430
+ if t .state == transactionStateExpired {
400
431
return nil , errExpiredTransaction
401
432
}
402
433
pmuts , err := mutationProtos (muts )
0 commit comments