@@ -19,6 +19,97 @@ const (
19
19
DefaultRecvTimeout = math .MaxInt64
20
20
)
21
21
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
+
22
113
// TimeoutManager manages the different timeouts used by the gbn package.
23
114
type TimeoutManager struct {
24
115
// useStaticTimeout is used to indicate whether the resendTimeout
0 commit comments