MediaWiki REL1_31
ClassicInterwikiLookup.php
Go to the documentation of this file.
1<?php
24
25use Cdb\Exception as CdbException;
26use Cdb\Reader as CdbReader;
27use Hooks;
28use Interwiki;
29use Language;
30use MapCacheLRU;
33
47
51 private $localCache;
52
57
61 private $objectCache;
62
67
71 private $cdbData;
72
77
82
86 private $cdbReader = null;
87
91 private $thisSite = null;
92
106 function __construct(
110 $cdbData,
113 ) {
114 $this->localCache = new MapCacheLRU( 100 );
115
116 $this->contentLanguage = $contentLanguage;
117 $this->objectCache = $objectCache;
118 $this->objectCacheExpiry = $objectCacheExpiry;
119 $this->cdbData = $cdbData;
120 $this->interwikiScopes = $interwikiScopes;
121 $this->fallbackSite = $fallbackSite;
122 }
123
130 public function isValidInterwiki( $prefix ) {
131 $result = $this->fetch( $prefix );
132
133 return (bool)$result;
134 }
135
142 public function fetch( $prefix ) {
143 if ( $prefix == '' ) {
144 return null;
145 }
146
147 $prefix = $this->contentLanguage->lc( $prefix );
148 if ( $this->localCache->has( $prefix ) ) {
149 return $this->localCache->get( $prefix );
150 }
151
152 if ( $this->cdbData ) {
153 $iw = $this->getInterwikiCached( $prefix );
154 } else {
155 $iw = $this->load( $prefix );
156 if ( !$iw ) {
157 $iw = false;
158 }
159 }
160 $this->localCache->set( $prefix, $iw );
161
162 return $iw;
163 }
164
170 public function resetLocalCache() {
171 $this->localCache->clear();
172 }
173
178 public function invalidateCache( $prefix ) {
179 $this->localCache->clear( $prefix );
180
181 $key = $this->objectCache->makeKey( 'interwiki', $prefix );
182 $this->objectCache->delete( $key );
183 }
184
193 private function getInterwikiCached( $prefix ) {
194 $value = $this->getInterwikiCacheEntry( $prefix );
195
196 if ( $value ) {
197 // Split values
198 list( $local, $url ) = explode( ' ', $value, 2 );
199 return new Interwiki( $prefix, $url, '', '', (int)$local );
200 } else {
201 return false;
202 }
203 }
204
213 private function getInterwikiCacheEntry( $prefix ) {
214 wfDebug( __METHOD__ . "( $prefix )\n" );
215 $value = false;
216 try {
217 // Resolve site name
218 if ( $this->interwikiScopes >= 3 && !$this->thisSite ) {
219 $this->thisSite = $this->getCacheValue( '__sites:' . wfWikiID() );
220 if ( $this->thisSite == '' ) {
221 $this->thisSite = $this->fallbackSite;
222 }
223 }
224
225 $value = $this->getCacheValue( wfWikiID() . ':' . $prefix );
226 // Site level
227 if ( $value == '' && $this->interwikiScopes >= 3 ) {
228 $value = $this->getCacheValue( "_{$this->thisSite}:{$prefix}" );
229 }
230 // Global Level
231 if ( $value == '' && $this->interwikiScopes >= 2 ) {
232 $value = $this->getCacheValue( "__global:{$prefix}" );
233 }
234 if ( $value == 'undef' ) {
235 $value = '';
236 }
237 } catch ( CdbException $e ) {
238 wfDebug( __METHOD__ . ": CdbException caught, error message was "
239 . $e->getMessage() );
240 }
241
242 return $value;
243 }
244
245 private function getCacheValue( $key ) {
246 if ( $this->cdbReader === null ) {
247 if ( is_string( $this->cdbData ) ) {
248 $this->cdbReader = \Cdb\Reader::open( $this->cdbData );
249 } elseif ( is_array( $this->cdbData ) ) {
250 $this->cdbReader = new \Cdb\Reader\Hash( $this->cdbData );
251 } else {
252 $this->cdbReader = false;
253 }
254 }
255
256 if ( $this->cdbReader ) {
257 return $this->cdbReader->get( $key );
258 } else {
259 return false;
260 }
261 }
262
269 private function load( $prefix ) {
270 $iwData = [];
271 if ( !Hooks::run( 'InterwikiLoadPrefix', [ $prefix, &$iwData ] ) ) {
272 return $this->loadFromArray( $iwData );
273 }
274
275 if ( is_array( $iwData ) ) {
276 $iw = $this->loadFromArray( $iwData );
277 if ( $iw ) {
278 return $iw; // handled by hook
279 }
280 }
281
282 $iwData = $this->objectCache->getWithSetCallback(
283 $this->objectCache->makeKey( 'interwiki', $prefix ),
284 $this->objectCacheExpiry,
285 function ( $oldValue, &$ttl, array &$setOpts ) use ( $prefix ) {
286 $dbr = wfGetDB( DB_REPLICA ); // TODO: inject LoadBalancer
287
288 $setOpts += Database::getCacheSetOptions( $dbr );
289
290 $row = $dbr->selectRow(
291 'interwiki',
292 self::selectFields(),
293 [ 'iw_prefix' => $prefix ],
294 __METHOD__
295 );
296
297 return $row ? (array)$row : '!NONEXISTENT';
298 }
299 );
300
301 if ( is_array( $iwData ) ) {
302 return $this->loadFromArray( $iwData ) ?: false;
303 }
304
305 return false;
306 }
307
314 private function loadFromArray( $mc ) {
315 if ( isset( $mc['iw_url'] ) ) {
316 $url = $mc['iw_url'];
317 $local = isset( $mc['iw_local'] ) ? $mc['iw_local'] : 0;
318 $trans = isset( $mc['iw_trans'] ) ? $mc['iw_trans'] : 0;
319 $api = isset( $mc['iw_api'] ) ? $mc['iw_api'] : '';
320 $wikiId = isset( $mc['iw_wikiid'] ) ? $mc['iw_wikiid'] : '';
321
322 return new Interwiki( null, $url, $api, $wikiId, $local, $trans );
323 }
324
325 return false;
326 }
327
334 private function getAllPrefixesCached( $local ) {
335 wfDebug( __METHOD__ . "()\n" );
336 $data = [];
337 try {
338 /* Resolve site name */
339 if ( $this->interwikiScopes >= 3 && !$this->thisSite ) {
340 $site = $this->getCacheValue( '__sites:' . wfWikiID() );
341
342 if ( $site == '' ) {
343 $this->thisSite = $this->fallbackSite;
344 } else {
345 $this->thisSite = $site;
346 }
347 }
348
349 // List of interwiki sources
350 $sources = [];
351 // Global Level
352 if ( $this->interwikiScopes >= 2 ) {
353 $sources[] = '__global';
354 }
355 // Site level
356 if ( $this->interwikiScopes >= 3 ) {
357 $sources[] = '_' . $this->thisSite;
358 }
359 $sources[] = wfWikiID();
360
361 foreach ( $sources as $source ) {
362 $list = $this->getCacheValue( '__list:' . $source );
363 foreach ( explode( ' ', $list ) as $iw_prefix ) {
364 $row = $this->getCacheValue( "{$source}:{$iw_prefix}" );
365 if ( !$row ) {
366 continue;
367 }
368
369 list( $iw_local, $iw_url ) = explode( ' ', $row );
370
371 if ( $local !== null && $local != $iw_local ) {
372 continue;
373 }
374
375 $data[$iw_prefix] = [
376 'iw_prefix' => $iw_prefix,
377 'iw_url' => $iw_url,
378 'iw_local' => $iw_local,
379 ];
380 }
381 }
382 } catch ( CdbException $e ) {
383 wfDebug( __METHOD__ . ": CdbException caught, error message was "
384 . $e->getMessage() );
385 }
386
387 return array_values( $data );
388 }
389
396 private function getAllPrefixesDB( $local ) {
397 $db = wfGetDB( DB_REPLICA ); // TODO: inject DB LoadBalancer
398
399 $where = [];
400
401 if ( $local !== null ) {
402 if ( $local == 1 ) {
403 $where['iw_local'] = 1;
404 } elseif ( $local == 0 ) {
405 $where['iw_local'] = 0;
406 }
407 }
408
409 $res = $db->select( 'interwiki',
410 self::selectFields(),
411 $where, __METHOD__, [ 'ORDER BY' => 'iw_prefix' ]
412 );
413
414 $retval = [];
415 foreach ( $res as $row ) {
416 $retval[] = (array)$row;
417 }
418
419 return $retval;
420 }
421
428 public function getAllPrefixes( $local = null ) {
429 if ( $this->cdbData ) {
430 return $this->getAllPrefixesCached( $local );
431 }
432
433 return $this->getAllPrefixesDB( $local );
434 }
435
441 private static function selectFields() {
442 return [
443 'iw_prefix',
444 'iw_url',
445 'iw_api',
446 'iw_wikiid',
447 'iw_local',
448 'iw_trans'
449 ];
450 }
451
452}
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
Hooks class.
Definition Hooks.php:34
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition Hooks.php:203
Value object for representing interwiki records.
Definition Interwiki.php:27
Internationalisation code.
Definition Language.php:35
Handles a simple LRU key/value map with a maximum number of entries.
InterwikiLookup implementing the "classic" interwiki storage (hardcoded up to MW 1....
getAllPrefixesDB( $local)
Fetch all interwiki prefixes from DB.
load( $prefix)
Load the interwiki, trying first memcached then the DB.
fetch( $prefix)
Fetch an Interwiki object.
__construct(Language $contentLanguage, WANObjectCache $objectCache, $objectCacheExpiry, $cdbData, $interwikiScopes, $fallbackSite)
invalidateCache( $prefix)
Purge the in-process and object cache for an interwiki prefix.
resetLocalCache()
Resets locally cached Interwiki objects.
static selectFields()
Return the list of interwiki fields that should be selected to create a new Interwiki object.
getAllPrefixes( $local=null)
Returns all interwiki prefixes.
isValidInterwiki( $prefix)
Check whether an interwiki prefix exists.
loadFromArray( $mc)
Fill in member variables from an array (e.g.
getInterwikiCacheEntry( $prefix)
Get entry from interwiki cache.
getAllPrefixesCached( $local)
Fetch all interwiki prefixes from interwiki cache.
getInterwikiCached( $prefix)
Fetch interwiki prefix data from local cache in constant database.
Multi-datacenter aware caching interface.
Relational database abstraction object.
Definition Database.php:48
$res
Definition database.txt:21
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition deferred.txt:11
when a variable name is used in a function
Definition design.txt:94
the array() calling protocol came about after MediaWiki 1.4rc1.
namespace being checked & $result
Definition hooks.txt:2323
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account incomplete not yet checked for validity & $retval
Definition hooks.txt:266
returning false will NOT prevent logging $e
Definition hooks.txt:2176
Service interface for looking up Interwiki records.
MediaWiki has optional support for a high distributed memory object caching system For general information on but for a larger site with heavy load
Definition memcached.txt:6
$source
Copyright (C) 2018 Kunal Mehta legoktm@member.fsf.org
const DB_REPLICA
Definition defines.php:25