summaryrefslogtreecommitdiff
path: root/vendor/jonahgeorge/jaeger-client-php/src/Jaeger/Util/RateLimiter.php
blob: d767ad40ff1b037c3a76caa189f5cf4160a85bb5 (plain)
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php

namespace Jaeger\Util;

use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;

class RateLimiter
{
    /**
     * @var CacheItemPoolInterface
     */
    private $cache;

    /**
     * @var CacheItemInterface
     */
    private $balance;

    /**
     * @var CacheItemInterface
     */
    private $lastTick;

    /**
     * @var float
     */
    private $creditsPerNanosecond = 0;

    /**
     * @var float
     */
    private $maxBalance = 0;

    /**
     * RateLimiter constructor.
     *
     * @param CacheItemPoolInterface $cache
     * @param string $currentBalanceKey key of current balance value in $cache
     * @param string $lastTickKey key of last tick value in $cache
     * @throws \Psr\Cache\InvalidArgumentException
     */
    public function __construct(
        CacheItemPoolInterface $cache,
        string $currentBalanceKey,
        string $lastTickKey
    ) {
        $this->cache = $cache;
        $this->balance = $this->cache->getItem($currentBalanceKey);
        $this->lastTick = $this->cache->getItem($lastTickKey);
    }

    /**
     * @param $itemCost
     * @return bool
     */
    public function checkCredit($itemCost)
    {
        if (!$this->creditsPerNanosecond) {
            return false;
        }

        list($lastTick, $balance) = $this->getState();

        if (!$lastTick) {
            $this->saveState(hrtime(true), 0);
            return true;
        }

        $currentTick = hrtime(true);
        $elapsedTime = $currentTick - $lastTick;
        $balance += $elapsedTime * $this->creditsPerNanosecond;
        if ($balance > $this->maxBalance) {
            $balance = $this->maxBalance;
        }

        $result = false;
        if ($balance >= $itemCost) {
            $balance -= $itemCost;
            $result = true;
        }

        $this->saveState($currentTick, $balance);

        return $result;
    }


    /**
     * Initializes limiter costs and boundaries
     *
     * @param float $creditsPerNanosecond
     * @param float $maxBalance
     */
    public function initialize(float $creditsPerNanosecond, float $maxBalance)
    {
        $this->creditsPerNanosecond = $creditsPerNanosecond;
        $this->maxBalance = $maxBalance;
    }

    /**
     * Method loads last tick and current balance from cache
     *
     * @return array [$lastTick, $balance]
     */
    private function getState() : array
    {
        return [
            $this->lastTick->get(),
            $this->balance->get()
        ];
    }

    /**
     * Method saves last tick and current balance into cache
     *
     * @param integer $lastTick
     * @param float $balance
     */
    private function saveState($lastTick, $balance)
    {
        $this->lastTick->set($lastTick);
        $this->balance->set($balance);
        $this->cache->saveDeferred($this->lastTick);
        $this->cache->saveDeferred($this->balance);
        $this->cache->commit();
    }
}