2016-09-14 11:34:17 +00:00
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* Generator of database load balancing objects.
|
|
|
|
|
*
|
|
|
|
|
* 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 Database
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use MediaWiki\Logger\LoggerFactory;
|
2016-09-29 03:59:11 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
2018-02-17 22:09:02 +00:00
|
|
|
use Wikimedia\Rdbms\LBFactory;
|
2017-02-06 22:32:49 +00:00
|
|
|
use Wikimedia\Rdbms\DatabaseDomain;
|
2016-09-14 11:34:17 +00:00
|
|
|
|
|
|
|
|
/**
|
2016-09-30 21:06:02 +00:00
|
|
|
* MediaWiki-specific class for generating database load balancers
|
2016-09-14 11:34:17 +00:00
|
|
|
* @ingroup Database
|
|
|
|
|
*/
|
2016-09-30 21:06:02 +00:00
|
|
|
abstract class MWLBFactory {
|
2018-04-05 16:13:08 +00:00
|
|
|
|
|
|
|
|
/** @var array Cache of already-logged deprecation messages */
|
|
|
|
|
private static $loggedDeprecations = [];
|
|
|
|
|
|
2016-09-14 11:34:17 +00:00
|
|
|
/**
|
2016-09-18 01:50:56 +00:00
|
|
|
* @param array $lbConf Config for LBFactory::__construct()
|
|
|
|
|
* @param Config $mainConfig Main config object from MediaWikiServices
|
2017-04-10 05:34:30 +00:00
|
|
|
* @param ConfiguredReadOnlyMode $readOnlyMode
|
2016-09-15 18:52:55 +00:00
|
|
|
* @return array
|
|
|
|
|
*/
|
2017-04-10 05:34:30 +00:00
|
|
|
public static function applyDefaultConfig( array $lbConf, Config $mainConfig,
|
|
|
|
|
ConfiguredReadOnlyMode $readOnlyMode
|
|
|
|
|
) {
|
2016-09-15 20:51:31 +00:00
|
|
|
global $wgCommandLineMode;
|
2016-09-15 09:21:21 +00:00
|
|
|
|
2016-11-17 21:59:20 +00:00
|
|
|
static $typesWithSchema = [ 'postgres', 'msssql' ];
|
|
|
|
|
|
2016-09-18 01:50:56 +00:00
|
|
|
$lbConf += [
|
|
|
|
|
'localDomain' => new DatabaseDomain(
|
|
|
|
|
$mainConfig->get( 'DBname' ),
|
2018-01-30 03:09:07 +00:00
|
|
|
$mainConfig->get( 'DBmwschema' ),
|
2016-09-18 01:50:56 +00:00
|
|
|
$mainConfig->get( 'DBprefix' )
|
|
|
|
|
),
|
2016-09-17 22:30:17 +00:00
|
|
|
'profiler' => Profiler::instance(),
|
2016-09-14 11:34:17 +00:00
|
|
|
'trxProfiler' => Profiler::instance()->getTransactionProfiler(),
|
|
|
|
|
'replLogger' => LoggerFactory::getInstance( 'DBReplication' ),
|
2016-09-16 20:57:56 +00:00
|
|
|
'queryLogger' => LoggerFactory::getInstance( 'DBQuery' ),
|
|
|
|
|
'connLogger' => LoggerFactory::getInstance( 'DBConnection' ),
|
2016-09-14 11:34:17 +00:00
|
|
|
'perfLogger' => LoggerFactory::getInstance( 'DBPerformance' ),
|
2016-09-15 18:52:55 +00:00
|
|
|
'errorLogger' => [ MWExceptionHandler::class, 'logException' ],
|
2018-04-05 16:13:08 +00:00
|
|
|
'deprecationLogger' => [ static::class, 'logDeprecation' ],
|
2016-09-15 18:52:55 +00:00
|
|
|
'cliMode' => $wgCommandLineMode,
|
2016-09-18 01:50:56 +00:00
|
|
|
'hostname' => wfHostname(),
|
2017-04-10 05:34:30 +00:00
|
|
|
'readOnlyReason' => $readOnlyMode->getReason(),
|
2018-06-12 21:49:52 +00:00
|
|
|
'defaultGroup' => $mainConfig->get( 'DBDefaultGroup' ),
|
2016-09-14 11:34:17 +00:00
|
|
|
];
|
2016-09-18 01:50:56 +00:00
|
|
|
|
2017-02-24 03:39:03 +00:00
|
|
|
// When making changes here, remember to also specify MediaWiki-specific options
|
|
|
|
|
// for Database classes in the relevant Installer subclass.
|
|
|
|
|
// Such as MysqlInstaller::openConnection and PostgresInstaller::openConnectionWithParams.
|
2018-01-13 00:02:09 +00:00
|
|
|
if ( $lbConf['class'] === Wikimedia\Rdbms\LBFactorySimple::class ) {
|
2016-09-18 01:50:56 +00:00
|
|
|
if ( isset( $lbConf['servers'] ) ) {
|
|
|
|
|
// Server array is already explicitly configured; leave alone
|
|
|
|
|
} elseif ( is_array( $mainConfig->get( 'DBservers' ) ) ) {
|
|
|
|
|
foreach ( $mainConfig->get( 'DBservers' ) as $i => $server ) {
|
|
|
|
|
if ( $server['type'] === 'sqlite' ) {
|
|
|
|
|
$server += [ 'dbDirectory' => $mainConfig->get( 'SQLiteDataDir' ) ];
|
2016-09-19 17:37:57 +00:00
|
|
|
} elseif ( $server['type'] === 'postgres' ) {
|
2016-11-10 05:35:57 +00:00
|
|
|
$server += [
|
|
|
|
|
'port' => $mainConfig->get( 'DBport' ),
|
|
|
|
|
// Work around the reserved word usage in MediaWiki schema
|
|
|
|
|
'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
|
|
|
|
|
];
|
2017-02-09 22:30:05 +00:00
|
|
|
} elseif ( $server['type'] === 'mssql' ) {
|
|
|
|
|
$server += [
|
|
|
|
|
'port' => $mainConfig->get( 'DBport' ),
|
|
|
|
|
'useWindowsAuth' => $mainConfig->get( 'DBWindowsAuthentication' )
|
|
|
|
|
];
|
2016-09-18 01:50:56 +00:00
|
|
|
}
|
2017-02-09 22:30:05 +00:00
|
|
|
|
2016-11-17 21:59:20 +00:00
|
|
|
if ( in_array( $server['type'], $typesWithSchema, true ) ) {
|
|
|
|
|
$server += [ 'schema' => $mainConfig->get( 'DBmwschema' ) ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$server += [
|
2016-09-18 01:50:56 +00:00
|
|
|
'tablePrefix' => $mainConfig->get( 'DBprefix' ),
|
|
|
|
|
'flags' => DBO_DEFAULT,
|
|
|
|
|
'sqlMode' => $mainConfig->get( 'SQLMode' ),
|
|
|
|
|
'utf8Mode' => $mainConfig->get( 'DBmysql5' )
|
|
|
|
|
];
|
2016-11-17 21:59:20 +00:00
|
|
|
|
|
|
|
|
$lbConf['servers'][$i] = $server;
|
2016-09-18 01:50:56 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$flags = DBO_DEFAULT;
|
|
|
|
|
$flags |= $mainConfig->get( 'DebugDumpSql' ) ? DBO_DEBUG : 0;
|
|
|
|
|
$flags |= $mainConfig->get( 'DBssl' ) ? DBO_SSL : 0;
|
|
|
|
|
$flags |= $mainConfig->get( 'DBcompress' ) ? DBO_COMPRESS : 0;
|
|
|
|
|
$server = [
|
|
|
|
|
'host' => $mainConfig->get( 'DBserver' ),
|
|
|
|
|
'user' => $mainConfig->get( 'DBuser' ),
|
|
|
|
|
'password' => $mainConfig->get( 'DBpassword' ),
|
|
|
|
|
'dbname' => $mainConfig->get( 'DBname' ),
|
|
|
|
|
'tablePrefix' => $mainConfig->get( 'DBprefix' ),
|
|
|
|
|
'type' => $mainConfig->get( 'DBtype' ),
|
|
|
|
|
'load' => 1,
|
|
|
|
|
'flags' => $flags,
|
|
|
|
|
'sqlMode' => $mainConfig->get( 'SQLMode' ),
|
|
|
|
|
'utf8Mode' => $mainConfig->get( 'DBmysql5' )
|
|
|
|
|
];
|
2016-11-17 21:59:20 +00:00
|
|
|
if ( in_array( $server['type'], $typesWithSchema, true ) ) {
|
|
|
|
|
$server += [ 'schema' => $mainConfig->get( 'DBmwschema' ) ];
|
|
|
|
|
}
|
2016-09-18 01:50:56 +00:00
|
|
|
if ( $server['type'] === 'sqlite' ) {
|
|
|
|
|
$server[ 'dbDirectory'] = $mainConfig->get( 'SQLiteDataDir' );
|
2016-09-19 17:37:57 +00:00
|
|
|
} elseif ( $server['type'] === 'postgres' ) {
|
|
|
|
|
$server['port'] = $mainConfig->get( 'DBport' );
|
2016-11-10 05:35:57 +00:00
|
|
|
// Work around the reserved word usage in MediaWiki schema
|
|
|
|
|
$server['keywordTableMap'] = [ 'user' => 'mwuser', 'text' => 'pagecontent' ];
|
2017-02-09 22:30:05 +00:00
|
|
|
} elseif ( $server['type'] === 'mssql' ) {
|
|
|
|
|
$server['port'] = $mainConfig->get( 'DBport' );
|
|
|
|
|
$server['useWindowsAuth'] = $mainConfig->get( 'DBWindowsAuthentication' );
|
2016-09-18 01:50:56 +00:00
|
|
|
}
|
|
|
|
|
$lbConf['servers'] = [ $server ];
|
|
|
|
|
}
|
2016-09-19 22:13:43 +00:00
|
|
|
if ( !isset( $lbConf['externalClusters'] ) ) {
|
|
|
|
|
$lbConf['externalClusters'] = $mainConfig->get( 'ExternalServers' );
|
2016-09-18 01:50:56 +00:00
|
|
|
}
|
2018-01-13 00:02:09 +00:00
|
|
|
} elseif ( $lbConf['class'] === Wikimedia\Rdbms\LBFactoryMulti::class ) {
|
2016-09-18 01:50:56 +00:00
|
|
|
if ( isset( $lbConf['serverTemplate'] ) ) {
|
2016-11-17 21:59:20 +00:00
|
|
|
if ( in_array( $lbConf['serverTemplate']['type'], $typesWithSchema, true ) ) {
|
|
|
|
|
$lbConf['serverTemplate']['schema'] = $mainConfig->get( 'DBmwschema' );
|
|
|
|
|
}
|
2016-09-18 01:50:56 +00:00
|
|
|
$lbConf['serverTemplate']['sqlMode'] = $mainConfig->get( 'SQLMode' );
|
|
|
|
|
$lbConf['serverTemplate']['utf8Mode'] = $mainConfig->get( 'DBmysql5' );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-17 03:13:35 +00:00
|
|
|
$services = MediaWikiServices::getInstance();
|
|
|
|
|
|
2016-09-14 11:34:17 +00:00
|
|
|
// Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
|
2017-08-17 03:13:35 +00:00
|
|
|
$sCache = $services->getLocalServerObjectCache();
|
2016-09-14 11:34:17 +00:00
|
|
|
if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
|
2016-09-18 01:50:56 +00:00
|
|
|
$lbConf['srvCache'] = $sCache;
|
2016-09-14 11:34:17 +00:00
|
|
|
}
|
2017-08-17 03:13:35 +00:00
|
|
|
$mStash = $services->getMainObjectStash();
|
|
|
|
|
if ( $mStash->getQoS( $mStash::ATTR_EMULATION ) > $mStash::QOS_EMULATION_SQL ) {
|
|
|
|
|
$lbConf['memStash'] = $mStash;
|
2016-09-14 11:34:17 +00:00
|
|
|
}
|
2017-08-17 03:13:35 +00:00
|
|
|
$wCache = $services->getMainWANObjectCache();
|
2016-09-14 11:34:17 +00:00
|
|
|
if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
|
2016-09-18 01:50:56 +00:00
|
|
|
$lbConf['wanCache'] = $wCache;
|
2016-09-16 03:33:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-18 01:50:56 +00:00
|
|
|
return $lbConf;
|
2016-09-14 11:34:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the LBFactory class to use and the load balancer configuration.
|
|
|
|
|
*
|
|
|
|
|
* @todo instead of this, use a ServiceContainer for managing the different implementations.
|
|
|
|
|
*
|
|
|
|
|
* @param array $config (e.g. $wgLBFactoryConf)
|
|
|
|
|
* @return string Class name
|
|
|
|
|
*/
|
|
|
|
|
public static function getLBFactoryClass( array $config ) {
|
|
|
|
|
// For configuration backward compatibility after removing
|
|
|
|
|
// underscores from class names in MediaWiki 1.23.
|
|
|
|
|
$bcClasses = [
|
|
|
|
|
'LBFactory_Simple' => 'LBFactorySimple',
|
|
|
|
|
'LBFactory_Single' => 'LBFactorySingle',
|
|
|
|
|
'LBFactory_Multi' => 'LBFactoryMulti'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$class = $config['class'];
|
|
|
|
|
|
|
|
|
|
if ( isset( $bcClasses[$class] ) ) {
|
|
|
|
|
$class = $bcClasses[$class];
|
|
|
|
|
wfDeprecated(
|
|
|
|
|
'$wgLBFactoryConf must be updated. See RELEASE-NOTES for details',
|
|
|
|
|
'1.23'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-26 18:27:37 +00:00
|
|
|
// For configuration backward compatibility after moving classes to namespaces (1.29)
|
|
|
|
|
$compat = [
|
|
|
|
|
'LBFactorySingle' => Wikimedia\Rdbms\LBFactorySingle::class,
|
|
|
|
|
'LBFactorySimple' => Wikimedia\Rdbms\LBFactorySimple::class,
|
|
|
|
|
'LBFactoryMulti' => Wikimedia\Rdbms\LBFactoryMulti::class
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if ( isset( $compat[$class] ) ) {
|
|
|
|
|
$class = $compat[$class];
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-14 11:34:17 +00:00
|
|
|
return $class;
|
|
|
|
|
}
|
2018-02-17 22:09:02 +00:00
|
|
|
|
2018-04-20 20:45:49 +00:00
|
|
|
public static function setSchemaAliases( LBFactory $lbFactory, Config $config ) {
|
|
|
|
|
if ( $config->get( 'DBtype' ) === 'mysql' ) {
|
2018-02-17 22:09:02 +00:00
|
|
|
/**
|
|
|
|
|
* When SQLite indexes were introduced in r45764, it was noted that
|
|
|
|
|
* SQLite requires index names to be unique within the whole database,
|
|
|
|
|
* not just within a schema. As discussed in CR r45819, to avoid the
|
|
|
|
|
* need for a schema change on existing installations, the indexes
|
|
|
|
|
* were implicitly mapped from the new names to the old names.
|
|
|
|
|
*
|
|
|
|
|
* This mapping can be removed if DB patches are introduced to alter
|
|
|
|
|
* the relevant tables in existing installations. Note that because
|
|
|
|
|
* this index mapping applies to table creation, even new installations
|
|
|
|
|
* of MySQL have the old names (except for installations created during
|
|
|
|
|
* a period where this mapping was inappropriately removed, see
|
|
|
|
|
* T154872).
|
|
|
|
|
*/
|
|
|
|
|
$lbFactory->setIndexAliases( [
|
|
|
|
|
'ar_usertext_timestamp' => 'usertext_timestamp',
|
|
|
|
|
'un_user_id' => 'user_id',
|
|
|
|
|
'un_user_ip' => 'user_ip',
|
|
|
|
|
] );
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-05 16:13:08 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Log a database deprecation warning
|
|
|
|
|
* @param string $msg Deprecation message
|
|
|
|
|
*/
|
|
|
|
|
public static function logDeprecation( $msg ) {
|
|
|
|
|
global $wgDevelopmentWarnings;
|
|
|
|
|
|
|
|
|
|
if ( isset( self::$loggedDeprecations[$msg] ) ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
self::$loggedDeprecations[$msg] = true;
|
|
|
|
|
|
|
|
|
|
if ( $wgDevelopmentWarnings ) {
|
|
|
|
|
trigger_error( $msg, E_USER_DEPRECATED );
|
|
|
|
|
}
|
|
|
|
|
wfDebugLog( 'deprecated', $msg, 'private' );
|
|
|
|
|
}
|
2016-09-14 11:34:17 +00:00
|
|
|
}
|