Completed
Branch master (a465d1)
by
unknown
26:13
created

ObjectCache::getMainWANInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
/**
3
 * Functions to get cache objects.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @ingroup Cache
22
 */
23
24
use MediaWiki\Logger\LoggerFactory;
25
use MediaWiki\MediaWikiServices;
26
27
/**
28
 * Functions to get cache objects
29
 *
30
 * The word "cache" has two main dictionary meanings, and both
31
 * are used in this factory class. They are:
32
 *
33
 *   - a) Cache (the computer science definition).
34
 *        A place to store copies or computations on existing data for
35
 *        higher access speeds.
36
 *   - b) Storage.
37
 *        A place to store lightweight data that is not canonically
38
 *        stored anywhere else (e.g. a "hoard" of objects).
39
 *
40
 * The former should always use strongly consistent stores, so callers don't
41
 * have to deal with stale reads. The later may be eventually consistent, but
42
 * callers can use BagOStuff:READ_LATEST to see the latest available data.
43
 *
44
 * Primary entry points:
45
 *
46
 * - ObjectCache::getMainWANInstance()
47
 *   Purpose: Memory cache.
48
 *   Stored in the local data-center's main cache (keyspace different from local-cluster cache).
49
 *   Delete events are broadcasted to other DCs main cache. See WANObjectCache for details.
50
 *
51
 * - ObjectCache::getLocalServerInstance( $fallbackType )
52
 *   Purpose: Memory cache for very hot keys.
53
 *   Stored only on the individual web server (typically APC for web requests,
54
 *   and EmptyBagOStuff in CLI mode).
55
 *   Not replicated to the other servers.
56
 *
57
 * - ObjectCache::getLocalClusterInstance()
58
 *   Purpose: Memory storage for per-cluster coordination and tracking.
59
 *   A typical use case would be a rate limit counter or cache regeneration mutex.
60
 *   Stored centrally within the local data-center. Not replicated to other DCs.
61
 *   Configured by $wgMainCacheType.
62
 *
63
 * - ObjectCache::getMainStashInstance()
64
 *   Purpose: Ephemeral global storage.
65
 *   Stored centrally within the primary data-center.
66
 *   Changes are applied there first and replicated to other DCs (best-effort).
67
 *   To retrieve the latest value (e.g. not from a slave), use BagOStuff::READ_LATEST.
68
 *   This store may be subject to LRU style evictions.
69
 *
70
 * - ObjectCache::getInstance( $cacheType )
71
 *   Purpose: Special cases (like tiered memory/disk caches).
72
 *   Get a specific cache type by key in $wgObjectCaches.
73
 *
74
 * All the above cache instances (BagOStuff and WANObjectCache) have their makeKey()
75
 * method scoped to the *current* wiki ID. Use makeGlobalKey() to avoid this scoping
76
 * when using keys that need to be shared amongst wikis.
77
 *
78
 * @ingroup Cache
79
 */
