@@ -19,6 +19,101 @@ 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.
84+ func (b * TimeoutBooster ) Reset (newTimeout time.Duration ) {
85+ b .mu .Lock ()
86+ defer b .mu .Unlock ()
87+
88+ b .boostCount = 0
89+ b .originalTimeout = newTimeout
90+ }
91+
92+ // RestartFrequencyTimeout restart the frequency limit timeout, which ensures
93+ // that boosting won't be possible until the duration of the original timeout
94+ // has passed.
95+ func (b * TimeoutBooster ) RestartFrequencyTimeout () {
96+ b .mu .Lock ()
97+ defer b .mu .Unlock ()
98+
99+ if b .withBoostFrequencyLimit {
100+ b .lastBoost = time .Now ()
101+ }
102+ }
103+
104+ // GetCurrentTimeout returns the value of the timeout, with the boost applied.
105+ func (b * TimeoutBooster ) GetCurrentTimeout () time.Duration {
106+ b .mu .Lock ()
107+ defer b .mu .Unlock ()
108+
109+ increase := time .Duration (
110+ float32 (b .originalTimeout ) * b .boostPercent *
111+ float32 (b .boostCount ),
112+ )
113+
114+ return b .originalTimeout + increase
115+ }
116+
22117// TimeoutManager manages the different timeouts used by the gbn package.
23118type TimeoutManager struct {
24119 // useStaticTimeout is used to indicate whether the resendTimeout
0 commit comments