@@ -14,25 +14,35 @@ type txBeginner interface {
14
14
BeginTx (context.Context , * sql.TxOptions ) (* sql.Tx , error )
15
15
}
16
16
17
- func beginMultiTx (ctx context.Context , opts * sql.TxOptions , txb ... txBeginner ) ([] * sql. Tx , error ) {
17
+ func beginMultiTx (ctx context.Context , opts * sql.TxOptions , txb map [ string ] txBeginner , errCallback ErrCallbackFunc ) (map [ string ] executor , error ) {
18
18
type result struct {
19
- tx * sql.Tx
20
- err error
19
+ name string
20
+ tx * sql.Tx
21
+ err error
21
22
}
22
23
23
24
rc := make (chan result , len (txb ))
24
25
25
- for _ , n := range txb {
26
- go func (n txBeginner ) {
27
- var r result
28
- r .tx , r .err = n .BeginTx (ctx , opts )
26
+ for name , b := range txb {
27
+ go func (name string , b txBeginner ) {
28
+ r := result {name : name }
29
+
30
+ r .tx , r .err = b .BeginTx (ctx , opts )
31
+ if r .err != nil {
32
+ r .err = & NodeError {name , r .err }
33
+
34
+ if errCallback != nil {
35
+ errCallback (r .err )
36
+ }
37
+ }
38
+
29
39
rc <- r
30
- }(n )
40
+ }(name , b )
31
41
}
32
42
33
43
var errs []error
34
44
35
- txs := make ([] * sql. Tx , 0 , len (txb ))
45
+ txs := make (map [ string ] executor , len (txb ))
36
46
37
47
for i := 0 ; i < len (txb ); i ++ {
38
48
r := <- rc
@@ -42,8 +52,7 @@ func beginMultiTx(ctx context.Context, opts *sql.TxOptions, txb ...txBeginner) (
42
52
continue
43
53
}
44
54
45
- txs = append (txs , r .tx )
46
-
55
+ txs [r .name ] = r .tx
47
56
}
48
57
49
58
if errs != nil {
@@ -60,9 +69,10 @@ func beginMultiTx(ctx context.Context, opts *sql.TxOptions, txb ...txBeginner) (
60
69
// MultiTx holds a slice of open transactions to multiple nodes.
61
70
// All methods on this type run their sql.Tx variant in one Go routine per Node.
62
71
type MultiTx struct {
63
- tx []* sql.Tx
64
- wg sync.WaitGroup
65
- cancel context.CancelFunc
72
+ tx map [string ]executor
73
+ wg sync.WaitGroup
74
+ cancel context.CancelFunc
75
+ errCallback ErrCallbackFunc
66
76
}
67
77
68
78
// cancelWait cancels a previously running operation on TX
@@ -91,11 +101,20 @@ func (m *MultiTx) cancelWait() {
91
101
func (m * MultiTx ) Rollback () error {
92
102
m .cancelWait ()
93
103
ec := make (chan error , len (m .tx ))
94
- for _ , tx := range m .tx {
95
- go func (tx * sql.Tx ) {
104
+
105
+ for name , tx := range m .tx {
106
+ go func (name string , tx * sql.Tx ) {
96
107
err := tx .Rollback ()
108
+ if err != nil {
109
+ err = & NodeError {name , err }
110
+ }
111
+
112
+ if m .errCallback != nil {
113
+ m .errCallback (err )
114
+ }
115
+
97
116
ec <- err
98
- }(tx )
117
+ }(name , tx .( * sql. Tx ) )
99
118
}
100
119
101
120
var errs []error
@@ -125,10 +144,20 @@ func (m *MultiTx) Rollback() error {
125
144
// This method is primarily included to implement boil.Transactor
126
145
func (m * MultiTx ) Commit () error {
127
146
ec := make (chan error , len (m .tx ))
128
- for _ , tx := range m .tx {
129
- go func (tx * sql.Tx ) {
130
- ec <- tx .Commit ()
131
- }(tx )
147
+
148
+ for name , tx := range m .tx {
149
+ go func (name string , tx * sql.Tx ) {
150
+ err := tx .Commit ()
151
+ if err != nil {
152
+ err = & NodeError {name , err }
153
+ }
154
+
155
+ if m .errCallback != nil {
156
+ m .errCallback (err )
157
+ }
158
+
159
+ ec <- err
160
+ }(name , tx .(* sql.Tx ))
132
161
}
133
162
134
163
var errs []error
@@ -159,7 +188,7 @@ func (m *MultiTx) context(ctx context.Context) context.Context {
159
188
// It does not make much sense to run this method against multiple Nodes, as they are ussualy slaves.
160
189
// This method is primarily included to implement boil.ContextExecutor.
161
190
func (m * MultiTx ) ExecContext (ctx context.Context , query string , args ... interface {}) (res sql.Result , err error ) {
162
- return multiExec (m .context (ctx ), & m .wg , mtx2Exec ( m .tx ) , query , args ... )
191
+ return multiExec (m .context (ctx ), & m .wg , m .tx , m . errCallback , query , args ... )
163
192
}
164
193
165
194
// Exec runs ExecContext with context.Background().
@@ -178,7 +207,7 @@ func (m *MultiTx) Exec(query string, args ...interface{}) (sql.Result, error) {
178
207
//
179
208
// Implements boil.ContextExecutor.
180
209
func (m * MultiTx ) QueryContext (ctx context.Context , query string , args ... interface {}) (rows * sql.Rows , err error ) {
181
- return multiQuery (m .context (ctx ), & m .wg , mtx2Exec ( m .tx ) , query , args ... )
210
+ return multiQuery (m .context (ctx ), & m .wg , m .tx , m . errCallback , query , args ... )
182
211
}
183
212
184
213
// Query runs QueryContext with context.Background().
@@ -195,7 +224,7 @@ func (m *MultiTx) Query(query string, args ...interface{}) (*sql.Rows, error) {
195
224
// If you have a choice, stick with a regular QueryContext.
196
225
// This method is primarily included to implement boil.Executor.
197
226
func (m * MultiTx ) QueryRowContext (ctx context.Context , query string , args ... interface {}) * sql.Row {
198
- return multiQueryRow (m .context (ctx ), & m .wg , mtx2Exec ( m .tx ) , query , args ... )
227
+ return multiQueryRow (m .context (ctx ), & m .wg , m .tx , m . errCallback , query , args ... )
199
228
}
200
229
201
230
// QueryRow wrapper around sql.DB.QueryRow.
0 commit comments