80
class ObjectCache {
81
	/** @var BagOStuff[] Map of (id => BagOStuff) */
82
	public static $instances = [];
83
	/** @var WANObjectCache[] Map of (id => WANObjectCache) */
84
	public static $wanInstances = [];
85
86
	/**
87
	 * Get a cached instance of the specified type of cache object.
88
	 *
89
	 * @param string $id A key in $wgObjectCaches.
90
	 * @return BagOStuff
91
	 */
92
	public static function getInstance( $id ) {
93
		if ( !isset( self::$instances[$id] ) ) {
94
			self::$instances[$id] = self::newFromId( $id );
95
		}
96
97
		return self::$instances[$id];
98
	}
99
100
	/**
101
	 * Get a cached instance of the specified type of WAN cache object.
102
	 *
103
	 * @since 1.26
104
	 * @param string $id A key in $wgWANObjectCaches.
105
	 * @return WANObjectCache
106
	 */
107
	public static function getWANInstance( $id ) {
108
		if ( !isset( self::$wanInstances[$id] ) ) {
109
			self::$wanInstances[$id] = self::newWANCacheFromId( $id );
110
		}
111
112
		return self::$wanInstances[$id];
113
	}
114
115
	/**
116
	 * Create a new cache object of the specified type.
117
	 *
118
	 * @param string $id A key in $wgObjectCaches.
119
	 * @return BagOStuff
120
	 * @throws MWException
121
	 */
122
	public static function newFromId( $id ) {
123
		global $wgObjectCaches;
124
125
		if ( !isset( $wgObjectCaches[$id] ) ) {
126
			throw new MWException( "Invalid object cache type \"$id\" requested. " .
127
				"It is not present in \$wgObjectCaches." );
128
		}
129
130
		return self::newFromParams( $wgObjectCaches[$id] );
131
	}
132
133
	/**
134
	 * Get the default keyspace for this wiki.
135
	 *
136
	 * This is either the value of the `CachePrefix` configuration variable,
137
	 * or (if the former is unset) the `DBname` configuration variable, with
138
	 * `DBprefix` (if defined).
139
	 *
140
	 * @return string
141
	 */
142
	public static function getDefaultKeyspace() {
143
		global $wgCachePrefix;
144
145
		$keyspace = $wgCachePrefix;
146
		if ( is_string( $keyspace ) && $keyspace !== '' ) {
147
			return $keyspace;
148
		}
149
150
		return wfWikiID();
151
	}
152
153
	/**
154
	 * Create a new cache object from parameters.
155
	 *
156
	 * @param array $params Must have 'factory' or 'class' property.
157
	 *  - factory: Callback passed $params that returns BagOStuff.
158
	 *  - class: BagOStuff subclass constructed with $params.
159
	 *  - loggroup: Alias to set 'logger' key with LoggerFactory group.
160
	 *  - .. Other parameters passed to factory or class.
161
	 * @return BagOStuff
162
	 * @throws MWException
163
	 */
164
	public static function newFromParams( $params ) {
0 ignored issues
show
Coding Style introduced by
newFromParams uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
165 View Code Duplication
		if ( isset( $params['loggroup'] ) ) {
166
			$params['logger'] = LoggerFactory::getInstance( $params['loggroup'] );
167
		} else {
168
			$params['logger'] = LoggerFactory::getInstance( 'objectcache' );
169
		}
170
		if ( !isset( $params['keyspace'] ) ) {
171
			$params['keyspace'] = self::getDefaultKeyspace();
172
		}
173
		if ( isset( $params['factory'] ) ) {
174
			return call_user_func( $params['factory'], $params );
175
		} elseif ( isset( $params['class'] ) ) {
176
			$class = $params['class'];
177
			// Automatically set the 'async' update handler
178
			$params['asyncHandler'] = isset( $params['asyncHandler'] )
179
				? $params['asyncHandler']
180
				: 'DeferredUpdates::addCallableUpdate';
181
			// Enable reportDupes by default
182
			$params['reportDupes'] = isset( $params['reportDupes'] )
183
				? $params['reportDupes']
184
				: true;
185
			// Do b/c logic for MemcachedBagOStuff
186
			if ( is_subclass_of( $class, 'MemcachedBagOStuff' ) ) {
187
				if ( !isset( $params['servers'] ) ) {
188
					$params['servers'] = $GLOBALS['wgMemCachedServers'];
189
				}
190
				if ( !isset( $params['debug'] ) ) {
191
					$params['debug'] = $GLOBALS['wgMemCachedDebug'];
192
				}
193
				if ( !isset( $params['persistent'] ) ) {
194
					$params['persistent'] = $GLOBALS['wgMemCachedPersistent'];
195
				}
196
				if ( !isset( $params['timeout'] ) ) {
197
					$params['timeout'] = $GLOBALS['wgMemCachedTimeout'];
198
				}
199
			}
200
			return new $class( $params );
201
		} else {
202
			throw new MWException( "The definition of cache type \""
203
				. print_r( $params, true ) . "\" lacks both "
204
				. "factory and class parameters." );
205
		}
206
	}
207
208
	/**
209
	 * Factory function for CACHE_ANYTHING (referenced from DefaultSettings.php)
210
	 *
211
	 * CACHE_ANYTHING means that stuff has to be cached, not caching is not an option.
212
	 * If a caching method is configured for any of the main caches ($wgMainCacheType,
213
	 * $wgMessageCacheType, $wgParserCacheType), then CACHE_ANYTHING will effectively
214
	 * be an alias to the configured cache choice for that.
215
	 * If no cache choice is configured (by default $wgMainCacheType is CACHE_NONE),
216
	 * then CACHE_ANYTHING will forward to CACHE_DB.
217
	 *
218
	 * @param array $params
219
	 * @return BagOStuff
220
	 */
221
	public static function newAnything( $params ) {
222
		global $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType;
223
		$candidates = [ $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType ];
224
		foreach ( $candidates as $candidate ) {
225
			if ( $candidate !== CACHE_NONE && $candidate !== CACHE_ANYTHING ) {
226
				return self::getInstance( $candidate );
227
			}
228
		}
229
		return self::getInstance( CACHE_DB );
230
	}
231
232
	/**
233
	 * Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
234
	 *
235
	 * This will look for any APC style server-local cache.
236
	 * A fallback cache can be specified if none is found.
237
	 *
238
	 *     // Direct calls
239
	 *     ObjectCache::getLocalServerInstance( $fallbackType );
240
	 *
241
	 *     // From $wgObjectCaches via newFromParams()
242
	 *     ObjectCache::getLocalServerInstance( array( 'fallback' => $fallbackType ) );
243
	 *
244
	 * @param int|string|array $fallback Fallback cache or parameter map with 'fallback'
245
	 * @return BagOStuff
246
	 * @throws MWException
247
	 * @since 1.27
248
	 */
249
	public static function getLocalServerInstance( $fallback = CACHE_NONE ) {
250
		if ( function_exists( 'apc_fetch' ) ) {
251
			$id = 'apc';
252
		} elseif ( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) {
253
			$id = 'xcache';
254
		} elseif ( function_exists( 'wincache_ucache_get' ) ) {
255
			$id = 'wincache';
256
		} else {
257
			if ( is_array( $fallback ) ) {
258
				$id = isset( $fallback['fallback'] ) ? $fallback['fallback'] : CACHE_NONE;
259
			} else {
260
				$id = $fallback;
261
			}
262
		}
263
264
		return self::getInstance( $id );
265
	}
266
267
	/**
268
	 * @param array $params [optional] Array key 'fallback' for $fallback.
269
	 * @param int|string $fallback Fallback cache, e.g. (CACHE_NONE, "hash") (since 1.24)
270
	 * @return BagOStuff
271
	 * @deprecated 1.27
272
	 */
273
	public static function newAccelerator( $params = [], $fallback = null ) {
274
		if ( $fallback === null ) {
275
			if ( is_array( $params ) && isset( $params['fallback'] ) ) {
276
				$fallback = $params['fallback'];
277
			} elseif ( !is_array( $params ) ) {
278
				$fallback = $params;
279
			}
280
		}
281
282
		return self::getLocalServerInstance( $fallback );
283
	}
284
285
	/**
286
	 * Create a new cache object of the specified type.
287
	 *
288
	 * @since 1.26
289
	 * @param string $id A key in $wgWANObjectCaches.
290
	 * @return WANObjectCache
291
	 * @throws MWException
292
	 */
293
	public static function newWANCacheFromId( $id ) {
294
		global $wgWANObjectCaches;
295
296
		if ( !isset( $wgWANObjectCaches[$id] ) ) {
297
			throw new MWException( "Invalid object cache type \"$id\" requested. " .
298
				"It is not present in \$wgWANObjectCaches." );
299
		}
300
301
		$params = $wgWANObjectCaches[$id];
302
		foreach ( $params['channels'] as $action => $channel ) {
303
			$params['relayers'][$action] = MediaWikiServices::getInstance()->getEventRelayerGroup()
304
				->getRelayer( $channel );
305
			$params['channels'][$action] = $channel;
306
		}
307
		$params['cache'] = self::newFromId( $params['cacheId'] );
308 View Code Duplication
		if ( isset( $params['loggroup'] ) ) {
309
			$params['logger'] = LoggerFactory::getInstance( $params['loggroup'] );
310
		} else {
311
			$params['logger'] = LoggerFactory::getInstance( 'objectcache' );
312
		}
313
		$class = $params['class'];
314
315
		return new $class( $params );
316
	}
317
318
	/**
319
	 * Get the main cluster-local cache object.
320
	 *
321
	 * @since 1.27
322
	 * @return BagOStuff
323
	 */
324
	public static function getLocalClusterInstance() {
325
		global $wgMainCacheType;
326
327
		return self::getInstance( $wgMainCacheType );
328
	}
329
330
	/**
331
	 * Get the main WAN cache object.
332
	 *
333
	 * @since 1.26
334
	 * @return WANObjectCache
335
	 */
336
	public static function getMainWANInstance() {
337
		global $wgMainWANCache;
338
339
		return self::getWANInstance( $wgMainWANCache );
340
	}
341
342
	/**
343
	 * Get the cache object for the main stash.
344
	 *
345
	 * Stash objects are BagOStuff instances suitable for storing light
346
	 * weight data that is not canonically stored elsewhere (such as RDBMS).
347
	 * Stashes should be configured to propagate changes to all data-centers.
348
	 *
349
	 * Callers should be prepared for:
350
	 *   - a) Writes to be slower in non-"primary" (e.g. HTTP GET/HEAD only) DCs
351
	 *   - b) Reads to be eventually consistent, e.g. for get()/getMulti()
352
	 * In general, this means avoiding updates on idempotent HTTP requests and
353
	 * avoiding an assumption of perfect serializability (or accepting anomalies).
354
	 * Reads may be eventually consistent or data might rollback as nodes flap.
355
	 * Callers can use BagOStuff:READ_LATEST to see the latest available data.
356
	 *
357
	 * @return BagOStuff
358
	 * @since 1.26
359
	 */
360
	public static function getMainStashInstance() {
361
		global $wgMainStash;
362
363
		return self::getInstance( $wgMainStash );
364
	}
365
366
	/**
367
	 * Clear all the cached instances.
368
	 */
369
	public static function clear() {
370
		self::$instances = [];
371
		self::$wanInstances = [];
372
	}
373
}
374