@@ -30,6 +30,10 @@ import (
30
30
"go.etcd.io/etcd/tests/v3/robustness/report"
31
31
)
32
32
33
+ var (
34
+ errClientIsClosed = errors .New ("client is closed" )
35
+ )
36
+
33
37
// RecordingClient provides a semi-etcd client (different interface than
34
38
// clientv3.Client) that records all the requests and responses made. Doesn't
35
39
// allow for concurrent requests to conform to model.AppendableHistory requirements.
@@ -45,6 +49,8 @@ type RecordingClient struct {
45
49
// mux ensures order of request appending.
46
50
kvMux sync.Mutex
47
51
kvOperations * model.AppendableHistory
52
+
53
+ isClosed bool
48
54
}
49
55
50
56
var _ clientv3.KV = (* RecordingClient )(nil )
@@ -69,11 +75,20 @@ func NewRecordingClient(endpoints []string, ids identity.Provider, baseTime time
69
75
client : * cc ,
70
76
kvOperations : model .NewAppendableHistory (ids ),
71
77
baseTime : baseTime ,
78
+ isClosed : false ,
72
79
}, nil
73
80
}
74
81
75
82
func (c * RecordingClient ) Close () error {
76
- return c .client .Close ()
83
+ c .kvMux .Lock ()
84
+ defer c .kvMux .Unlock ()
85
+ if c .isClosed {
86
+ return nil
87
+ }
88
+
89
+ err := c .client .Close ()
90
+ c .isClosed = true // if we set to true only if there is no error, we need to handle the retry in defer
91
+ return err
77
92
}
78
93
79
94
func (c * RecordingClient ) Report () report.ClientReport {
@@ -94,6 +109,12 @@ func (c *RecordingClient) Get(ctx context.Context, key string, opts ...clientv3.
94
109
}
95
110
96
111
func (c * RecordingClient ) Range (ctx context.Context , start , end string , revision , limit int64 ) (* clientv3.GetResponse , error ) {
112
+ c .kvMux .Lock ()
113
+ defer c .kvMux .Unlock ()
114
+ if c .isClosed {
115
+ return nil , errClientIsClosed
116
+ }
117
+
97
118
ops := []clientv3.OpOption {}
98
119
if end != "" {
99
120
ops = append (ops , clientv3 .WithRange (end ))
@@ -104,8 +125,6 @@ func (c *RecordingClient) Range(ctx context.Context, start, end string, revision
104
125
if limit != 0 {
105
126
ops = append (ops , clientv3 .WithLimit (limit ))
106
127
}
107
- c .kvMux .Lock ()
108
- defer c .kvMux .Unlock ()
109
128
callTime := time .Since (c .baseTime )
110
129
resp , err := c .client .Get (ctx , start , ops ... )
111
130
returnTime := time .Since (c .baseTime )
@@ -116,6 +135,10 @@ func (c *RecordingClient) Range(ctx context.Context, start, end string, revision
116
135
func (c * RecordingClient ) Put (ctx context.Context , key , value string , _ ... clientv3.OpOption ) (* clientv3.PutResponse , error ) {
117
136
c .kvMux .Lock ()
118
137
defer c .kvMux .Unlock ()
138
+ if c .isClosed {
139
+ return nil , errClientIsClosed
140
+ }
141
+
119
142
callTime := time .Since (c .baseTime )
120
143
resp , err := c .client .Put (ctx , key , value )
121
144
returnTime := time .Since (c .baseTime )
@@ -126,6 +149,10 @@ func (c *RecordingClient) Put(ctx context.Context, key, value string, _ ...clien
126
149
func (c * RecordingClient ) Delete (ctx context.Context , key string , _ ... clientv3.OpOption ) (* clientv3.DeleteResponse , error ) {
127
150
c .kvMux .Lock ()
128
151
defer c .kvMux .Unlock ()
152
+ if c .isClosed {
153
+ return nil , errClientIsClosed
154
+ }
155
+
129
156
callTime := time .Since (c .baseTime )
130
157
resp , err := c .client .Delete (ctx , key )
131
158
returnTime := time .Since (c .baseTime )
@@ -172,12 +199,22 @@ func (w *wrappedTxn) Commit() (*clientv3.TxnResponse, error) {
172
199
}
173
200
174
201
func (c * RecordingClient ) Txn (ctx context.Context ) clientv3.Txn {
202
+ c .kvMux .Lock ()
203
+ defer c .kvMux .Unlock ()
204
+ if c .isClosed {
205
+ return nil
206
+ }
207
+
175
208
return & wrappedTxn {txn : c .client .Txn (ctx ), c : c }
176
209
}
177
210
178
211
func (c * RecordingClient ) LeaseGrant (ctx context.Context , ttl int64 ) (* clientv3.LeaseGrantResponse , error ) {
179
212
c .kvMux .Lock ()
180
213
defer c .kvMux .Unlock ()
214
+ if c .isClosed {
215
+ return nil , errClientIsClosed
216
+ }
217
+
181
218
callTime := time .Since (c .baseTime )
182
219
resp , err := c .client .Lease .Grant (ctx , ttl )
183
220
returnTime := time .Since (c .baseTime )
@@ -188,6 +225,10 @@ func (c *RecordingClient) LeaseGrant(ctx context.Context, ttl int64) (*clientv3.
188
225
func (c * RecordingClient ) LeaseRevoke (ctx context.Context , leaseID int64 ) (* clientv3.LeaseRevokeResponse , error ) {
189
226
c .kvMux .Lock ()
190
227
defer c .kvMux .Unlock ()
228
+ if c .isClosed {
229
+ return nil , errClientIsClosed
230
+ }
231
+
191
232
callTime := time .Since (c .baseTime )
192
233
resp , err := c .client .Lease .Revoke (ctx , clientv3 .LeaseID (leaseID ))
193
234
returnTime := time .Since (c .baseTime )
@@ -196,9 +237,13 @@ func (c *RecordingClient) LeaseRevoke(ctx context.Context, leaseID int64) (*clie
196
237
}
197
238
198
239
func (c * RecordingClient ) PutWithLease (ctx context.Context , key string , value string , leaseID int64 ) (* clientv3.PutResponse , error ) {
199
- opts := clientv3 .WithLease (clientv3 .LeaseID (leaseID ))
200
240
c .kvMux .Lock ()
201
241
defer c .kvMux .Unlock ()
242
+ if c .isClosed {
243
+ return nil , errClientIsClosed
244
+ }
245
+
246
+ opts := clientv3 .WithLease (clientv3 .LeaseID (leaseID ))
202
247
callTime := time .Since (c .baseTime )
203
248
resp , err := c .client .Put (ctx , key , value , opts )
204
249
returnTime := time .Since (c .baseTime )
@@ -209,6 +254,10 @@ func (c *RecordingClient) PutWithLease(ctx context.Context, key string, value st
209
254
func (c * RecordingClient ) Defragment (ctx context.Context ) (* clientv3.DefragmentResponse , error ) {
210
255
c .kvMux .Lock ()
211
256
defer c .kvMux .Unlock ()
257
+ if c .isClosed {
258
+ return nil , errClientIsClosed
259
+ }
260
+
212
261
callTime := time .Since (c .baseTime )
213
262
resp , err := c .client .Defragment (ctx , c .client .Endpoints ()[0 ])
214
263
returnTime := time .Since (c .baseTime )
@@ -219,6 +268,10 @@ func (c *RecordingClient) Defragment(ctx context.Context) (*clientv3.DefragmentR
219
268
func (c * RecordingClient ) Compact (ctx context.Context , rev int64 , _ ... clientv3.CompactOption ) (* clientv3.CompactResponse , error ) {
220
269
c .kvMux .Lock ()
221
270
defer c .kvMux .Unlock ()
271
+ if c .isClosed {
272
+ return nil , errClientIsClosed
273
+ }
274
+
222
275
callTime := time .Since (c .baseTime )
223
276
resp , err := c .client .Compact (ctx , rev )
224
277
returnTime := time .Since (c .baseTime )
@@ -229,48 +282,76 @@ func (c *RecordingClient) Compact(ctx context.Context, rev int64, _ ...clientv3.
229
282
func (c * RecordingClient ) MemberList (ctx context.Context , opts ... clientv3.OpOption ) (* clientv3.MemberListResponse , error ) {
230
283
c .kvMux .Lock ()
231
284
defer c .kvMux .Unlock ()
285
+ if c .isClosed {
286
+ return nil , errClientIsClosed
287
+ }
288
+
232
289
resp , err := c .client .MemberList (ctx , opts ... )
233
290
return resp , err
234
291
}
235
292
236
293
func (c * RecordingClient ) MemberAdd (ctx context.Context , peerAddrs []string ) (* clientv3.MemberAddResponse , error ) {
237
294
c .kvMux .Lock ()
238
295
defer c .kvMux .Unlock ()
296
+ if c .isClosed {
297
+ return nil , errClientIsClosed
298
+ }
299
+
239
300
resp , err := c .client .MemberAdd (ctx , peerAddrs )
240
301
return resp , err
241
302
}
242
303
243
304
func (c * RecordingClient ) MemberAddAsLearner (ctx context.Context , peerAddrs []string ) (* clientv3.MemberAddResponse , error ) {
244
305
c .kvMux .Lock ()
245
306
defer c .kvMux .Unlock ()
307
+ if c .isClosed {
308
+ return nil , errClientIsClosed
309
+ }
310
+
246
311
resp , err := c .client .MemberAddAsLearner (ctx , peerAddrs )
247
312
return resp , err
248
313
}
249
314
250
315
func (c * RecordingClient ) MemberRemove (ctx context.Context , id uint64 ) (* clientv3.MemberRemoveResponse , error ) {
251
316
c .kvMux .Lock ()
252
317
defer c .kvMux .Unlock ()
318
+ if c .isClosed {
319
+ return nil , errClientIsClosed
320
+ }
321
+
253
322
resp , err := c .client .MemberRemove (ctx , id )
254
323
return resp , err
255
324
}
256
325
257
326
func (c * RecordingClient ) MemberUpdate (ctx context.Context , id uint64 , peerAddrs []string ) (* clientv3.MemberUpdateResponse , error ) {
258
327
c .kvMux .Lock ()
259
328
defer c .kvMux .Unlock ()
329
+ if c .isClosed {
330
+ return nil , errClientIsClosed
331
+ }
332
+
260
333
resp , err := c .client .MemberUpdate (ctx , id , peerAddrs )
261
334
return resp , err
262
335
}
263
336
264
337
func (c * RecordingClient ) MemberPromote (ctx context.Context , id uint64 ) (* clientv3.MemberPromoteResponse , error ) {
265
338
c .kvMux .Lock ()
266
339
defer c .kvMux .Unlock ()
340
+ if c .isClosed {
341
+ return nil , errClientIsClosed
342
+ }
343
+
267
344
resp , err := c .client .MemberPromote (ctx , id )
268
345
return resp , err
269
346
}
270
347
271
348
func (c * RecordingClient ) Status (ctx context.Context , endpoint string ) (* clientv3.StatusResponse , error ) {
272
349
c .kvMux .Lock ()
273
350
defer c .kvMux .Unlock ()
351
+ if c .isClosed {
352
+ return nil , errClientIsClosed
353
+ }
354
+
274
355
resp , err := c .client .Status (ctx , endpoint )
275
356
return resp , err
276
357
}
@@ -280,6 +361,12 @@ func (c *RecordingClient) Endpoints() []string {
280
361
}
281
362
282
363
func (c * RecordingClient ) Watch (ctx context.Context , key string , rev int64 , withPrefix bool , withProgressNotify bool , withPrevKV bool ) clientv3.WatchChan {
364
+ c .kvMux .Lock ()
365
+ defer c .kvMux .Unlock ()
366
+ if c .isClosed {
367
+ return nil
368
+ }
369
+
283
370
request := model.WatchRequest {
284
371
Key : key ,
285
372
Revision : rev ,
@@ -333,6 +420,12 @@ func (c *RecordingClient) watch(ctx context.Context, request model.WatchRequest)
333
420
}
334
421
335
422
func (c * RecordingClient ) RequestProgress (ctx context.Context ) error {
423
+ c .kvMux .Lock ()
424
+ defer c .kvMux .Unlock ()
425
+ if c .isClosed {
426
+ return errClientIsClosed
427
+ }
428
+
336
429
return c .client .RequestProgress (ctx )
337
430
}
338
431
@@ -434,7 +527,7 @@ func (cs *ClientSet) close() {
434
527
return
435
528
}
436
529
for _ , c := range cs .clients {
437
- c .Close ()
530
+ _ = c .Close ()
438
531
}
439
532
cs .closed = true
440
533
}
0 commit comments