File: token_bucket.go

package info (click to toggle)
golang-github-aws-aws-sdk-go-v2 1.30.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 662,428 kB
  • sloc: java: 16,875; makefile: 432; sh: 175
file content (96 lines) | stat: -rw-r--r-- 2,387 bytes parent folder | download | duplicates (7)
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
package ratelimit

import (
	"sync"
)

// TokenBucket provides a concurrency safe utility for adding and removing
// tokens from the available token bucket.
type TokenBucket struct {
	remainingTokens uint
	maxCapacity     uint
	minCapacity     uint
	mu              sync.Mutex
}

// NewTokenBucket returns an initialized TokenBucket with the capacity
// specified.
func NewTokenBucket(i uint) *TokenBucket {
	return &TokenBucket{
		remainingTokens: i,
		maxCapacity:     i,
		minCapacity:     1,
	}
}

// Retrieve attempts to reduce the available tokens by the amount requested. If
// there are tokens available true will be returned along with the number of
// available tokens remaining. If amount requested is larger than the available
// capacity, false will be returned along with the available capacity. If the
// amount is less than the available capacity, the capacity will be reduced by
// that amount, and the remaining capacity and true will be returned.
func (t *TokenBucket) Retrieve(amount uint) (available uint, retrieved bool) {
	t.mu.Lock()
	defer t.mu.Unlock()

	if amount > t.remainingTokens {
		return t.remainingTokens, false
	}

	t.remainingTokens -= amount
	return t.remainingTokens, true
}

// Refund returns the amount of tokens back to the available token bucket, up
// to the initial capacity.
func (t *TokenBucket) Refund(amount uint) {
	t.mu.Lock()
	defer t.mu.Unlock()

	// Capacity cannot exceed max capacity.
	t.remainingTokens = uintMin(t.remainingTokens+amount, t.maxCapacity)
}

// Capacity returns the maximum capacity of tokens that the bucket could
// contain.
func (t *TokenBucket) Capacity() uint {
	t.mu.Lock()
	defer t.mu.Unlock()

	return t.maxCapacity
}

// Remaining returns the number of tokens that remaining in the bucket.
func (t *TokenBucket) Remaining() uint {
	t.mu.Lock()
	defer t.mu.Unlock()

	return t.remainingTokens
}

// Resize adjusts the size of the token bucket. Returns the capacity remaining.
func (t *TokenBucket) Resize(size uint) uint {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.maxCapacity = uintMax(size, t.minCapacity)

	// Capacity needs to be capped at max capacity, if max size reduced.
	t.remainingTokens = uintMin(t.remainingTokens, t.maxCapacity)

	return t.remainingTokens
}

func uintMin(a, b uint) uint {
	if a < b {
		return a
	}
	return b
}

func uintMax(a, b uint) uint {
	if a > b {
		return a
	}
	return b
}