blob: 8f194c98030c6f8903bef70b2b64c7bfa0ccd85c [file] [log] [blame]
Abhay Kumara2ae5992025-11-10 14:02:24 +00001// Copyright 2022 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package lease
16
17import (
18 "math"
19 "sync"
20 "time"
21
22 "go.etcd.io/etcd/server/v3/lease/leasepb"
23 "go.etcd.io/etcd/server/v3/storage/backend"
24 "go.etcd.io/etcd/server/v3/storage/schema"
25)
26
27type Lease struct {
28 ID LeaseID
29 ttl int64 // time to live of the lease in seconds
30 remainingTTL int64 // remaining time to live in seconds, if zero valued it is considered unset and the full ttl should be used
31 // expiryMu protects concurrent accesses to expiry
32 expiryMu sync.RWMutex
33 // expiry is time when lease should expire. no expiration when expiry.IsZero() is true
34 expiry time.Time
35
36 // mu protects concurrent accesses to itemSet
37 mu sync.RWMutex
38 itemSet map[LeaseItem]struct{}
39 revokec chan struct{}
40}
41
42func NewLease(id LeaseID, ttl int64) *Lease {
43 return &Lease{
44 ID: id,
45 ttl: ttl,
46 itemSet: make(map[LeaseItem]struct{}),
47 revokec: make(chan struct{}),
48 }
49}
50
51func (l *Lease) expired() bool {
52 return l.Remaining() <= 0
53}
54
55func (l *Lease) persistTo(b backend.Backend) {
56 lpb := leasepb.Lease{ID: int64(l.ID), TTL: l.ttl, RemainingTTL: l.remainingTTL}
57 tx := b.BatchTx()
58 tx.LockInsideApply()
59 defer tx.Unlock()
60 schema.MustUnsafePutLease(tx, &lpb)
61}
62
63// TTL returns the TTL of the Lease.
64func (l *Lease) TTL() int64 {
65 return l.ttl
66}
67
68// SetLeaseItem sets the given lease item, this func is thread-safe
69func (l *Lease) SetLeaseItem(item LeaseItem) {
70 l.mu.Lock()
71 defer l.mu.Unlock()
72 l.itemSet[item] = struct{}{}
73}
74
75// getRemainingTTL returns the last checkpointed remaining TTL of the lease.
76func (l *Lease) getRemainingTTL() int64 {
77 if l.remainingTTL > 0 {
78 return l.remainingTTL
79 }
80 return l.ttl
81}
82
83// refresh refreshes the expiry of the lease.
84func (l *Lease) refresh(extend time.Duration) {
85 newExpiry := time.Now().Add(extend + time.Duration(l.getRemainingTTL())*time.Second)
86 l.expiryMu.Lock()
87 defer l.expiryMu.Unlock()
88 l.expiry = newExpiry
89}
90
91// forever sets the expiry of lease to be forever.
92func (l *Lease) forever() {
93 l.expiryMu.Lock()
94 defer l.expiryMu.Unlock()
95 l.expiry = forever
96}
97
98// Demoted returns true if the lease's expiry has been reset to forever.
99func (l *Lease) Demoted() bool {
100 l.expiryMu.RLock()
101 defer l.expiryMu.RUnlock()
102 return l.expiry == forever
103}
104
105// Keys returns all the keys attached to the lease.
106func (l *Lease) Keys() []string {
107 l.mu.RLock()
108 keys := make([]string, 0, len(l.itemSet))
109 for k := range l.itemSet {
110 keys = append(keys, k.Key)
111 }
112 l.mu.RUnlock()
113 return keys
114}
115
116// Remaining returns the remaining time of the lease.
117func (l *Lease) Remaining() time.Duration {
118 l.expiryMu.RLock()
119 defer l.expiryMu.RUnlock()
120 if l.expiry.IsZero() {
121 return time.Duration(math.MaxInt64)
122 }
123 return time.Until(l.expiry)
124}
125
126type LeaseItem struct {
127 Key string
128}
129
130// leasesByExpiry implements the sort.Interface.
131type leasesByExpiry []*Lease
132
133func (le leasesByExpiry) Len() int { return len(le) }
134func (le leasesByExpiry) Less(i, j int) bool { return le[i].Remaining() < le[j].Remaining() }
135func (le leasesByExpiry) Swap(i, j int) { le[i], le[j] = le[j], le[i] }