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
|
<?php
namespace Wikimedia\WRStats;
/**
* A class representing a batch of increment/peek operations on a WRStatsRateLimiter
*
* @since 1.39
*/
class LimitBatch {
/** @var WRStatsRateLimiter */
private $limiter;
/** @var int */
private $defaultAmount;
/** @var LimitOperation[] */
private $operations = [];
/**
* @internal Use WRStatsFactory::createRateLimiter()->createBatch() instead
* @param WRStatsRateLimiter $limiter
* @param int $defaultAmount
*/
public function __construct(
WRStatsRateLimiter $limiter,
$defaultAmount
) {
$this->limiter = $limiter;
$this->defaultAmount = $defaultAmount;
}
/**
* Construct a local entity key and queue an operation for it.
*
* @param string $condName The condition name to be incremented/tested,
* which must match one of the ones passed to createRateLimiter()
* @param mixed $components Entity key component or array of components
* @param int|null $amount The amount to increment by, or null to use the default
* @return $this
*/
public function localOp( $condName, $components = [], $amount = null ) {
if ( !is_array( $components ) ) {
$components = [ $components ];
}
$this->queueOp(
$condName,
new LocalEntityKey( array_merge( [ $condName ], $components ) ),
$amount
);
return $this;
}
/**
* Construct a global entity key and queue an operation for it.
*
* @param string $condName The condition name to be incremented/tested,
* which must match one of the ones passed to createRateLimiter()
* @param mixed $components Entity key components
* @param int|null $amount The amount, or null to use the default
* @return $this
*/
public function globalOp( $condName, $components = [], $amount = null ) {
if ( !is_array( $components ) ) {
$components = [ $components ];
}
$this->queueOp(
$condName,
new GlobalEntityKey( array_merge( [ $condName ], $components ) ),
$amount
);
return $this;
}
private function queueOp( $type, $entity, $amount ) {
$amount ??= $this->defaultAmount;
if ( isset( $this->operations[$type] ) ) {
throw new WRStatsError( 'Cannot queue multiple actions of the same type, ' .
'because the result array is indexed by type' );
}
$this->operations[$type] = new LimitOperation( $type, $entity, $amount );
}
/**
* Execute the batch, checking each operation against the defined limit,
* but don't actually increment the metrics.
*
* @return LimitBatchResult
*/
public function peek() {
return $this->limiter->peekBatch( $this->operations );
}
/**
* Execute the batch, unconditionally incrementing all the specified metrics.
*/
public function incr() {
$this->limiter->incrBatch( $this->operations );
}
/**
* Execute the batch, checking each operation against the defined limit.
* If all operations are allowed, all metrics will be incremented. If some
* of the operations exceed the limit, none of the metrics will be
* incremented.
*
* @return LimitBatchResult
*/
public function tryIncr() {
return $this->limiter->tryIncrBatch( $this->operations );
}
}
|