Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/drivers/local/token_bucket.go
1986 views
1
package local
2
3
import "context"
4
5
type TokenBucket interface {
6
Take() <-chan struct{}
7
Put()
8
Do(context.Context, func() error) error
9
}
10
11
// StaticTokenBucket is a bucket with a fixed number of tokens,
12
// where the retrieval and return of tokens are manually controlled.
13
// In the initial state, the bucket is full.
14
type StaticTokenBucket struct {
15
bucket chan struct{}
16
}
17
18
func NewStaticTokenBucket(size int) StaticTokenBucket {
19
bucket := make(chan struct{}, size)
20
for range size {
21
bucket <- struct{}{}
22
}
23
return StaticTokenBucket{bucket: bucket}
24
}
25
26
func NewStaticTokenBucketWithMigration(oldBucket TokenBucket, size int) StaticTokenBucket {
27
if oldBucket != nil {
28
oldStaticBucket, ok := oldBucket.(StaticTokenBucket)
29
if ok {
30
oldSize := cap(oldStaticBucket.bucket)
31
migrateSize := oldSize
32
if size < migrateSize {
33
migrateSize = size
34
}
35
36
bucket := make(chan struct{}, size)
37
for range size - migrateSize {
38
bucket <- struct{}{}
39
}
40
41
if migrateSize != 0 {
42
go func() {
43
for range migrateSize {
44
<-oldStaticBucket.bucket
45
bucket <- struct{}{}
46
}
47
close(oldStaticBucket.bucket)
48
}()
49
}
50
return StaticTokenBucket{bucket: bucket}
51
}
52
}
53
return NewStaticTokenBucket(size)
54
}
55
56
// Take channel maybe closed when local driver is modified.
57
// don't call Put method after the channel is closed.
58
func (b StaticTokenBucket) Take() <-chan struct{} {
59
return b.bucket
60
}
61
62
func (b StaticTokenBucket) Put() {
63
b.bucket <- struct{}{}
64
}
65
66
func (b StaticTokenBucket) Do(ctx context.Context, f func() error) error {
67
select {
68
case <-ctx.Done():
69
return ctx.Err()
70
case _, ok := <-b.Take():
71
if ok {
72
defer b.Put()
73
}
74
}
75
return f()
76
}
77
78
// NopTokenBucket all function calls to this bucket will success immediately
79
type NopTokenBucket struct {
80
nop chan struct{}
81
}
82
83
func NewNopTokenBucket() NopTokenBucket {
84
nop := make(chan struct{})
85
close(nop)
86
return NopTokenBucket{nop}
87
}
88
89
func (b NopTokenBucket) Take() <-chan struct{} {
90
return b.nop
91
}
92
93
func (b NopTokenBucket) Put() {}
94
95
func (b NopTokenBucket) Do(_ context.Context, f func() error) error { return f() }
96
97