From: Aaron Schulz Date: Wed, 20 Feb 2019 00:26:10 +0000 (-0800) Subject: Backport WikiMap/JobQueueGroup logic to handle hyphenated DB names X-Git-Tag: 1.31.2~27 X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=a7e147b7ee64830788a67779e2d8137017c0e919;hp=b47ae9f94bccb493a73d2731ef33c6a9b79ab92e Backport WikiMap/JobQueueGroup logic to handle hyphenated DB names Although the documentation in DefaultSettings.php states that such cases should be avoided, some common cases and code paths can be made to work easily enough. Partially cherry-picked from dcd0a3d53, 51945dbca3594, and 5196ac32c6. Bug: T204423 Change-Id: Ia3c5855b18b98d9fc5bc02fe68358cfa52ccbce1 --- diff --git a/RELEASE-NOTES-1.31 b/RELEASE-NOTES-1.31 index 28d026ded3..1a66001cb8 100644 --- a/RELEASE-NOTES-1.31 +++ b/RELEASE-NOTES-1.31 @@ -58,6 +58,7 @@ THIS IS NOT A RELEASE YET has been started. * (T216968) Return pageid as int in both list=iwbacklinks and list=langbacklinks. * (T215169) Fix for Database::update() with IGNORE option fails on PostgreSQL. +* (T204423) Backport support for hyphenated DB names in JobQueueGroup. == MediaWiki 1.31.1 == diff --git a/includes/WikiMap.php b/includes/WikiMap.php index 8bb37b5c88..9cc308d228 100644 --- a/includes/WikiMap.php +++ b/includes/WikiMap.php @@ -258,4 +258,37 @@ class WikiMap { ? "{$domain->getDatabase()}-{$domain->getTablePrefix()}" : $domain->getDatabase(); } + + /** + * @param DatabaseDomain|string $domain + * @return bool Whether $domain has the same DB/prefix as the current wiki + * @since 1.33 + */ + public static function isCurrentWikiDbDomain( $domain ) { + $domain = DatabaseDomain::newFromId( $domain ); + $curDomain = self::getCurrentWikiDbDomain(); + + if ( !in_array( $curDomain->getSchema(), [ null, 'mediawiki' ], true ) ) { + // Include the schema if it is set and is not the default placeholder. + // This means a site admin may have specifically taylored the schemas. + // Domain IDs might use the form --, meaning that + // the schema portion must be accounted for to disambiguate wikis. + return $curDomain->equals( $domain ); + } + + return ( + $curDomain->getDatabase() === $domain->getDatabase() && + $curDomain->getTablePrefix() === $domain->getTablePrefix() + ); + } + + /** + * @return DatabaseDomain Database domain of the current wiki + * @since 1.33 + */ + public static function getCurrentWikiDbDomain() { + global $wgDBname, $wgDBmwschema, $wgDBprefix; + // Avoid invoking LBFactory to avoid any chance of recursion + return new DatabaseDomain( $wgDBname, $wgDBmwschema, (string)$wgDBprefix ); + } } diff --git a/includes/jobqueue/JobQueue.php b/includes/jobqueue/JobQueue.php index 1f4f179a67..3a8bf1ab8a 100644 --- a/includes/jobqueue/JobQueue.php +++ b/includes/jobqueue/JobQueue.php @@ -362,7 +362,7 @@ abstract class JobQueue { global $wgJobClasses; $this->assertNotReadOnly(); - if ( $this->wiki !== wfWikiID() ) { + if ( !WikiMap::isCurrentWikiDbDomain( $this->wiki ) ) { throw new MWException( "Cannot pop '{$this->type}' job off foreign wiki queue." ); } elseif ( !isset( $wgJobClasses[$this->type] ) ) { // Do not pop jobs if there is no class for the queue type diff --git a/includes/jobqueue/JobQueueGroup.php b/includes/jobqueue/JobQueueGroup.php index addc7fc2e1..df55fc579a 100644 --- a/includes/jobqueue/JobQueueGroup.php +++ b/includes/jobqueue/JobQueueGroup.php @@ -33,8 +33,8 @@ class JobQueueGroup { /** @var ProcessCacheLRU */ protected $cache; - /** @var string Wiki ID */ - protected $wiki; + /** @var string Wiki DB domain ID */ + protected $domain; /** @var string|bool Read only rationale (or false if r/w) */ protected $readOnlyReason; /** @var bool Whether the wiki is not recognized in configuration */ @@ -56,34 +56,40 @@ class JobQueueGroup { const CACHE_VERSION = 1; // integer; cache version /** - * @param string $wiki Wiki ID + * @param string $domain Wiki DB domain ID * @param string|bool $readOnlyReason Read-only reason or false */ - protected function __construct( $wiki, $readOnlyReason ) { - $this->wiki = $wiki; + protected function __construct( $domain, $readOnlyReason ) { + $this->domain = $domain; $this->readOnlyReason = $readOnlyReason; $this->cache = new ProcessCacheLRU( 10 ); } /** - * @param bool|string $wiki Wiki ID + * @param bool|string $domain Wiki domain ID * @return JobQueueGroup */ - public static function singleton( $wiki = false ) { + public static function singleton( $domain = false ) { global $wgLocalDatabases; - $wiki = ( $wiki === false ) ? wfWikiID() : $wiki; + if ( $domain === false ) { + $domain = WikiMap::getCurrentWikiDbDomain()->getId(); + } - if ( !isset( self::$instances[$wiki] ) ) { - self::$instances[$wiki] = new self( $wiki, wfConfiguredReadOnlyReason() ); + if ( !isset( self::$instances[$domain] ) ) { + self::$instances[$domain] = new self( $domain, wfConfiguredReadOnlyReason() ); // Make sure jobs are not getting pushed to bogus wikis. This can confuse // the job runner system into spawning endless RPC requests that fail (T171371). - if ( $wiki !== wfWikiID() && !in_array( $wiki, $wgLocalDatabases ) ) { - self::$instances[$wiki]->invalidWiki = true; + $wikiId = WikiMap::getWikiIdFromDomain( $domain ); + if ( + !WikiMap::isCurrentWikiDbDomain( $domain ) && + !in_array( $wikiId, $wgLocalDatabases ) + ) { + self::$instances[$domain]->invalidWiki = true; } } - return self::$instances[$wiki]; + return self::$instances[$domain]; } /** @@ -104,7 +110,7 @@ class JobQueueGroup { public function get( $type ) { global $wgJobTypeConf; - $conf = [ 'wiki' => $this->wiki, 'type' => $type ]; + $conf = [ 'wiki' => $this->domain, 'type' => $type ]; if ( isset( $wgJobTypeConf[$type] ) ) { $conf = $conf + $wgJobTypeConf[$type]; } else { @@ -133,7 +139,7 @@ class JobQueueGroup { if ( $this->invalidWiki ) { // Do not enqueue job that cannot be run (T171371) - $e = new LogicException( "Domain '{$this->wiki}' is not recognized." ); + $e = new LogicException( "Domain '{$this->domain}' is not recognized." ); MWExceptionHandler::logException( $e ); return; } @@ -163,13 +169,13 @@ class JobQueueGroup { $cache = ObjectCache::getLocalClusterInstance(); $cache->set( - $cache->makeGlobalKey( 'jobqueue', $this->wiki, 'hasjobs', self::TYPE_ANY ), + $cache->makeGlobalKey( 'jobqueue', $this->domain, 'hasjobs', self::TYPE_ANY ), 'true', 15 ); if ( array_diff( array_keys( $jobsByType ), $wgJobTypesExcludedFromDefaultQueue ) ) { $cache->set( - $cache->makeGlobalKey( 'jobqueue', $this->wiki, 'hasjobs', self::TYPE_DEFAULT ), + $cache->makeGlobalKey( 'jobqueue', $this->domain, 'hasjobs', self::TYPE_DEFAULT ), 'true', 15 ); @@ -190,7 +196,7 @@ class JobQueueGroup { public function lazyPush( $jobs ) { if ( $this->invalidWiki ) { // Do not enqueue job that cannot be run (T171371) - throw new LogicException( "Domain '{$this->wiki}' is not recognized." ); + throw new LogicException( "Domain '{$this->domain}' is not recognized." ); } if ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ) { @@ -338,7 +344,7 @@ class JobQueueGroup { */ public function queuesHaveJobs( $type = self::TYPE_ANY ) { $cache = ObjectCache::getLocalClusterInstance(); - $key = $cache->makeGlobalKey( 'jobqueue', $this->wiki, 'hasjobs', $type ); + $key = $cache->makeGlobalKey( 'jobqueue', $this->domain, 'hasjobs', $type ); $value = $cache->get( $key ); if ( $value === false ) { @@ -407,7 +413,7 @@ class JobQueueGroup { $this->coalescedQueues = []; foreach ( $wgJobTypeConf as $type => $conf ) { $queue = JobQueue::factory( - [ 'wiki' => $this->wiki, 'type' => 'null' ] + $conf ); + [ 'wiki' => $this->domain, 'type' => 'null' ] + $conf ); $loc = $queue->getCoalesceLocationInternal(); if ( !isset( $this->coalescedQueues[$loc] ) ) { $this->coalescedQueues[$loc]['queue'] = $queue; @@ -433,22 +439,21 @@ class JobQueueGroup { */ private function getCachedConfigVar( $name ) { // @TODO: cleanup this whole method with a proper config system - if ( $this->wiki === wfWikiID() ) { + if ( WikiMap::isCurrentWikiDbDomain( $this->domain ) ) { return $GLOBALS[$name]; // common case } else { - $wiki = $this->wiki; + $wiki = WikiMap::getWikiIdFromDomain( $this->domain ); $cache = ObjectCache::getMainWANInstance(); $value = $cache->getWithSetCallback( - $cache->makeGlobalKey( 'jobqueue', 'configvalue', $wiki, $name ), + $cache->makeGlobalKey( 'jobqueue', 'configvalue', $this->domain, $name ), $cache::TTL_DAY + mt_rand( 0, $cache::TTL_DAY ), function () use ( $wiki, $name ) { global $wgConf; - + // @TODO: use the full domain ID here return [ 'v' => $wgConf->getConfig( $wiki, $name ) ]; }, [ 'pcTTL' => WANObjectCache::TTL_PROC_LONG ] ); - return $value['v']; } }