MediaWiki master
ObjectCacheFactory.php
Go to the documentation of this file.
1<?php
26
64 public const CONSTRUCTOR_OPTIONS = [
65 MainConfigNames::SQLiteDataDir,
66 MainConfigNames::UpdateRowsPerQuery,
67 MainConfigNames::MemCachedServers,
68 MainConfigNames::MemCachedPersistent,
69 MainConfigNames::MemCachedTimeout,
70 MainConfigNames::CachePrefix,
71 MainConfigNames::ObjectCaches,
72 MainConfigNames::MainCacheType,
73 ];
74
75 private ServiceOptions $options;
76 private StatsFactory $stats;
77 private Spi $logger;
79 private $instances = [];
80 private string $domainId;
82 private $dbLoadBalancerFactory;
83
84 public function __construct(
85 ServiceOptions $options,
86 StatsFactory $stats,
87 Spi $loggerSpi,
88 callable $dbLoadBalancerFactory,
89 string $domainId
90 ) {
91 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
92 $this->options = $options;
93 $this->stats = $stats;
94 $this->logger = $loggerSpi;
95 $this->dbLoadBalancerFactory = $dbLoadBalancerFactory;
96 $this->domainId = $domainId;
97 }
98
108 private function getDefaultKeyspace(): string {
109 $cachePrefix = $this->options->get( MainConfigNames::CachePrefix );
110 if ( is_string( $cachePrefix ) && $cachePrefix !== '' ) {
111 return $cachePrefix;
112 }
113
114 return $this->domainId;
115 }
116
123 private function newFromId( $id ): BagOStuff {
124 if ( $id === CACHE_ANYTHING ) {
126 }
127
128 if ( !isset( $this->options->get( MainConfigNames::ObjectCaches )[$id] ) ) {
129 // Always recognize these
130 if ( $id === CACHE_NONE ) {
131 return new EmptyBagOStuff();
132 } elseif ( $id === CACHE_HASH ) {
133 return new HashBagOStuff();
134 } elseif ( $id === CACHE_ACCEL ) {
135 return ObjectCache::makeLocalServerCache( $this->getDefaultKeyspace() );
136 }
137
138 throw new InvalidArgumentException( "Invalid object cache type \"$id\" requested. " .
139 "It is not present in \$wgObjectCaches." );
140 }
141
142 return $this->newFromParams( $this->options->get( MainConfigNames::ObjectCaches )[$id] );
143 }
144
151 public function getInstance( $id ): BagOStuff {
152 if ( !isset( $this->instances[$id] ) ) {
153 $this->instances[$id] = $this->newFromId( $id );
154 }
155
156 return $this->instances[$id];
157 }
158
174 public function newFromParams( array $params ): BagOStuff {
175 $logger = $this->logger->getLogger( $params['loggroup'] ?? 'objectcache' );
176 // Apply default parameters and resolve the logger instance
177 $params += [
178 'logger' => $logger,
179 'keyspace' => $this->getDefaultKeyspace(),
180 'asyncHandler' => [ DeferredUpdates::class, 'addCallableUpdate' ],
181 'reportDupes' => true,
182 'stats' => $this->stats,
183 ];
184
185 if ( isset( $params['factory'] ) ) {
186 $args = $params['args'] ?? [ $params ];
187
188 return call_user_func( $params['factory'], ...$args );
189 }
190
191 if ( !isset( $params['class'] ) ) {
192 throw new InvalidArgumentException(
193 'No "factory" nor "class" provided; got "' . print_r( $params, true ) . '"'
194 );
195 }
196
197 $class = $params['class'];
198
199 // Normalization and DI for SqlBagOStuff
200 if ( is_a( $class, SqlBagOStuff::class, true ) ) {
201 $this->prepareSqlBagOStuffFromParams( $params );
202 }
203
204 // Normalization and DI for MemcachedBagOStuff
205 if ( is_subclass_of( $class, MemcachedBagOStuff::class ) ) {
206 $this->prepareMemcachedBagOStuffFromParams( $params );
207 }
208
209 // Normalization and DI for MultiWriteBagOStuff
210 if ( is_a( $class, MultiWriteBagOStuff::class, true ) ) {
211 $this->prepareMultiWriteBagOStuffFromParams( $params );
212 }
213 if ( is_a( $class, RESTBagOStuff::class, true ) ) {
214 $this->prepareRESTBagOStuffFromParams( $params );
215 }
216
217 return new $class( $params );
218 }
219
220 private function prepareSqlBagOStuffFromParams( array &$params ): void {
221 if ( isset( $params['globalKeyLB'] ) ) {
222 throw new InvalidArgumentException(
223 'globalKeyLB in $wgObjectCaches is no longer supported' );
224 }
225 if ( isset( $params['server'] ) && !isset( $params['servers'] ) ) {
226 $params['servers'] = [ $params['server'] ];
227 unset( $params['server'] );
228 }
229 if ( isset( $params['servers'] ) ) {
230 // In the past it was not required to set 'dbDirectory' in $wgObjectCaches
231 foreach ( $params['servers'] as &$server ) {
232 if ( $server['type'] === 'sqlite' && !isset( $server['dbDirectory'] ) ) {
233 $server['dbDirectory'] = $this->options->get( MainConfigNames::SQLiteDataDir );
234 }
235 }
236 } elseif ( isset( $params['cluster'] ) ) {
237 $cluster = $params['cluster'];
238 $dbLbFactory = $this->dbLoadBalancerFactory;
239 $params['loadBalancerCallback'] = static function () use ( $cluster, $dbLbFactory ) {
240 return $dbLbFactory()->getExternalLB( $cluster );
241 };
242 $params += [ 'dbDomain' => false ];
243 } else {
244 $dbLbFactory = $this->dbLoadBalancerFactory;
245 $params['loadBalancerCallback'] = static function () use ( $dbLbFactory ) {
246 return $dbLbFactory()->getMainLb();
247 };
248 $params += [ 'dbDomain' => false ];
249 }
250 $params += [ 'writeBatchSize' => $this->options->get( MainConfigNames::UpdateRowsPerQuery ) ];
251 }
252
253 private function prepareMemcachedBagOStuffFromParams( array &$params ): void {
254 $params += [
255 'servers' => $this->options->get( MainConfigNames::MemCachedServers ),
256 'persistent' => $this->options->get( MainConfigNames::MemCachedPersistent ),
257 'timeout' => $this->options->get( MainConfigNames::MemCachedTimeout ),
258 ];
259 }
260
261 private function prepareMultiWriteBagOStuffFromParams( array &$params ): void {
262 // Phan warns about foreach with non-array because it
263 // thinks any key can be Closure|IBufferingStatsdDataFactory
264 '@phan-var array{caches:array[]} $params';
265 foreach ( $params['caches'] ?? [] as $i => $cacheInfo ) {
266 // Ensure logger, keyspace, asyncHandler, etc are injected just as if
267 // one of these was configured without MultiWriteBagOStuff.
268 $params['caches'][$i] = $this->newFromParams( $cacheInfo );
269 }
270 }
271
272 private function prepareRESTBagOStuffFromParams( array &$params ): void {
273 $params['telemetry'] = Telemetry::getInstance();
274 }
275
293 $cache = $this->getInstance( CACHE_ACCEL );
294 if ( $cache instanceof EmptyBagOStuff ) {
295 if ( is_array( $fallback ) ) {
296 $fallback = $fallback['fallback'] ?? CACHE_NONE;
297 }
298 $cache = $this->getInstance( $fallback );
299 }
300
301 return $cache;
302 }
303
307 public function clear(): void {
308 $this->instances = [];
309 }
310
318 public function setInstanceForTesting( $cacheId, BagOStuff $cache ): void {
319 if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
320 throw new LogicException( __METHOD__ . ' can not be called outside of tests' );
321 }
322 $this->instances[$cacheId] = $cache;
323 }
324}
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
$fallback
array $params
The job parameters.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
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.
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Service for handling telemetry data.
Definition Telemetry.php:29
A class containing constants representing the names of configuration variables.
Factory for cache objects as configured in the ObjectCaches setting.
getInstance( $id)
Get a cached instance of the specified type of cache object.
__construct(ServiceOptions $options, StatsFactory $stats, Spi $loggerSpi, callable $dbLoadBalancerFactory, string $domainId)
getLocalServerInstance( $fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from configuration)
setInstanceForTesting( $cacheId, BagOStuff $cache)
newFromParams(array $params)
clear()
Clear all the cached instances.
static getAnythingId()
static makeLocalServerCache( $keyspace)
Create a new BagOStuff instance for local-server caching.
StatsFactory Implementation.
Service provider interface to create \Psr\Log\LoggerInterface objects.
Definition Spi.php:64