PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / trunk
Transferito: WP Migration vtrunk
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / vendor / aws / aws-sdk-php / src / Retry / RateLimiter.php
transferito / vendor / aws / aws-sdk-php / src / Retry Last commit date
Exception 11 months ago Configuration.php 11 months ago ConfigurationInterface.php 11 months ago ConfigurationProvider.php 11 months ago QuotaManager.php 11 months ago RateLimiter.php 11 months ago RetryHelperTrait.php 11 months ago
RateLimiter.php
183 lines
1 <?php
2 namespace Aws\Retry;
3
4
5 /**
6 * @internal
7 */
8 class RateLimiter
9 {
10 // User-configurable constants
11 private $beta;
12 private $minCapacity;
13 private $minFillRate;
14 private $scaleConstant;
15 private $smooth;
16
17 // Optional callable time provider
18 private $timeProvider;
19
20 // Pre-set state variables
21 private $currentCapacity = 0;
22 private $enabled = false;
23 private $lastMaxRate = 0;
24 private $measuredTxRate = 0;
25 private $requestCount = 0;
26
27 // Other state variables
28 private $fillRate;
29 private $lastThrottleTime;
30 private $lastTimestamp;
31 private $lastTxRateBucket;
32 private $maxCapacity;
33 private $timeWindow;
34
35 public function __construct($options = [])
36 {
37 $this->beta = isset($options['beta'])
38 ? $options['beta']
39 : 0.7;
40 $this->minCapacity = isset($options['min_capacity'])
41 ? $options['min_capacity']
42 : 1;
43 $this->minFillRate = isset($options['min_fill_rate'])
44 ? $options['min_fill_rate']
45 : 0.5;
46 $this->scaleConstant = isset($options['scale_constant'])
47 ? $options['scale_constant']
48 : 0.4;
49 $this->smooth = isset($options['smooth'])
50 ? $options['smooth']
51 : 0.8;
52 $this->timeProvider = isset($options['time_provider'])
53 ? $options['time_provider']
54 : null;
55
56 $this->lastTxRateBucket = floor($this->time());
57 $this->lastThrottleTime = $this->time();
58 }
59
60 public function isEnabled()
61 {
62 return $this->enabled;
63 }
64
65 public function getSendToken()
66 {
67 $this->acquireToken(1);
68 }
69
70 public function updateSendingRate($isThrottled)
71 {
72 $this->updateMeasuredRate();
73
74 if ($isThrottled) {
75 if (!$this->isEnabled()) {
76 $rateToUse = $this->measuredTxRate;
77 } else {
78 $rateToUse = min($this->measuredTxRate, $this->fillRate);
79 }
80
81 $this->lastMaxRate = $rateToUse;
82 $this->calculateTimeWindow();
83 $this->lastThrottleTime = $this->time();
84 $calculatedRate = $this->cubicThrottle($rateToUse);
85 $this->enableTokenBucket();
86 } else {
87 $this->calculateTimeWindow();
88 $calculatedRate = $this->cubicSuccess($this->time());
89 }
90 $newRate = min($calculatedRate, 2 * $this->measuredTxRate);
91 $this->updateTokenBucketRate($newRate);
92 return $newRate;
93 }
94
95 private function acquireToken($amount)
96 {
97 if (!$this->enabled) {
98 return true;
99 }
100
101 $this->refillTokenBucket();
102
103 if ($amount > $this->currentCapacity) {
104 usleep((int) (1000000 * ($amount - $this->currentCapacity) / $this->fillRate));
105 }
106
107 $this->currentCapacity -= $amount;
108 return true;
109 }
110
111 private function calculateTimeWindow()
112 {
113 $this->timeWindow = pow(($this->lastMaxRate * (1 - $this->beta) / $this->scaleConstant), 0.333);
114 }
115
116 private function cubicSuccess($timestamp)
117 {
118 $dt = $timestamp - $this->lastThrottleTime;
119 return $this->scaleConstant * pow($dt - $this->timeWindow, 3) + $this->lastMaxRate;
120 }
121
122 private function cubicThrottle($rateToUse)
123 {
124 return $rateToUse * $this->beta;
125 }
126
127 private function enableTokenBucket()
128 {
129 $this->enabled = true;
130 }
131
132 private function refillTokenBucket()
133 {
134 $timestamp = $this->time();
135 if (!isset($this->lastTimestamp)) {
136 $this->lastTimestamp = $timestamp;
137 return;
138 }
139 $fillAmount = ($timestamp - $this->lastTimestamp) * $this->fillRate;
140 $this->currentCapacity = $this->currentCapacity + $fillAmount;
141 if (!is_null($this->maxCapacity)) {
142 $this->currentCapacity = min(
143 $this->maxCapacity,
144 $this->currentCapacity
145 );
146 }
147
148 $this->lastTimestamp = $timestamp;
149 }
150
151 private function time()
152 {
153 if (is_callable($this->timeProvider)) {
154 $provider = $this->timeProvider;
155 $time = $provider();
156 return $time;
157 }
158 return microtime(true);
159 }
160
161 private function updateMeasuredRate()
162 {
163 $timestamp = $this->time();
164 $timeBucket = floor(round($timestamp, 3) * 2) / 2;
165 $this->requestCount++;
166 if ($timeBucket > $this->lastTxRateBucket) {
167 $currentRate = $this->requestCount / ($timeBucket - $this->lastTxRateBucket);
168 $this->measuredTxRate = ($currentRate * $this->smooth)
169 + ($this->measuredTxRate * (1 - $this->smooth));
170 $this->requestCount = 0;
171 $this->lastTxRateBucket = $timeBucket;
172 }
173 }
174
175 private function updateTokenBucketRate($newRps)
176 {
177 $this->refillTokenBucket();
178 $this->fillRate = max($newRps, $this->minFillRate);
179 $this->maxCapacity = max($newRps, $this->minCapacity);
180 $this->currentCapacity = min($this->currentCapacity, $this->maxCapacity);
181 }
182 }
183