File: EditStashCache.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (137 lines) | stat: -rw-r--r-- 3,675 bytes parent folder | download
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php

namespace MediaWiki\Extension\AbuseFilter;

use InvalidArgumentException;
use MediaWiki\Extension\AbuseFilter\Variables\VariableHolder;
use MediaWiki\Extension\AbuseFilter\Variables\VariablesManager;
use MediaWiki\Linker\LinkTarget;
use Psr\Log\LoggerInterface;
use Wikimedia\ObjectCache\BagOStuff;
use Wikimedia\Stats\IBufferingStatsdDataFactory;

/**
 * Wrapper around cache for storing and retrieving data from edit stash
 */
class EditStashCache {

	private const CACHE_VERSION = 'v5';

	/** @var BagOStuff */
	private $cache;

	/** @var IBufferingStatsdDataFactory */
	private $statsdDataFactory;

	/** @var VariablesManager */
	private $variablesManager;

	/** @var LoggerInterface */
	private $logger;

	/** @var LinkTarget */
	private $target;

	/** @var string */
	private $group;

	/**
	 * @param BagOStuff $cache
	 * @param IBufferingStatsdDataFactory $statsdDataFactory
	 * @param VariablesManager $variablesManager
	 * @param LoggerInterface $logger
	 * @param LinkTarget $target
	 * @param string $group
	 */
	public function __construct(
		BagOStuff $cache,
		IBufferingStatsdDataFactory $statsdDataFactory,
		VariablesManager $variablesManager,
		LoggerInterface $logger,
		LinkTarget $target,
		string $group
	) {
		$this->cache = $cache;
		$this->statsdDataFactory = $statsdDataFactory;
		$this->variablesManager = $variablesManager;
		$this->logger = $logger;
		$this->target = $target;
		$this->group = $group;
	}

	/**
	 * @param VariableHolder $vars For creating the key
	 * @param array $data Data to store
	 */
	public function store( VariableHolder $vars, array $data ): void {
		$key = $this->getStashKey( $vars );
		$this->cache->set( $key, $data, BagOStuff::TTL_MINUTE );
		$this->logCache( 'store', $key );
	}

	/**
	 * Search the cache to find data for a previous execution done for the current edit.
	 *
	 * @param VariableHolder $vars For creating the key
	 * @return false|array False on cache miss, the array with data otherwise
	 */
	public function seek( VariableHolder $vars ) {
		$key = $this->getStashKey( $vars );
		$value = $this->cache->get( $key );
		$status = $value !== false ? 'hit' : 'miss';
		$this->logCache( $status, $key );
		return $value;
	}

	/**
	 * Log cache operations related to stashed edits, i.e. store, hit and miss
	 *
	 * @param string $type Either 'store', 'hit' or 'miss'
	 * @param string $key The cache key used
	 * @throws InvalidArgumentException
	 */
	private function logCache( string $type, string $key ): void {
		if ( !in_array( $type, [ 'store', 'hit', 'miss' ] ) ) {
			// @codeCoverageIgnoreStart
			throw new InvalidArgumentException( '$type must be either "store", "hit" or "miss"' );
			// @codeCoverageIgnoreEnd
		}
		$this->logger->debug(
			__METHOD__ . ": cache {logtype} for '{target}' (key {key}).",
			[ 'logtype' => $type, 'target' => $this->target, 'key' => $key ]
		);
		$this->statsdDataFactory->increment( "abusefilter.check-stash.$type" );
	}

	/**
	 * Get the stash key for the current variables
	 *
	 * @param VariableHolder $vars
	 * @return string
	 */
	private function getStashKey( VariableHolder $vars ): string {
		$inputVars = $this->variablesManager->exportNonLazyVars( $vars );
		// Exclude noisy fields that have superficial changes
		$excludedVars = [
			'old_html' => true,
			'new_html' => true,
			'user_age' => true,
			'timestamp' => true,
			'page_age' => true,
			'page_last_edit_age' => true,
		];

		$inputVars = array_diff_key( $inputVars, $excludedVars );
		ksort( $inputVars );
		$hash = md5( serialize( $inputVars ) );

		return $this->cache->makeKey(
			'abusefilter',
			'check-stash',
			$this->group,
			$hash,
			self::CACHE_VERSION
		);
	}

}