...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package clientv3
16
17 import (
18 "context"
19 "sync"
20
21 pb "go.etcd.io/etcd/api/v3/etcdserverpb"
22
23 "google.golang.org/grpc"
24 )
25
26
27
28
29
30
31
32
33
34
35
36 type Txn interface {
37
38
39
40 If(cs ...Cmp) Txn
41
42
43
44 Then(ops ...Op) Txn
45
46
47
48 Else(ops ...Op) Txn
49
50
51 Commit() (*TxnResponse, error)
52 }
53
54 type txn struct {
55 kv *kv
56 ctx context.Context
57
58 mu sync.Mutex
59 cif bool
60 cthen bool
61 celse bool
62
63 isWrite bool
64
65 cmps []*pb.Compare
66
67 sus []*pb.RequestOp
68 fas []*pb.RequestOp
69
70 callOpts []grpc.CallOption
71 }
72
73 func (txn *txn) If(cs ...Cmp) Txn {
74 txn.mu.Lock()
75 defer txn.mu.Unlock()
76
77 if txn.cif {
78 panic("cannot call If twice!")
79 }
80
81 if txn.cthen {
82 panic("cannot call If after Then!")
83 }
84
85 if txn.celse {
86 panic("cannot call If after Else!")
87 }
88
89 txn.cif = true
90
91 for i := range cs {
92 txn.cmps = append(txn.cmps, (*pb.Compare)(&cs[i]))
93 }
94
95 return txn
96 }
97
98 func (txn *txn) Then(ops ...Op) Txn {
99 txn.mu.Lock()
100 defer txn.mu.Unlock()
101
102 if txn.cthen {
103 panic("cannot call Then twice!")
104 }
105 if txn.celse {
106 panic("cannot call Then after Else!")
107 }
108
109 txn.cthen = true
110
111 for _, op := range ops {
112 txn.isWrite = txn.isWrite || op.isWrite()
113 txn.sus = append(txn.sus, op.toRequestOp())
114 }
115
116 return txn
117 }
118
119 func (txn *txn) Else(ops ...Op) Txn {
120 txn.mu.Lock()
121 defer txn.mu.Unlock()
122
123 if txn.celse {
124 panic("cannot call Else twice!")
125 }
126
127 txn.celse = true
128
129 for _, op := range ops {
130 txn.isWrite = txn.isWrite || op.isWrite()
131 txn.fas = append(txn.fas, op.toRequestOp())
132 }
133
134 return txn
135 }
136
137 func (txn *txn) Commit() (*TxnResponse, error) {
138 txn.mu.Lock()
139 defer txn.mu.Unlock()
140
141 r := &pb.TxnRequest{Compare: txn.cmps, Success: txn.sus, Failure: txn.fas}
142
143 var resp *pb.TxnResponse
144 var err error
145 resp, err = txn.kv.remote.Txn(txn.ctx, r, txn.callOpts...)
146 if err != nil {
147 return nil, toErr(txn.ctx, err)
148 }
149 return (*TxnResponse)(resp), nil
150 }
151
View as plain text