* getQueueTypes() now gets the config of the target wiki.
Previously, for WMF, if an extension using jobs was not
on aawiki, those job queues would not be seen by nextJobDB.
* Also fixed nextJobDB.php so that it no longer only considers
jobs types known to aawiki for picking a DB for default jobs.
* Note that $wgJobTypesExcludedFromDefaultQueue should be global.
* This adds a SiteConfiguration::getConfig() function, which calls
a new getConfiguration.php script.
Change-Id: I7e6904ead17efa407291f423a2b18e3c866d55fd
*/
public $siteParamsCallback = null;
+ /**
+ * Configuration cache for getConfig()
+ * @var array
+ */
+ protected $cfgCache = array();
+
/**
* Retrieves a configuration setting for a given wiki.
* @param $settingName String ID of the setting name to retrieve
return array( $site, $lang );
}
+ /**
+ * Get the resolved (post-setup) configuration of a potentially foreign wiki.
+ * For foreign wikis, this is expensive, and only works if maintenance
+ * scripts are setup to handle the --wiki parameter such as in wiki farms.
+ *
+ * @param string $wiki
+ * @param array|string $settings A setting name or array of setting names
+ * @return Array|mixed Array if $settings is an array, otherwise the value
+ * @throws MWException
+ * @since 1.21
+ */
+ public function getConfig( $wiki, $settings ) {
+ global $IP;
+
+ $multi = is_array( $settings );
+ $settings = (array)$settings;
+ if ( $wiki === wfWikiID() ) { // $wiki is this wiki
+ $res = array();
+ foreach ( $settings as $name ) {
+ if ( !preg_match( '/^wg[A-Z]/', $name ) ) {
+ throw new MWException( "Variable '$name' does start with 'wg'." );
+ } elseif ( !isset( $GLOBALS[$name] ) ) {
+ throw new MWException( "Variable '$name' is not set." );
+ }
+ $res[$name] = $GLOBALS[$name];
+ }
+ } else { // $wiki is a foreign wiki
+ if ( isset( $this->cfgCache[$wiki] ) ) {
+ $res = array_intersect_key( $this->cfgCache[$wiki], array_flip( $settings ) );
+ if ( count( $res ) == count( $settings ) ) {
+ return $res; // cache hit
+ }
+ } elseif ( !in_array( $wiki, $this->wikis ) ) {
+ throw new MWException( "No such wiki '$wiki'." );
+ } else {
+ $this->cfgCache[$wiki] = array();
+ }
+ $retVal = 1;
+ $cmd = wfShellWikiCmd(
+ "$IP/maintenance/getConfiguration.php",
+ array(
+ '--wiki', $wiki,
+ '--settings', implode( ' ', $settings ),
+ '--format', 'PHP'
+ )
+ );
+ // ulimit5.sh breaks this call
+ $data = trim( wfShellExec( $cmd, $retVal, array(), array( 'memory' => 0 ) ) );
+ if ( $retVal != 0 || !strlen( $data ) ) {
+ throw new MWException( "Failed to run getConfiguration.php." );
+ }
+ $res = unserialize( $data );
+ if ( !is_array( $res ) ) {
+ throw new MWException( "Failed to unserialize configuration array." );
+ }
+ $this->cfgCache[$wiki] = $this->cfgCache[$wiki] + $res;
+ }
+
+ return $multi ? $res : current( $res );
+ }
+
/**
* Returns true if the given vhost is handled locally.
* @param $vhost String
* @return array List of strings
*/
public function getQueueTypes() {
- global $wgJobClasses;
-
- return array_keys( $wgJobClasses );
+ return array_keys( $this->getCachedConfigVar( 'wgJobClasses' ) );
}
/**
return $count;
}
+
+ private function getCachedConfigVar( $name ) {
+ global $wgConf, $wgMemc;
+
+ if ( $this->wiki === wfWikiID() ) {
+ return $GLOBALS[$name]; // common case
+ } else {
+ list( $db, $prefix ) = wfSplitWikiID( $this->wiki );
+ $key = wfForeignMemcKey( $db, $prefix, 'configvalue', $name );
+ $value = $wgMemc->get( $key ); // ('v' => ...) or false
+ if ( is_array( $value ) ) {
+ return $value['v'];
+ } else {
+ $value = $wgConf->getConfig( $this->wiki, $name );
+ $wgMemc->set( $key, array( 'v' => $value ), 86400 + mt_rand( 0, 86400 ) );
+ return $value;
+ }
+ }
+ }
}
--- /dev/null
+<?php
+/**
+ * Print serialized output of MediaWiki config vars
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ * @author Tim Starling
+ * @author Antoine Musso
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Print serialized output of MediaWiki config vars
+ *
+ * @ingroup Maintenance
+ */
+class GetConfiguration extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Get serialized MediaWiki site configuration";
+ $this->addOption( 'settings', 'Space-separated list of wg* variables', true, true );
+ $this->addOption( 'format', 'PHP or JSON', true, true );
+ $this->addOption( 'wiki', 'Wiki ID', true, true );
+ }
+
+ public function execute() {
+ $res = array();
+ foreach ( explode( ' ', $this->getOption( 'settings' ) ) as $name ) {
+ if ( !preg_match( '/^wg[A-Z]/', $name ) ) {
+ throw new MWException( "Variable '$name' does start with 'wg'." );
+ } elseif ( !isset( $GLOBALS[$name] ) ) {
+ throw new MWException( "Variable '$name' is not set." );
+ } elseif ( !$this->isAllowedVariable( $GLOBALS[$name] ) ) {
+ throw new MWException( "Variable '$name' includes non-array, non-scalar, items." );
+ }
+ $res[$name] = $GLOBALS[$name];
+ }
+
+ $out = null;
+ switch( $this->getOption( 'format' ) ) {
+ case 'PHP':
+ $out = serialize( $res );
+ break;
+ case 'JSON':
+ $out = FormatJson::encode( $res );
+ break;
+ default:
+ throw new MWException( "Invalid serialization format given." );
+ }
+ if ( !is_string( $out ) ) {
+ throw new MWException( "Failed to serialize the requested settings." );
+ }
+
+ $this->output( $out . "\n" );
+ }
+
+ private function isAllowedVariable( $value ) {
+ if ( is_array( $value ) ) {
+ foreach ( $value as $k => $v ) {
+ if ( !$this->isAllowedVariable( $v ) ) {
+ return false;
+ }
+ }
+ return true;
+ } elseif ( is_scalar( $value ) ) {
+ return true;
+ }
+ return false;
+ }
+}
+
+$maintClass = "GetConfiguration";
+require_once( RUN_MAINTENANCE_IF_MAIN );
}
public function execute() {
- global $wgMemc;
+ global $wgMemc, $wgJobTypesExcludedFromDefaultQueue;
$type = false; // job type required/picked
+
if ( $this->hasOption( 'types' ) ) {
$types = explode( ' ', $this->getOption( 'types' ) );
} elseif ( $this->hasOption( 'type' ) ) {
$types = array( $this->getOption( 'type' ) );
} else {
- $types = JobQueueGroup::singleton()->getDefaultQueueTypes();
+ $types = false;
}
// Handle any required periodic queue maintenance
// Flatten the tree of candidates into a flat list so that a random
// item can be selected, weighing each queue (type/db tuple) equally.
foreach ( $pendingDBs as $type => $dbs ) {
- if ( in_array( $type, $types ) ) {
+ if (
+ ( is_array( $types ) && in_array( $type, $types ) ) ||
+ ( $types === false && !in_array( $type, $wgJobTypesExcludedFromDefaultQueue ) )
+ ) {
foreach ( $dbs as $db ) {
$candidates[] = array( $type, $db );
}