MediaWiki REL1_39
WRStatsRateLimiter.php
Go to the documentation of this file.
1<?php
2
3namespace Wikimedia\WRStats;
4
10 private $store;
12 private $conditions;
14 private $specs;
16 private $prefix;
18 private $now;
19
21 public const BUCKET_COUNT = 30;
22
33 public function __construct(
34 StatsStore $store,
35 $conditions,
36 $prefix = 'WRLimit',
37 $options = []
38 ) {
39 $this->store = $store;
40 $this->conditions = $conditions;
41 $this->prefix = $prefix;
42 $bucketCount = $options['bucketCount'] ?? self::BUCKET_COUNT;
43
44 $specs = [];
45 foreach ( $conditions as $name => $condition ) {
46 $specs[$name] = [
47 'sequences' => [ [
48 'timeStep' => $condition->window / $bucketCount,
49 'expiry' => $condition->window
50 ] ]
51 ];
52 }
53 $this->specs = $specs;
54 }
55
63 public function createBatch( $defaultAmount = 1 ) {
64 return new LimitBatch( $this, $defaultAmount );
65 }
66
76 public function peek(
77 string $condName,
78 EntityKey $entityKey = null,
79 $amount = 1
81 $actions = [ new LimitOperation( $condName, $entityKey, $amount ) ];
82 $result = $this->peekBatch( $actions );
83 return $result->getAllResults()[0];
84 }
85
93 public function peekBatch( array $operations ) {
94 $reader = new WRStatsReader( $this->store, $this->specs, $this->prefix );
95 if ( $this->now !== null ) {
96 $reader->setCurrentTime( $this->now );
97 }
98
99 $rates = [];
100 $amounts = [];
101 foreach ( $operations as $operation ) {
102 $name = $operation->condName;
103 $cond = $this->conditions[$name] ?? null;
104 if ( $cond === null ) {
105 throw new WRStatsError( __METHOD__ .
106 ": unrecognized metric \"$name\"" );
107 }
108 if ( !isset( $rates[$name] ) ) {
109 $range = $reader->latest( $cond->window );
110 $rates[$name] = $reader->getRate( $name, $operation->entityKey, $range );
111 $amounts[$name] = 0;
112 }
113 $amounts[$name] += $operation->amount;
114 }
115
116 $results = [];
117 foreach ( $operations as $i => $operation ) {
118 $name = $operation->condName;
119 $total = $rates[$name]->total();
120 $cond = $this->conditions[$name];
121 $results[$i] = new LimitOperationResult(
122 $cond,
123 $total,
124 $total + $amounts[$name]
125 );
126 }
127 return new LimitBatchResult( $results );
128 }
129
139 public function tryIncr(
140 string $condName,
141 EntityKey $entityKey = null,
142 $amount = 1
144 $actions = [ new LimitOperation( $condName, $entityKey, $amount ) ];
145 $result = $this->tryIncrBatch( $actions );
146 return $result->getAllResults()[0];
147 }
148
156 public function tryIncrBatch( array $operations ) {
157 $result = $this->peekBatch( $operations );
158 if ( $result->isAllowed() ) {
159 $this->incrBatch( $operations );
160 }
161 return $result;
162 }
163
172 public function incr(
173 string $condName,
174 EntityKey $entityKey = null,
175 $amount = 1
176 ) {
177 $actions = [ new LimitOperation( $condName, $entityKey, $amount ) ];
178 $this->incrBatch( $actions );
179 }
180
186 public function incrBatch( array $operations ) {
187 $writer = new WRStatsWriter( $this->store, $this->specs, $this->prefix );
188 if ( $this->now !== null ) {
189 $writer->setCurrentTime( $this->now );
190 }
191 foreach ( $operations as $operation ) {
192 $writer->incr(
193 $operation->condName,
194 $operation->entityKey,
195 $operation->amount
196 );
197 }
198 $writer->flush();
199 }
200
206 public function setCurrentTime( $now ) {
207 $this->now = $now;
208 }
209
213 public function resetCurrentTime() {
214 $this->now = null;
215 }
216}
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.
Class representing one item in a limit batch.
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,...
The narrow interface WRStats needs into a memcached-like key-value store.