MediaWiki  master
ClassicInterwikiLookup.php
Go to the documentation of this file.
1 <?php
24 
25 use Cdb\Exception as CdbException;
26 use Cdb\Reader as CdbReader;
27 use Interwiki;
28 use Language;
29 use MapCacheLRU;
32 use WANObjectCache;
33 use WikiMap;
35 
49 
53  private $localCache;
54 
58  private $contLang;
59 
63  private $objectCache;
64 
69 
73  private $cdbData;
74 
79 
83  private $fallbackSite;
84 
88  private $cdbReader = null;
89 
93  private $thisSite = null;
94 
96  private $hookRunner;
97 
112  public function __construct(
115  HookContainer $hookContainer,
117  $cdbData,
120  ) {
121  $this->localCache = new MapCacheLRU( 100 );
122 
123  $this->contLang = $contLang;
124  $this->objectCache = $objectCache;
125  $this->hookRunner = new HookRunner( $hookContainer );
126  $this->objectCacheExpiry = $objectCacheExpiry;
127  $this->cdbData = $cdbData;
128  $this->interwikiScopes = $interwikiScopes;
129  $this->fallbackSite = $fallbackSite;
130  }
131 
138  public function isValidInterwiki( $prefix ) {
139  $result = $this->fetch( $prefix );
140 
141  return (bool)$result;
142  }
143 
150  public function fetch( $prefix ) {
151  if ( $prefix == '' ) {
152  return null;
153  }
154 
155  $prefix = $this->contLang->lc( $prefix );
156  if ( $this->localCache->has( $prefix ) ) {
157  return $this->localCache->get( $prefix );
158  }
159 
160  if ( $this->cdbData ) {
161  $iw = $this->getInterwikiCached( $prefix );
162  } else {
163  $iw = $this->load( $prefix );
164  if ( !$iw ) {
165  $iw = false;
166  }
167  }
168  $this->localCache->set( $prefix, $iw );
169 
170  return $iw;
171  }
172 
178  public function resetLocalCache() {
179  $this->localCache->clear();
180  }
181 
186  public function invalidateCache( $prefix ) {
187  $this->localCache->clear( $prefix );
188 
189  $key = $this->objectCache->makeKey( 'interwiki', $prefix );
190  $this->objectCache->delete( $key );
191  }
192 
201  private function getInterwikiCached( $prefix ) {
202  $value = $this->getInterwikiCacheEntry( $prefix );
203 
204  if ( $value ) {
205  // Split values
206  list( $local, $url ) = explode( ' ', $value, 2 );
207  return new Interwiki( $prefix, $url, '', '', (int)$local );
208  } else {
209  return false;
210  }
211  }
212 
221  private function getInterwikiCacheEntry( $prefix ) {
222  wfDebug( __METHOD__ . "( $prefix )" );
223 
224  $wikiId = WikiMap::getCurrentWikiId();
225 
226  $value = false;
227  try {
228  // Resolve site name
229  if ( $this->interwikiScopes >= 3 && !$this->thisSite ) {
230  $this->thisSite = $this->getCacheValue( '__sites:' . $wikiId );
231  if ( $this->thisSite == '' ) {
232  $this->thisSite = $this->fallbackSite;
233  }
234  }
235 
236  $value = $this->getCacheValue( $wikiId . ':' . $prefix );
237  // Site level
238  if ( $value == '' && $this->interwikiScopes >= 3 ) {
239  $value = $this->getCacheValue( "_{$this->thisSite}:{$prefix}" );
240  }
241  // Global Level
242  if ( $value == '' && $this->interwikiScopes >= 2 ) {
243  $value = $this->getCacheValue( "__global:{$prefix}" );
244  }
245  if ( $value == 'undef' ) {
246  $value = '';
247  }
248  } catch ( CdbException $e ) {
249  wfDebug( __METHOD__ . ": CdbException caught, error message was "
250  . $e->getMessage() );
251  }
252 
253  return $value;
254  }
255 
256  private function getCacheValue( $key ) {
257  if ( $this->cdbReader === null ) {
258  if ( is_string( $this->cdbData ) ) {
259  $this->cdbReader = \Cdb\Reader::open( $this->cdbData );
260  } elseif ( is_array( $this->cdbData ) ) {
261  $this->cdbReader = new \Cdb\Reader\Hash( $this->cdbData );
262  } else {
263  $this->cdbReader = false;
264  }
265  }
266 
267  if ( $this->cdbReader ) {
268  return $this->cdbReader->get( $key );
269  } else {
270  return false;
271  }
272  }
273 
280  private function load( $prefix ) {
281  $iwData = [];
282  if ( !$this->hookRunner->onInterwikiLoadPrefix( $prefix, $iwData ) ) {
283  return $this->loadFromArray( $iwData );
284  }
285 
286  if ( is_array( $iwData ) ) {
287  $iw = $this->loadFromArray( $iwData );
288  if ( $iw ) {
289  return $iw; // handled by hook
290  }
291  }
292 
293  $fname = __METHOD__;
294  $iwData = $this->objectCache->getWithSetCallback(
295  $this->objectCache->makeKey( 'interwiki', $prefix ),
296  $this->objectCacheExpiry,
297  function ( $oldValue, &$ttl, array &$setOpts ) use ( $prefix, $fname ) {
298  $dbr = wfGetDB( DB_REPLICA ); // TODO: inject LoadBalancer
299 
300  $setOpts += Database::getCacheSetOptions( $dbr );
301 
302  $row = $dbr->selectRow(
303  'interwiki',
304  self::selectFields(),
305  [ 'iw_prefix' => $prefix ],
306  $fname
307  );
308 
309  return $row ? (array)$row : '!NONEXISTENT';
310  }
311  );
312 
313  if ( is_array( $iwData ) ) {
314  return $this->loadFromArray( $iwData ) ?: false;
315  }
316 
317  return false;
318  }
319 
326  private function loadFromArray( $mc ) {
327  if ( isset( $mc['iw_url'] ) ) {
328  $url = $mc['iw_url'];
329  $local = $mc['iw_local'] ?? 0;
330  $trans = $mc['iw_trans'] ?? 0;
331  $api = $mc['iw_api'] ?? '';
332  $wikiId = $mc['iw_wikiid'] ?? '';
333 
334  return new Interwiki( null, $url, $api, $wikiId, $local, $trans );
335  }
336 
337  return false;
338  }
339 
346  private function getAllPrefixesCached( $local ) {
347  wfDebug( __METHOD__ . "()" );
348 
349  $wikiId = WikiMap::getCurrentWikiId();
350 
351  $data = [];
352  try {
353  /* Resolve site name */
354  if ( $this->interwikiScopes >= 3 && !$this->thisSite ) {
355  $site = $this->getCacheValue( '__sites:' . $wikiId );
356 
357  if ( $site == '' ) {
358  $this->thisSite = $this->fallbackSite;
359  } else {
360  $this->thisSite = $site;
361  }
362  }
363 
364  // List of interwiki sources
365  $sources = [];
366  // Global Level
367  if ( $this->interwikiScopes >= 2 ) {
368  $sources[] = '__global';
369  }
370  // Site level
371  if ( $this->interwikiScopes >= 3 ) {
372  $sources[] = '_' . $this->thisSite;
373  }
374  $sources[] = $wikiId;
375 
376  foreach ( $sources as $source ) {
377  $list = $this->getCacheValue( '__list:' . $source );
378  foreach ( explode( ' ', $list ) as $iw_prefix ) {
379  $row = $this->getCacheValue( "{$source}:{$iw_prefix}" );
380  if ( !$row ) {
381  continue;
382  }
383 
384  list( $iw_local, $iw_url ) = explode( ' ', $row );
385 
386  if ( $local !== null && $local != $iw_local ) {
387  continue;
388  }
389 
390  $data[$iw_prefix] = [
391  'iw_prefix' => $iw_prefix,
392  'iw_url' => $iw_url,
393  'iw_local' => $iw_local,
394  ];
395  }
396  }
397  } catch ( CdbException $e ) {
398  wfDebug( __METHOD__ . ": CdbException caught, error message was "
399  . $e->getMessage() );
400  }
401 
402  return array_values( $data );
403  }
404 
411  private function getAllPrefixesDB( $local ) {
412  $db = wfGetDB( DB_REPLICA ); // TODO: inject DB LoadBalancer
413 
414  $where = [];
415 
416  if ( $local !== null ) {
417  if ( $local == 1 ) {
418  $where['iw_local'] = 1;
419  } elseif ( $local == 0 ) {
420  $where['iw_local'] = 0;
421  }
422  }
423 
424  $res = $db->select( 'interwiki',
425  self::selectFields(),
426  $where, __METHOD__, [ 'ORDER BY' => 'iw_prefix' ]
427  );
428 
429  $retval = [];
430  foreach ( $res as $row ) {
431  $retval[] = (array)$row;
432  }
433 
434  return $retval;
435  }
436 
443  public function getAllPrefixes( $local = null ) {
444  if ( $this->cdbData ) {
445  return $this->getAllPrefixesCached( $local );
446  }
447 
448  return $this->getAllPrefixesDB( $local );
449  }
450 
456  private static function selectFields() {
457  return [
458  'iw_prefix',
459  'iw_url',
460  'iw_api',
461  'iw_wikiid',
462  'iw_local',
463  'iw_trans'
464  ];
465  }
466 
467 }
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:49
MediaWiki\Interwiki\ClassicInterwikiLookup\$localCache
MapCacheLRU $localCache
Definition: ClassicInterwikiLookup.php:53
MediaWiki\Interwiki\ClassicInterwikiLookup\isValidInterwiki
isValidInterwiki( $prefix)
Check whether an interwiki prefix exists.
Definition: ClassicInterwikiLookup.php:138
MediaWiki\Interwiki\ClassicInterwikiLookup
InterwikiLookup implementing the "classic" interwiki storage (hardcoded up to MW 1....
Definition: ClassicInterwikiLookup.php:48
MediaWiki\Interwiki\ClassicInterwikiLookup\getAllPrefixesCached
getAllPrefixesCached( $local)
Fetch all interwiki prefixes from interwiki cache.
Definition: ClassicInterwikiLookup.php:346
MediaWiki\Interwiki\ClassicInterwikiLookup\resetLocalCache
resetLocalCache()
Resets locally cached Interwiki objects.
Definition: ClassicInterwikiLookup.php:178
MediaWiki\Interwiki\ClassicInterwikiLookup\$thisSite
string null $thisSite
Definition: ClassicInterwikiLookup.php:93
$res
$res
Definition: testCompression.php:57
WikiMap\getCurrentWikiId
static getCurrentWikiId()
Definition: WikiMap.php:303
MediaWiki\Interwiki\ClassicInterwikiLookup\$interwikiScopes
int $interwikiScopes
Definition: ClassicInterwikiLookup.php:78
MediaWiki\Interwiki\ClassicInterwikiLookup\$contLang
Language $contLang
Definition: ClassicInterwikiLookup.php:58
$dbr
$dbr
Definition: testCompression.php:54
MediaWiki\Interwiki\ClassicInterwikiLookup\getAllPrefixesDB
getAllPrefixesDB( $local)
Fetch all interwiki prefixes from DB.
Definition: ClassicInterwikiLookup.php:411
MediaWiki\Interwiki\ClassicInterwikiLookup\getInterwikiCacheEntry
getInterwikiCacheEntry( $prefix)
Get entry from interwiki cache.
Definition: ClassicInterwikiLookup.php:221
Wikimedia\Rdbms\Database\getCacheSetOptions
static getCacheSetOptions(IDatabase $db1, IDatabase $db2=null)
Merge the result of getSessionLagStatus() for several DBs using the most pessimistic values to estima...
Definition: Database.php:4703
MediaWiki\Interwiki\ClassicInterwikiLookup\load
load( $prefix)
Load the interwiki, trying first memcached then the DB.
Definition: ClassicInterwikiLookup.php:280
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2463
MediaWiki\Interwiki\InterwikiLookup
Service interface for looking up Interwiki records.
Definition: InterwikiLookup.php:32
MediaWiki\Interwiki\ClassicInterwikiLookup\$objectCache
WANObjectCache $objectCache
Definition: ClassicInterwikiLookup.php:63
MapCacheLRU
Handles a simple LRU key/value map with a maximum number of entries.
Definition: MapCacheLRU.php:38
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
MediaWiki\Interwiki\ClassicInterwikiLookup\$hookRunner
HookRunner $hookRunner
Definition: ClassicInterwikiLookup.php:96
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:913
MediaWiki\Interwiki\ClassicInterwikiLookup\$cdbData
bool array string $cdbData
Definition: ClassicInterwikiLookup.php:73
MediaWiki\Interwiki\ClassicInterwikiLookup\fetch
fetch( $prefix)
Fetch an Interwiki object.
Definition: ClassicInterwikiLookup.php:150
MediaWiki\Interwiki\ClassicInterwikiLookup\getAllPrefixes
getAllPrefixes( $local=null)
Returns all interwiki prefixes.
Definition: ClassicInterwikiLookup.php:443
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:125
MediaWiki\Interwiki\ClassicInterwikiLookup\$objectCacheExpiry
int $objectCacheExpiry
Definition: ClassicInterwikiLookup.php:68
MediaWiki\Interwiki\ClassicInterwikiLookup\$fallbackSite
string $fallbackSite
Definition: ClassicInterwikiLookup.php:83
MediaWiki\Interwiki\ClassicInterwikiLookup\invalidateCache
invalidateCache( $prefix)
Purge the in-process and object cache for an interwiki prefix.
Definition: ClassicInterwikiLookup.php:186
WikiMap
Helper tools for dealing with other locally-hosted wikis.
Definition: WikiMap.php:29
MediaWiki\Interwiki\ClassicInterwikiLookup\selectFields
static selectFields()
Return the list of interwiki fields that should be selected to create a new Interwiki object.
Definition: ClassicInterwikiLookup.php:456
MediaWiki\Interwiki\ClassicInterwikiLookup\__construct
__construct(Language $contLang, WANObjectCache $objectCache, HookContainer $hookContainer, $objectCacheExpiry, $cdbData, $interwikiScopes, $fallbackSite)
Definition: ClassicInterwikiLookup.php:112
Interwiki
Value object for representing interwiki records.
Definition: Interwiki.php:26
MediaWiki\Interwiki
Copyright (C) 2018 Kunal Mehta legoktm@member.fsf.org
Definition: ClassicInterwikiLookup.php:23
$source
$source
Definition: mwdoc-filter.php:34
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition: HookContainer.php:44
MediaWiki\Interwiki\ClassicInterwikiLookup\$cdbReader
CdbReader null $cdbReader
Definition: ClassicInterwikiLookup.php:88
MediaWiki\HookContainer\HookRunner
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:563
MediaWiki\Interwiki\ClassicInterwikiLookup\getInterwikiCached
getInterwikiCached( $prefix)
Fetch interwiki prefix data from local cache in constant database.
Definition: ClassicInterwikiLookup.php:201
MediaWiki\Interwiki\ClassicInterwikiLookup\getCacheValue
getCacheValue( $key)
Definition: ClassicInterwikiLookup.php:256
MediaWiki\Interwiki\ClassicInterwikiLookup\loadFromArray
loadFromArray( $mc)
Fill in member variables from an array (e.g.
Definition: ClassicInterwikiLookup.php:326
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:41