PluginProbe
Media Cloud Sync / 1.2.0
Media Cloud Sync v1.2.0
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
media-cloud-sync / includes / sdk / s3 / Aws / Retry / RateLimiter.php

RateLimiter.php in Media Cloud Sync 1.2.0, at includes/sdk/s3/Aws/Retry/RateLimiter.php

144 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\Aws\Retry;
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 // Optional callable time provider
17 private $timeProvider;
18 // Pre-set state variables
19 private $currentCapacity = 0;
20 private $enabled = \false;
21 private $lastMaxRate = 0;
22 private $measuredTxRate = 0;
23 private $requestCount = 0;
24 // Other state variables
25 private $fillRate;
26 private $lastThrottleTime;
27 private $lastTimestamp;
28 private $lastTxRateBucket;
29 private $maxCapacity;
30 private $timeWindow;
31 public function __construct($options = [])
32 {
33 $this->beta = isset($options['beta']) ? $options['beta'] : 0.7;
34 $this->minCapacity = isset($options['min_capacity']) ? $options['min_capacity'] : 1;
35 $this->minFillRate = isset($options['min_fill_rate']) ? $options['min_fill_rate'] : 0.5;
36 $this->scaleConstant = isset($options['scale_constant']) ? $options['scale_constant'] : 0.4;
37 $this->smooth = isset($options['smooth']) ? $options['smooth'] : 0.8;
38 $this->timeProvider = isset($options['time_provider']) ? $options['time_provider'] : null;
39 $this->lastTxRateBucket = \floor($this->time());
40 $this->lastThrottleTime = $this->time();
41 }
42 public function isEnabled()
43 {
44 return $this->enabled;
45 }
46 public function getSendToken()
47 {
48 $this->acquireToken(1);
49 }
50 public function updateSendingRate($isThrottled)
51 {
52 $this->updateMeasuredRate();
53 if ($isThrottled) {
54 if (!$this->isEnabled()) {
55 $rateToUse = $this->measuredTxRate;
56 } else {
57 $rateToUse = \min($this->measuredTxRate, $this->fillRate);
58 }
59 $this->lastMaxRate = $rateToUse;
60 $this->calculateTimeWindow();
61 $this->lastThrottleTime = $this->time();
62 $calculatedRate = $this->cubicThrottle($rateToUse);
63 $this->enableTokenBucket();
64 } else {
65 $this->calculateTimeWindow();
66 $calculatedRate = $this->cubicSuccess($this->time());
67 }
68 $newRate = \min($calculatedRate, 2 * $this->measuredTxRate);
69 $this->updateTokenBucketRate($newRate);
70 return $newRate;
71 }
72 private function acquireToken($amount)
73 {
74 if (!$this->enabled) {
75 return \true;
76 }
77 $this->refillTokenBucket();
78 if ($amount > $this->currentCapacity) {
79 \usleep((int) (1000000 * ($amount - $this->currentCapacity) / $this->fillRate));
80 }
81 $this->currentCapacity -= $amount;
82 return \true;
83 }
84 private function calculateTimeWindow()
85 {
86 $this->timeWindow = \pow($this->lastMaxRate * (1 - $this->beta) / $this->scaleConstant, 0.333);
87 }
88 private function cubicSuccess($timestamp)
89 {
90 $dt = $timestamp - $this->lastThrottleTime;
91 return $this->scaleConstant * \pow($dt - $this->timeWindow, 3) + $this->lastMaxRate;
92 }
93 private function cubicThrottle($rateToUse)
94 {
95 return $rateToUse * $this->beta;
96 }
97 private function enableTokenBucket()
98 {
99 $this->enabled = \true;
100 }
101 private function refillTokenBucket()
102 {
103 $timestamp = $this->time();
104 if (!isset($this->lastTimestamp)) {
105 $this->lastTimestamp = $timestamp;
106 return;
107 }
108 $fillAmount = ($timestamp - $this->lastTimestamp) * $this->fillRate;
109 $this->currentCapacity = $this->currentCapacity + $fillAmount;
110 if (!\is_null($this->maxCapacity)) {
111 $this->currentCapacity = \min($this->maxCapacity, $this->currentCapacity);
112 }
113 $this->lastTimestamp = $timestamp;
114 }
115 private function time()
116 {
117 if (\is_callable($this->timeProvider)) {
118 $provider = $this->timeProvider;
119 $time = $provider();
120 return $time;
121 }
122 return \microtime(\true);
123 }
124 private function updateMeasuredRate()
125 {
126 $timestamp = $this->time();
127 $timeBucket = \floor(\round($timestamp, 3) * 2) / 2;
128 $this->requestCount++;
129 if ($timeBucket > $this->lastTxRateBucket) {
130 $currentRate = $this->requestCount / ($timeBucket - $this->lastTxRateBucket);
131 $this->measuredTxRate = $currentRate * $this->smooth + $this->measuredTxRate * (1 - $this->smooth);
132 $this->requestCount = 0;
133 $this->lastTxRateBucket = $timeBucket;
134 }
135 }
136 private function updateTokenBucketRate($newRps)
137 {
138 $this->refillTokenBucket();
139 $this->fillRate = \max($newRps, $this->minFillRate);
140 $this->maxCapacity = \max($newRps, $this->minCapacity);
141 $this->currentCapacity = \min($this->currentCapacity, $this->maxCapacity);
142 }
143 }
144