forked from youtube/doorman
-
Notifications
You must be signed in to change notification settings - Fork 0
/
store.go
213 lines (169 loc) · 5.49 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// Copyright 2016 Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package doorman
import "time"
// Lease represents a lease on capacity for some resource for some client.
type Lease struct {
// Expiry is the time at which this lease expires.
Expiry time.Time
// RefreshInterval is the interval at which the client should
// poll for updates for this resource.
RefreshInterval time.Duration
// Has is how much capacity was given to this client.
Has float64
// Wants is how much capacity was requested.
Wants float64
// Subclients is the number of subclients of this client.
Subclients int64
}
// ClientLeaseStatus contains information about a lease that
// a client has.
type ClientLeaseStatus struct {
ClientID string
Lease Lease
}
// ResourceLeaseStatus is a read-only copy of information about all leases
// for a particular resource. It can be used for display purposes.
type ResourceLeaseStatus struct {
// Resource id.
ID string
// The sum of all outstanding obligations.
SumHas float64
// The sum of all client wants.
SumWants float64
// A slice containing information about outstanding leases
Leases []ClientLeaseStatus
}
// IsZero returns true if the lease is a zero instance.
func (lease Lease) IsZero() bool {
return lease.Expiry.IsZero()
}
// LeaseStore is the set of outstanding leases for some particular
// resource.
type LeaseStore interface {
// SumHas returns the total capacity given out to clients
// at the moment.
SumHas() float64
// SumWants returns the total capacity requested by clients.
SumWants() float64
// Get returns the lease currently granted to this client.
Get(client string) Lease
// HasClient returns whether this client currently has a lease.
HasClient(client string) bool
// Assign updates the lease store to represent capacity given
// to a client.
Assign(client string, leaseLength, refreshInterval time.Duration, has, wants float64, subclients int64) Lease
// Release releases any leases granted to a client.
Release(client string)
// Clean removes any out of date leases. Returns the number of leases cleaned
Clean() int
// Count returns the number of subclients leases in the store.
Count() int64
// Returns a read-only copy of summary information about outstanding leases.
ResourceLeaseStatus() ResourceLeaseStatus
// Map executes a function for every lease in the store.
Map(func(id string, lease Lease))
// Subclients returns the number of subclients of the client with the given id.
Subclients(id string) int64
}
type leaseStoreImpl struct {
id string
leases map[string]Lease
sumWants float64
sumHas float64
count int64
}
// New returns a fresh LeaseStore implementation.
func NewLeaseStore(id string) LeaseStore {
return &leaseStoreImpl{
id: id,
leases: make(map[string]Lease),
}
}
func (store *leaseStoreImpl) Count() int64 {
return store.count
}
func (store *leaseStoreImpl) SumWants() float64 {
return store.sumWants
}
func (store *leaseStoreImpl) SumHas() float64 {
return store.sumHas
}
func (store *leaseStoreImpl) HasClient(client string) bool {
_, ok := store.leases[client]
return ok
}
func (store *leaseStoreImpl) Get(client string) Lease {
return store.leases[client]
}
func (store *leaseStoreImpl) Release(client string) {
lease, ok := store.leases[client]
if !ok {
return
}
store.sumWants -= lease.Wants
store.sumHas -= lease.Has
store.count -= lease.Subclients
delete(store.leases, client)
}
func (store *leaseStoreImpl) Assign(client string, leaseLength, refreshInterval time.Duration, has, wants float64, subclients int64) Lease {
lease := store.leases[client]
store.sumHas += has - lease.Has
store.sumWants += wants - lease.Wants
store.count += subclients - lease.Subclients
lease.Has, lease.Wants = has, wants
lease.Expiry = time.Now().Add(leaseLength)
lease.RefreshInterval = refreshInterval
lease.Subclients = subclients
store.leases[client] = lease
return lease
}
func (store *leaseStoreImpl) Clean() int {
when := time.Now()
result := 0
for client, lease := range store.leases {
if when.After(lease.Expiry) {
store.Release(client)
result++
}
}
return result
}
// ResourceLeaseStatus returns a read-only copy with summary information about outstanding leases.
func (store *leaseStoreImpl) ResourceLeaseStatus() ResourceLeaseStatus {
status := ResourceLeaseStatus{
ID: store.id,
SumHas: store.sumHas,
SumWants: store.sumWants,
Leases: make([]ClientLeaseStatus, 0, len(store.leases)),
}
for client, lease := range store.leases {
status.Leases = append(status.Leases, ClientLeaseStatus{
ClientID: client,
Lease: lease,
})
}
return status
}
// Map executes a function for every lease in the store.
func (store *leaseStoreImpl) Map(fun func(string, Lease)) {
for id, lease := range store.leases {
fun(id, lease)
}
}
// Subclients returns the number of subclients of the client with the given id.
// Every client has at least one subclient.
func (store *leaseStoreImpl) Subclients(id string) int64 {
return store.leases[id].Subclients
}