aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/unified_agent_client/throttling.cpp
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;
    }
}