aboutsummaryrefslogtreecommitdiffstats
path: root/includes/libs/WRStats/LimitBatch.php
blob: 3758a40fc6e3d5c27d945b5d00c836a3d92fb075 (plain) (blame)
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 );
	}
}