firestore: reset transaction write state in between retries
Change-Id: I308aaaea52bb25a50aeca42bfda65ae54fefdf0c
Reviewed-on: https://code-review.googlesource.com/c/36092
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Michael Lehenbauer <mikelehen@google.com>
Reviewed-by: Eno Compton <enocom@google.com>
diff --git a/firestore/transaction.go b/firestore/transaction.go
index 5bfe3e7..20a8a2a 100644
--- a/firestore/transaction.go
+++ b/firestore/transaction.go
@@ -172,6 +172,9 @@
err = cerr
break
}
+
+ // Reset state for the next attempt.
+ t.writes = nil
}
// If we run out of retries, return the last error we saw (which should
// be the Aborted from Commit, or a context error).
diff --git a/firestore/transaction_test.go b/firestore/transaction_test.go
index 3955a1a..758d11c 100644
--- a/firestore/transaction_test.go
+++ b/firestore/transaction_test.go
@@ -392,3 +392,77 @@
t.Fatal(err)
}
}
+
+// Each retry attempt has the same amount of commit writes.
+func TestRunTransaction_Retries(t *testing.T) {
+ ctx := context.Background()
+ const db = "projects/projectID/databases/(default)"
+ tid := []byte{1}
+ c, srv := newMock(t)
+
+ srv.addRPC(
+ &pb.BeginTransactionRequest{Database: db},
+ &pb.BeginTransactionResponse{Transaction: tid},
+ )
+
+ aDoc := &pb.Document{
+ Name: db + "/documents/C/a",
+ CreateTime: aTimestamp,
+ UpdateTime: aTimestamp2,
+ Fields: map[string]*pb.Value{"count": intval(1)},
+ }
+ aDoc2 := &pb.Document{
+ Name: aDoc.Name,
+ Fields: map[string]*pb.Value{"count": intval(7)},
+ }
+
+ srv.addRPC(
+ &pb.CommitRequest{
+ Database: db,
+ Transaction: tid,
+ Writes: []*pb.Write{{
+ Operation: &pb.Write_Update{aDoc2},
+ UpdateMask: &pb.DocumentMask{FieldPaths: []string{"count"}},
+ CurrentDocument: &pb.Precondition{
+ ConditionType: &pb.Precondition_Exists{true},
+ },
+ }},
+ },
+ status.Errorf(codes.Aborted, "something failed! please retry me!"),
+ )
+
+ srv.addRPC(
+ &pb.BeginTransactionRequest{
+ Database: db,
+ Options: &pb.TransactionOptions{
+ Mode: &pb.TransactionOptions_ReadWrite_{
+ &pb.TransactionOptions_ReadWrite{RetryTransaction: tid},
+ },
+ },
+ },
+ &pb.BeginTransactionResponse{Transaction: tid},
+ )
+
+ srv.addRPC(
+ &pb.CommitRequest{
+ Database: db,
+ Transaction: tid,
+ Writes: []*pb.Write{{
+ Operation: &pb.Write_Update{aDoc2},
+ UpdateMask: &pb.DocumentMask{FieldPaths: []string{"count"}},
+ CurrentDocument: &pb.Precondition{
+ ConditionType: &pb.Precondition_Exists{true},
+ },
+ }},
+ },
+ &pb.CommitResponse{CommitTime: aTimestamp3},
+ )
+
+ err := c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error {
+ docref := c.Collection("C").Doc("a")
+ return tx.Update(docref, []Update{{Path: "count", Value: 7}})
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+}