MediaWiki master
WRStatsRateLimiter.php
Go to the documentation of this file.
1<?php
2
3namespace Wikimedia\WRStats;
4
12 private $store;
14 private $conditions;
16 private $specs;
18 private $prefix;
20 private $now;
21
23 public const BUCKET_COUNT = 30;
24
32 public function __construct(
33 StatsStore $store,
34 $conditions,
35 $prefix = 'WRLimit',
36 $options = []
37 ) {
38 $this->store = $store;
39 $this->conditions = $conditions;
40 $this->prefix = $prefix;
41 $bucketCount = $options['bucketCount'] ?? self::BUCKET_COUNT;
42
43 $specs = [];
44 foreach ( $conditions as $name => $condition ) {
45 $specs[$name] = [
46 'sequences' => [ [
47 'timeStep' => $condition->window / $bucketCount,
48 'expiry' => $condition->window
49 ] ]
50 ];
51 }
52 $this->specs = $specs;
53 }
54
62 public function createBatch( $defaultAmount = 1 ) {
63 return new LimitBatch( $this, $defaultAmount );
64 }
65
75 public function peek(
76 string $condName,
77 EntityKey $entityKey = null,
78 $amount = 1
80 $actions = [ new LimitOperation( $condName, $entityKey, $amount ) ];
81 $result = $this->peekBatch( $actions );
82 return $result->getAllResults()[0];
83 }
84
92 public function peekBatch( array $operations ) {
93 $reader = new WRStatsReader( $this->store, $this->specs, $this->prefix );
94 if ( $this->now !== null ) {
95 $reader->setCurrentTime( $this->now );
96 }
97
98 $rates = [];
99 $amounts = [];
100 foreach ( $operations as $operation ) {
101 $name = $operation->condName;
102 $cond = $this->conditions[$name] ?? null;
103 if ( $cond === null ) {
104 throw new WRStatsError( "Unrecognized metric \"$name\"" );
105 }
106 if ( !isset( $rates[$name] ) ) {
107 $range = $reader->latest( $cond->window );
108 $rates[$name] = $reader->getRate( $name, $operation->entityKey, $range );
109 $amounts[$name] = 0;
110 }
111 $amounts[$name] += $operation->amount;
112 }
113
114 $results = [];
115 foreach ( $operations as $i => $operation ) {
116 $name = $operation->condName;
117 $total = $rates[$name]->total();
118 $cond = $this->conditions[$name];
119 $results[$i] = new LimitOperationResult(
120 $cond,
121 $total,
122 $total + $amounts[$name]
123 );
124 }
125 return new LimitBatchResult( $results );
126 }
127
137 public function tryIncr(
138 string $condName,
139 EntityKey $entityKey = null,
140 $amount = 1
142 $actions = [ new LimitOperation( $condName, $entityKey, $amount ) ];
143 $result = $this->tryIncrBatch( $actions );
144 return $result->getAllResults()[0];
145 }
146
154 public function tryIncrBatch( array $operations ) {
155 $result = $this->peekBatch( $operations );
156 if ( $result->isAllowed() ) {
157 $this->incrBatch( $operations );
158 }
159 return $result;
160 }
161
170 public function incr(
171 string $condName,
172 EntityKey $entityKey = null,
173 $amount = 1
174 ) {
175 $actions = [ new LimitOperation( $condName, $entityKey, $amount ) ];
176 $this->incrBatch( $actions );
177 }
178
184 public function incrBatch( array $operations ) {
185 $writer = new WRStatsWriter( $this->store, $this->specs, $this->prefix );
186 if ( $this->now !== null ) {
187 $writer->setCurrentTime( $this->now );
188 }
189 foreach ( $operations as $operation ) {
190 $writer->incr(
191 $operation->condName,
192 $operation->entityKey,
193 $operation->amount
194 );
195 }
196 $writer->flush();
197 }
198
204 public function setCurrentTime( $now ) {
205 $this->now = $now;
206 }
207
211 public function resetCurrentTime() {
212 $this->now = null;
213 }
214}
Base class for entity keys.
Definition EntityKey.php:13
A class representing the results from a batch operation.
A class representing a batch of increment/peek operations on a WRStatsRateLimiter.
Information about the result of a single item in a limit batch.
One item in a LimitBatch.
Exception class for errors thrown by the WRStats library.
A rate limiter with a WRStats backend.
resetCurrentTime()
Forget a time set with setCurrentTime().
tryIncrBatch(array $operations)
Check if the limit would be exceeded by execution of the given set of increment operations.
__construct(StatsStore $store, $conditions, $prefix='WRLimit', $options=[])
setCurrentTime( $now)
Set the current time.
incr(string $condName, EntityKey $entityKey=null, $amount=1)
Unconditionally increment a metric.
createBatch( $defaultAmount=1)
Create a batch object for rate limiting of multiple metrics.
peek(string $condName, EntityKey $entityKey=null, $amount=1)
Check whether executing a single operation would exceed the defined limit, without incrementing the c...
peekBatch(array $operations)
Check whether executing a given set of increment operations would exceed any defined limit,...
incrBatch(array $operations)
Unconditionally increment a set of metrics.
const BUCKET_COUNT
Default number of time buckets per action.
tryIncr(string $condName, EntityKey $entityKey=null, $amount=1)
Check if the limit would be exceeded by incrementing the specified metric.
Readers gather a batch of read operations, returning promises.
Writers gather a batch of increment operations and then commit them when flush() is called,...
Narrow interface for WRStatsFactory to a memcached-like key-value store.