Skip to content

Commit 7fac93b

Browse files
liyishuaiclaude
andcommitted
lease: reject KeepAlive during lease revocation
When a lease expires, the leader revokes it by deleting attached keys and then removing the lease from leaseMap. A concurrent KeepAlive (Renew) request can race in between these two steps: it finds the lease still in leaseMap and successfully renews it, returning a positive TTL to the client while the keys are already gone. Fix this by closing lease.revokec at the start of Revoke() before releasing the lock to delete keys, and checking lease.revokec in Renew() after acquiring the lock. If revokec is closed, Renew() returns ErrLeaseNotFound, ensuring the client is not misled into thinking the lease (and its keys) are still alive. Signed-off-by: Yishuai Li <yishuai.li@pingcap.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8df0f35 commit 7fac93b

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

server/lease/lessor.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ func (le *lessor) Revoke(id LeaseID) error {
332332
return ErrLeaseNotFound
333333
}
334334

335-
defer close(l.revokec)
335+
close(l.revokec)
336336
// unlock before doing external work
337337
le.mu.Unlock()
338338

@@ -448,6 +448,14 @@ func (le *lessor) Renew(id LeaseID) (int64, error) {
448448
le.mu.Unlock()
449449
return -1, ErrLeaseNotFound
450450
}
451+
452+
select {
453+
case <-l.revokec:
454+
le.mu.Unlock()
455+
return -1, ErrLeaseNotFound
456+
default:
457+
}
458+
451459
l.refresh(0)
452460
item := &LeaseWithTime{id: l.ID, time: l.expiry}
453461
le.leaseExpiredNotifier.RegisterOrUpdate(item)

0 commit comments

Comments
 (0)