Skip to content

Commit d92c615

Browse files
gbn: Add TimeoutBooster
TimeoutBooster is a type can be used to boost the value of a timeout by a specified percentage. The timeout can be boosted multiple times, and number of boosts are then cumulative.
1 parent d924596 commit d92c615

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

gbn/timeout_manager.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,97 @@ const (
1919
DefaultRecvTimeout = math.MaxInt64
2020
)
2121

22+
// TimeoutBooster is used to boost a timeout by a given percentage value.
23+
// The timeout will be boosted by the percentage value of the boostPercent any
24+
// time the Boost function is called, and is cumulative.
25+
type TimeoutBooster struct {
26+
// boostPercent defines the percentage value the original timeout will
27+
// be boosted any time the Boost function is called.
28+
boostPercent float32
29+
30+
// boostCount defines the number of times the timeout has been boosted.
31+
boostCount int
32+
33+
// originalTimeout defines the base timeout value that is boosted.
34+
originalTimeout time.Duration
35+
36+
// withBoostFrequencyLimit is used to indicate whether there is a cap to
37+
// how often the timeout can be boosted, which is the duration of the
38+
// original timeout.
39+
withBoostFrequencyLimit bool
40+
41+
// lastBoost defines the time when the last boost that had any affect
42+
// was applied.
43+
lastBoost time.Time
44+
45+
mu sync.Mutex
46+
}
47+
48+
// NewTimeoutBooster creates a new timeout booster. The originalTimeout defines
49+
// the base timeout value that is boosted. The timeout will be boosted by the
50+
// percentage value of the boostPercent any time the Boost function is called.
51+
// Finally if the withBoostFrequencyLimit is set, then there is a cap to how
52+
// often the timeout can be boosted, which is the duration of the original
53+
// timeout.
54+
func NewTimeoutBooster(originalTimeout time.Duration, boostPercent float32,
55+
withBoostFrequencyLimit bool) *TimeoutBooster {
56+
57+
return &TimeoutBooster{
58+
boostPercent: boostPercent,
59+
originalTimeout: originalTimeout,
60+
boostCount: 0,
61+
withBoostFrequencyLimit: withBoostFrequencyLimit,
62+
}
63+
}
64+
65+
// Boost boosts the timeout by the boost percent. If the withBoostFrequencyLimit
66+
// is set, then the boost will only be applied if the duration of the original
67+
// timeout has passed since the last boost that had any affect was applied.
68+
func (b *TimeoutBooster) Boost() {
69+
b.mu.Lock()
70+
defer b.mu.Unlock()
71+
72+
if b.withBoostFrequencyLimit {
73+
if time.Since(b.lastBoost) < b.originalTimeout {
74+
return
75+
}
76+
}
77+
78+
b.lastBoost = time.Now()
79+
b.boostCount++
80+
}
81+
82+
// Reset removes the current applied boost, and sets the original timeout to the
83+
// passed timeout. It also restarts the frequency limit timeout if the
84+
// withBoostFrequencyLimit was set to true when initializing the TimeoutBooster.
85+
func (b *TimeoutBooster) Reset(newTimeout time.Duration) {
86+
b.mu.Lock()
87+
defer b.mu.Unlock()
88+
89+
b.boostCount = 0
90+
b.originalTimeout = newTimeout
91+
92+
// We'll also restart the frequency timeout, to ensure that any message
93+
// we immediately resend after resetting the booster won't boost the
94+
// timeout.
95+
if b.withBoostFrequencyLimit {
96+
b.lastBoost = time.Now()
97+
}
98+
}
99+
100+
// GetCurrentTimeout returns the value of the timeout, with the boost applied.
101+
func (b *TimeoutBooster) GetCurrentTimeout() time.Duration {
102+
b.mu.Lock()
103+
defer b.mu.Unlock()
104+
105+
increase := time.Duration(
106+
float32(b.originalTimeout) * b.boostPercent *
107+
float32(b.boostCount),
108+
)
109+
110+
return b.originalTimeout + increase
111+
}
112+
22113
// TimeoutManager manages the different timeouts used by the gbn package.
23114
type TimeoutManager struct {
24115
// useStaticTimeout is used to indicate whether the resendTimeout

0 commit comments

Comments
 (0)