MediaWiki master
ObjectCache.php
Go to the documentation of this file.
1<?php
30
70 public static $instances = [];
71
77
84 public static function getInstance( $id ) {
85 if ( !isset( self::$instances[$id] ) ) {
86 self::$instances[$id] = self::newFromId( $id );
87 }
88
89 return self::$instances[$id];
90 }
91
99 private static function newFromId( $id ) {
100 global $wgObjectCaches;
101
102 if ( !isset( $wgObjectCaches[$id] ) ) {
103 // Always recognize these ones
104 if ( $id === CACHE_NONE ) {
105 return new EmptyBagOStuff();
106 } elseif ( $id === CACHE_HASH ) {
107 return new HashBagOStuff();
108 }
109
110 throw new InvalidArgumentException( "Invalid object cache type \"$id\" requested. " .
111 "It is not present in \$wgObjectCaches." );
112 }
113
114 return self::newFromParams( $wgObjectCaches[$id] );
115 }
116
126 private static function getDefaultKeyspace() {
127 global $wgCachePrefix;
128
129 $keyspace = $wgCachePrefix;
130 if ( is_string( $keyspace ) && $keyspace !== '' ) {
131 return $keyspace;
132 }
133
134 return WikiMap::getCurrentWikiDbDomain()->getId();
135 }
136
148 public static function newFromParams( array $params, MediaWikiServices $services = null ) {
149 $services ??= MediaWikiServices::getInstance();
150 $conf = $services->getMainConfig();
151
152 // Apply default parameters and resolve the logger instance
153 $params += [
154 'logger' => LoggerFactory::getInstance( $params['loggroup'] ?? 'objectcache' ),
155 'keyspace' => self::getDefaultKeyspace(),
156 'asyncHandler' => [ DeferredUpdates::class, 'addCallableUpdate' ],
157 'reportDupes' => true,
158 'stats' => $services->getStatsFactory(),
159 ];
160
161 if ( isset( $params['factory'] ) ) {
162 $args = $params['args'] ?? [ $params ];
163
164 return call_user_func( $params['factory'], ...$args );
165 }
166
167 if ( !isset( $params['class'] ) ) {
168 throw new InvalidArgumentException(
169 'No "factory" nor "class" provided; got "' . print_r( $params, true ) . '"'
170 );
171 }
172
173 $class = $params['class'];
174
175 // Normalization and DI for SqlBagOStuff
176 if ( is_a( $class, SqlBagOStuff::class, true ) ) {
177 if ( isset( $params['globalKeyLB'] ) ) {
178 throw new InvalidArgumentException(
179 'globalKeyLB in $wgObjectCaches is no longer supported' );
180 }
181 if ( isset( $params['server'] ) && !isset( $params['servers'] ) ) {
182 $params['servers'] = [ $params['server'] ];
183 unset( $params['server'] );
184 }
185 if ( isset( $params['servers'] ) ) {
186 // In the past it was not required to set 'dbDirectory' in $wgObjectCaches
187 foreach ( $params['servers'] as &$server ) {
188 if ( $server['type'] === 'sqlite' && !isset( $server['dbDirectory'] ) ) {
189 $server['dbDirectory'] = $conf->get( MainConfigNames::SQLiteDataDir );
190 }
191 }
192 } elseif ( isset( $params['cluster'] ) ) {
193 $cluster = $params['cluster'];
194 $params['loadBalancerCallback'] = static function () use ( $services, $cluster ) {
195 return $services->getDBLoadBalancerFactory()->getExternalLB( $cluster );
196 };
197 $params += [ 'dbDomain' => false ];
198 } else {
199 $params['loadBalancerCallback'] = static function () use ( $services ) {
200 return $services->getDBLoadBalancer();
201 };
202 $params += [ 'dbDomain' => false ];
203 }
204 $params += [ 'writeBatchSize' => $conf->get( MainConfigNames::UpdateRowsPerQuery ) ];
205 }
206
207 // Normalization and DI for MemcachedBagOStuff
208 if ( is_subclass_of( $class, MemcachedBagOStuff::class ) ) {
209 $params += [
210 'servers' => $conf->get( MainConfigNames::MemCachedServers ),
211 'persistent' => $conf->get( MainConfigNames::MemCachedPersistent ),
212 'timeout' => $conf->get( MainConfigNames::MemCachedTimeout ),
213 ];
214 }
215
216 // Normalization and DI for MultiWriteBagOStuff
217 if ( is_a( $class, MultiWriteBagOStuff::class, true ) ) {
218 // Phan warns about foreach with non-array because it
219 // thinks any key can be Closure|IBufferingStatsdDataFactory
220 '@phan-var array{caches:array[]} $params';
221 foreach ( $params['caches'] ?? [] as $i => $cacheInfo ) {
222 // Ensure logger, keyspace, asyncHandler, etc are injected just as if
223 // one of these was configured without MultiWriteBagOStuff.
224 $params['caches'][$i] = self::newFromParams( $cacheInfo, $services );
225 }
226 }
227 if ( is_a( $class, RESTBagOStuff::class, true ) ) {
228 $params['telemetry'] = Telemetry::getInstance();
229 }
230
231 return new $class( $params );
232 }
233
247 public static function newAnything( $params ) {
248 return self::getInstance( self::getAnythingId() );
249 }
250
255 private static function getAnythingId() {
258 foreach ( $candidates as $candidate ) {
259 if ( $candidate === CACHE_ACCEL ) {
260 // CACHE_ACCEL might default to nothing if no APCu
261 // See includes/ServiceWiring.php
262 $class = self::getLocalServerCacheClass();
263 if ( $class !== EmptyBagOStuff::class ) {
264 return $candidate;
265 }
266 } elseif ( $candidate !== CACHE_NONE && $candidate !== CACHE_ANYTHING ) {
267 return $candidate;
268 }
269 }
270
271 $services = MediaWikiServices::getInstance();
272
273 if ( $services->isServiceDisabled( 'DBLoadBalancer' ) ) {
274 // The DBLoadBalancer service is disabled, so we can't use the database!
275 $candidate = CACHE_NONE;
276 } elseif ( $services->isStorageDisabled() ) {
277 // Storage services are disabled because MediaWikiServices::disableStorage()
278 // was called. This is typically the case during installation.
279 $candidate = CACHE_NONE;
280 } else {
281 $candidate = CACHE_DB;
282 }
283 return $candidate;
284 }
285
303 public static function getLocalServerInstance( $fallback = CACHE_NONE ) {
304 $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
305 if ( $cache instanceof EmptyBagOStuff ) {
306 if ( is_array( $fallback ) ) {
307 $fallback = $fallback['fallback'] ?? CACHE_NONE;
308 }
309 $cache = self::getInstance( $fallback );
310 }
311
312 return $cache;
313 }
314
321 public static function getLocalClusterInstance() {
322 return MediaWikiServices::getInstance()->get( '_LocalClusterCache' );
323 }
324
331 public static function isDatabaseId( $id ) {
332 global $wgObjectCaches;
333 if ( !isset( $wgObjectCaches[$id] ) ) {
334 return false;
335 }
336 $cache = $wgObjectCaches[$id];
337 if ( ( $cache['class'] ?? '' ) === SqlBagOStuff::class ) {
338 return true;
339 }
340 if ( ( $cache['factory'] ?? '' ) === 'ObjectCache::newAnything' ) {
341 $id = self::getAnythingId();
342 return self::isDatabaseId( $id );
343 }
344 return false;
345 }
346
350 public static function clear() {
351 self::$instances = [];
352 }
353
368 public static function makeLocalServerCache(): BagOStuff {
369 $params = [
370 'reportDupes' => false,
371 // Even simple caches must use a keyspace (T247562)
372 'keyspace' => self::getDefaultKeyspace(),
373 ];
374 $class = self::getLocalServerCacheClass();
375 return new $class( $params );
376 }
377
382 private static function getLocalServerCacheClass() {
383 if ( self::$localServerCacheClass !== null ) {
384 return self::$localServerCacheClass;
385 }
386 if ( function_exists( 'apcu_fetch' ) ) {
387 // Make sure the APCu methods actually store anything
388 if ( PHP_SAPI !== 'cli' || ini_get( 'apc.enable_cli' ) ) {
389 return APCUBagOStuff::class;
390
391 }
392 } elseif ( function_exists( 'wincache_ucache_get' ) ) {
393 return WinCacheBagOStuff::class;
394 }
395
396 return EmptyBagOStuff::class;
397 }
398}
const CACHE_NONE
Definition Defines.php:86
const CACHE_ANYTHING
Definition Defines.php:85
const CACHE_ACCEL
Definition Defines.php:89
const CACHE_HASH
Definition Defines.php:90
const CACHE_DB
Definition Defines.php:87
$fallback
array $params
The job parameters.
Class representing a cache/ephemeral data store.
Definition BagOStuff.php:85
A BagOStuff object with no objects in it.
Simple store for keeping values in an associative array for the current process.
Defer callable updates to run later in the PHP process.
Service for handling telemetry data.
Definition Telemetry.php:29
Create PSR-3 logger objects.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Tools for dealing with other locally-hosted wikis.
Definition WikiMap.php:31
Functions to get cache objects.
static getLocalServerInstance( $fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from configuration)
static makeLocalServerCache()
Create a new BagOStuff instance for local-server caching.
static isDatabaseId( $id)
Determine whether a config ID would access the database.
static newAnything( $params)
Factory function for CACHE_ANYTHING (referenced by configuration)
static clear()
Clear all the cached instances.
static newFromParams(array $params, MediaWikiServices $services=null)
Create a new cache object from parameters.
static BagOStuff[] $instances
Map of (id => BagOStuff)
static getInstance( $id)
Get a cached instance of the specified type of cache object.
static string $localServerCacheClass
static getLocalClusterInstance()
Get the main cluster-local cache object.
$wgObjectCaches
Config variable stub for the ObjectCaches setting, for use by phpdoc and IDEs.
$wgParserCacheType
Config variable stub for the ParserCacheType setting, for use by phpdoc and IDEs.
$wgMainCacheType
Config variable stub for the MainCacheType setting, for use by phpdoc and IDEs.
$wgCachePrefix
Config variable stub for the CachePrefix setting, for use by phpdoc and IDEs.
$wgMessageCacheType
Config variable stub for the MessageCacheType setting, for use by phpdoc and IDEs.