@@ -3,6 +3,7 @@ package meta
3
3
import (
4
4
"context"
5
5
"crypto/tls"
6
+ "errors"
6
7
"fmt"
7
8
"strconv"
8
9
"sync"
@@ -239,6 +240,34 @@ func (e *ETCD) BatchUpdate(ctx context.Context, data map[string]string, opts ...
239
240
return e .batchUpdate (ctx , data , opts ... )
240
241
}
241
242
243
+ // isTTLChanged returns true iff there is a lease with the same ttl bound to the key
244
+ func (e * ETCD ) isTTLChanged (ctx context.Context , key string , ttl int64 ) (bool , error ) {
245
+ resp , err := e .GetOne (ctx , key )
246
+ if err != nil {
247
+ if errors .Is (err , types .ErrBadCount ) {
248
+ return false , nil
249
+ }
250
+ return false , err
251
+ }
252
+
253
+ leaseID := clientv3 .LeaseID (resp .Lease )
254
+ if leaseID == 0 {
255
+ return true , nil
256
+ }
257
+
258
+ getTTLResp , err := e .cliv3 .TimeToLive (ctx , leaseID )
259
+ if err != nil {
260
+ return false , err
261
+ }
262
+
263
+ changed := getTTLResp .GrantedTTL != ttl
264
+ if changed {
265
+ log .Infof (ctx , "[isTTLChanged] key %v ttl changed from %v to %v" , key , getTTLResp .GrantedTTL , ttl )
266
+ }
267
+
268
+ return changed , nil
269
+ }
270
+
242
271
// BindStatus keeps on a lease alive.
243
272
func (e * ETCD ) BindStatus (ctx context.Context , entityKey , statusKey , statusValue string , ttl int64 ) error {
244
273
if ttl == 0 {
@@ -256,19 +285,38 @@ func (e *ETCD) bindStatusWithTTL(ctx context.Context, entityKey, statusKey, stat
256
285
leaseID := lease .ID
257
286
updateStatus := []clientv3.Op {clientv3 .OpPut (statusKey , statusValue , clientv3 .WithLease (lease .ID ))}
258
287
259
- entityTxn , err := e .cliv3 .Txn (ctx ).
260
- If (clientv3 .Compare (clientv3 .Version (entityKey ), "!=" , 0 )).
261
- Then ( // making sure there's an exists entity kv-pair.
262
- clientv3 .OpTxn (
263
- []clientv3.Cmp {clientv3 .Compare (clientv3 .Version (statusKey ), "!=" , 0 )}, // Is the status exists?
264
- []clientv3.Op {clientv3 .OpTxn ( // there's an exists status
265
- []clientv3.Cmp {clientv3 .Compare (clientv3 .Value (statusKey ), "=" , statusValue )},
266
- []clientv3.Op {clientv3 .OpGet (statusKey )}, // The status hasn't been changed.
267
- updateStatus , // The status had been changed.
268
- )},
269
- updateStatus , // there isn't a status
270
- ),
271
- ).Commit ()
288
+ ttlChanged , err := e .isTTLChanged (ctx , statusKey , ttl )
289
+ if err != nil {
290
+ return err
291
+ }
292
+
293
+ var entityTxn * clientv3.TxnResponse
294
+
295
+ if ttlChanged {
296
+ entityTxn , err = e .cliv3 .Txn (ctx ).
297
+ If (clientv3 .Compare (clientv3 .Version (entityKey ), "!=" , 0 )).
298
+ Then (updateStatus ... ). // making sure there's an exists entity kv-pair.
299
+ Commit ()
300
+ } else {
301
+ entityTxn , err = e .cliv3 .Txn (ctx ).
302
+ If (clientv3 .Compare (clientv3 .Version (entityKey ), "!=" , 0 )).
303
+ Then ( // making sure there's an exists entity kv-pair.
304
+ clientv3 .OpTxn (
305
+ []clientv3.Cmp {clientv3 .Compare (clientv3 .Version (statusKey ), "!=" , 0 )}, // Is the status exists?
306
+ []clientv3.Op {clientv3 .OpTxn ( // there's an exists status
307
+ []clientv3.Cmp {clientv3 .Compare (clientv3 .LeaseValue (statusKey ), "!=" , 0 )}, //
308
+ []clientv3.Op {clientv3 .OpTxn ( // there has been a lease bound to the status
309
+ []clientv3.Cmp {clientv3 .Compare (clientv3 .Value (statusKey ), "=" , statusValue )}, // Is the status changed?
310
+ []clientv3.Op {clientv3 .OpGet (statusKey )}, // The status hasn't been changed.
311
+ updateStatus , // The status had been changed.
312
+ )},
313
+ updateStatus , // there is no lease bound to the status
314
+ )},
315
+ updateStatus , // there isn't a status
316
+ ),
317
+ ).Commit ()
318
+ }
319
+
272
320
if err != nil {
273
321
e .revokeLease (ctx , leaseID )
274
322
return err
@@ -280,14 +328,28 @@ func (e *ETCD) bindStatusWithTTL(ctx context.Context, entityKey, statusKey, stat
280
328
return types .ErrEntityNotExists
281
329
}
282
330
331
+ // if ttl is changed, replace with the new lease
332
+ if ttlChanged {
333
+ log .Infof (ctx , "[bindStatusWithTTL] put: key %s value %s" , statusKey , statusValue )
334
+ return nil
335
+ }
336
+
283
337
// There isn't a status bound to the entity.
284
338
statusTxn := entityTxn .Responses [0 ].GetResponseTxn ()
285
339
if ! statusTxn .Succeeded {
340
+ log .Infof (ctx , "[bindStatusWithTTL] put: key %s value %s" , statusKey , statusValue )
341
+ return nil
342
+ }
343
+
344
+ // There is no lease bound to the status yet
345
+ leaseTxn := statusTxn .Responses [0 ].GetResponseTxn ()
346
+ if ! leaseTxn .Succeeded {
347
+ log .Infof (ctx , "[bindStatusWithTTL] put: key %s value %s" , statusKey , statusValue )
286
348
return nil
287
349
}
288
350
289
351
// There is a status bound to the entity yet but its value isn't same as the expected one.
290
- valueTxn := statusTxn .Responses [0 ].GetResponseTxn ()
352
+ valueTxn := leaseTxn .Responses [0 ].GetResponseTxn ()
291
353
if ! valueTxn .Succeeded {
292
354
log .Infof (ctx , "[bindStatusWithTTL] put: key %s value %s" , statusKey , statusValue )
293
355
return nil
@@ -310,7 +372,22 @@ func (e *ETCD) bindStatusWithTTL(ctx context.Context, entityKey, statusKey, stat
310
372
// agent may report status earlier when core has not recorded the entity.
311
373
func (e * ETCD ) bindStatusWithoutTTL (ctx context.Context , statusKey , statusValue string ) error {
312
374
updateStatus := []clientv3.Op {clientv3 .OpPut (statusKey , statusValue )}
313
- _ , err := e .cliv3 .Txn (ctx ).
375
+
376
+ ttlChanged , err := e .isTTLChanged (ctx , statusKey , 0 )
377
+ if err != nil {
378
+ return err
379
+ }
380
+ if ttlChanged {
381
+ _ , err := e .Put (ctx , statusKey , statusValue )
382
+ if err != nil {
383
+ return err
384
+ }
385
+
386
+ log .Infof (ctx , "[bindStatusWithoutTTL] put: key %s value %s" , statusKey , statusValue )
387
+ return nil
388
+ }
389
+
390
+ resp , err := e .cliv3 .Txn (ctx ).
314
391
If (clientv3 .Compare (clientv3 .Version (statusKey ), "!=" , 0 )). // if there's an existing status key
315
392
Then (clientv3 .OpTxn ( // deal with existing status key
316
393
[]clientv3.Cmp {clientv3 .Compare (clientv3 .Value (statusKey ), "!=" , statusValue )}, // if the new value != the old value
@@ -319,10 +396,13 @@ func (e *ETCD) bindStatusWithoutTTL(ctx context.Context, statusKey, statusValue
319
396
)).
320
397
Else (updateStatus ... ). // otherwise deal with non-existing status key
321
398
Commit ()
322
- if err == nil {
399
+ if err != nil {
400
+ return err
401
+ }
402
+ if ! resp .Succeeded || resp .Responses [0 ].GetResponseTxn ().Succeeded {
323
403
log .Infof (ctx , "[bindStatusWithoutTTL] put: key %s value %s" , statusKey , statusValue )
324
404
}
325
- return err
405
+ return nil
326
406
}
327
407
328
408
func (e * ETCD ) revokeLease (ctx context.Context , leaseID clientv3.LeaseID ) {
0 commit comments