blob: 271f7b0e7e4e2d7afdd9a45784fd1717c5e2aa4b (
plain) (
blame)
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
|
#include "throttling.h"
#include <util/datetime/cputimer.h>
namespace NUnifiedAgent {
TThrottler::TThrottler(double rate, TDuration updatePeriod)
: CyclesPerMillisecond(GetCyclesPerMillisecond())
, UpdatePeriod(updatePeriod.MilliSeconds() * CyclesPerMillisecond)
, PeriodTokens(updatePeriod.SecondsFloat() * rate)
, AvailableTokens(0)
, ExpirationTime(0)
{
}
TThrottler::TThrottler(double rate, double burst)
: TThrottler(rate, TDuration::Seconds(burst / rate))
{
}
void TThrottler::Consume(double& tokens, TFMaybe<TDuration>& nextCheckDelay) {
const auto updateTime = UpdateTokens();
if (tokens <= AvailableTokens) {
AvailableTokens -= tokens;
tokens = 0.0;
nextCheckDelay = Nothing();
} else {
tokens -= AvailableTokens;
AvailableTokens = 0.0;
nextCheckDelay = TDuration::MicroSeconds((ExpirationTime - updateTime) * 1000 / CyclesPerMillisecond + 1);
}
}
bool TThrottler::TryConsume(double tokens) {
UpdateTokens();
if (tokens > AvailableTokens) {
return false;
}
AvailableTokens -= tokens;
return true;
}
void TThrottler::ConsumeAndWait(double tokens) {
TFMaybe<TDuration> nextCheckDelay;
while (true) {
Consume(tokens, nextCheckDelay);
if (!nextCheckDelay.Defined()) {
return;
}
Sleep(*nextCheckDelay);
}
}
ui64 TThrottler::UpdateTokens() {
const auto updateTime = GetCycleCount();
if (updateTime >= ExpirationTime) {
if (ExpirationTime == 0) {
ExpirationTime = updateTime + UpdatePeriod;
} else {
ExpirationTime += ((updateTime - ExpirationTime) / UpdatePeriod + 1) * UpdatePeriod;
}
AvailableTokens = PeriodTokens;
}
return updateTime;
}
}
|