Aaron Schulz has uploaded a new change for review.
https://gerrit.wikimedia.org/r/310924
Change subject: Move LBFactorySimple to /libs/rdbms
......................................................................
Move LBFactorySimple to /libs/rdbms
* Refactored LBFactory a bit to make this possible.
* Move newChronologyProtector() up to LBFactory and
make a lazy-loading method instead.
* Move appendPreShutdownTimeAsQuery() up to LBFactory.
* Inject the web request values for LBFactory from Setup.php.
* Remove unused laggedSlaveUsed() method.
Change-Id: Ie8a38a6f4d6359680eb6a5be24a34e30b9816479
---
M autoload.php
M includes/ServiceWiring.php
M includes/Setup.php
M includes/db/loadbalancer/LBFactoryMW.php
M includes/db/loadbalancer/LBFactoryMulti.php
M includes/libs/rdbms/lbfactory/LBFactory.php
R includes/libs/rdbms/lbfactory/LBFactorySimple.php
7 files changed, 146 insertions(+), 135 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/24/310924/1
diff --git a/autoload.php b/autoload.php
index 96c8190..15d1297 100644
--- a/autoload.php
+++ b/autoload.php
@@ -656,7 +656,7 @@
'LBFactory' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactory.php',
'LBFactoryMW' => __DIR__ . '/includes/db/loadbalancer/LBFactoryMW.php',
'LBFactoryMulti' => __DIR__ .
'/includes/db/loadbalancer/LBFactoryMulti.php',
- 'LBFactorySimple' => __DIR__ .
'/includes/db/loadbalancer/LBFactorySimple.php',
+ 'LBFactorySimple' => __DIR__ .
'/includes/libs/rdbms/lbfactory/LBFactorySimple.php',
'LBFactorySingle' => __DIR__ .
'/includes/db/loadbalancer/LBFactorySingle.php',
'LCStore' => __DIR__ . '/includes/cache/localisation/LCStore.php',
'LCStoreCDB' => __DIR__ . '/includes/cache/localisation/LCStoreCDB.php',
diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php
index 4ab412e..f054533 100644
--- a/includes/ServiceWiring.php
+++ b/includes/ServiceWiring.php
@@ -43,15 +43,53 @@
return [
'DBLoadBalancerFactory' => function( MediaWikiServices $services ) {
- $config = $services->getMainConfig()->get( 'LBFactoryConf' );
+ $mainConfig = $services->getMainConfig();
- $class = LBFactoryMW::getLBFactoryClass( $config );
- if ( !isset( $config['readOnlyReason'] ) ) {
+ $lbConf = $mainConfig->get( 'LBFactoryConf' );
+ if ( !isset( $lbConf['readOnlyReason'] ) ) {
// TODO: replace the global
wfConfiguredReadOnlyReason() with a service.
- $config['readOnlyReason'] =
wfConfiguredReadOnlyReason();
+ $lbConf['readOnlyReason'] =
wfConfiguredReadOnlyReason();
}
- return new $class( $config );
+ $class = LBFactoryMW::getLBFactoryClass( $lbConf );
+ if ( $class === 'LBFactorySimple' ) {
+ if ( is_array( $mainConfig->get( 'DBservers' ) ) ) {
+ foreach ( $mainConfig->get( 'DBservers' ) as $i
=> $server ) {
+ $lbConf['servers'][$i] = $server + [
+ 'schema' => $mainConfig->get(
'DBmwschema' ),
+ 'tablePrefix' =>
$mainConfig->get( 'DBprefix' ),
+ 'flags' => DBO_DEFAULT,
+ ];
+ if ( $i == 0 ) {
+
$lbConf['servers'][$i]['master'] = true;
+ } else {
+
$lbConf['servers'][$i]['replica'] = true;
+ }
+ }
+ } 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;
+ $lbConf['servers'] = [
+ [
+ 'host' => $mainConfig->get(
'DBserver' ),
+ 'user' => $mainConfig->get(
'DBuser' ),
+ 'password' => $mainConfig->get(
'DBpassword' ),
+ 'dbname' => $mainConfig->get(
'DBname' ),
+ 'schema' => $mainConfig->get(
'DBmwschema' ),
+ 'tablePrefix' =>
$mainConfig->get( 'DBprefix' ),
+ 'type' => $mainConfig->get(
'DBtype' ),
+ 'load' => 1,
+ 'flags' => $flags,
+ 'master' => true
+ ]
+ ];
+ }
+ $lbConf['externalServers'] = $mainConfig->get(
'ExternalServers' );
+ }
+
+ return new $class( $lbConf );
},
'DBLoadBalancer' => function( MediaWikiServices $services ) {
diff --git a/includes/Setup.php b/includes/Setup.php
index ddf5b89..cfcb42e 100644
--- a/includes/Setup.php
+++ b/includes/Setup.php
@@ -504,8 +504,9 @@
// Reset the global service locator, so any services that have already been
created will be
// re-created while taking into account any custom settings and extensions.
MediaWikiServices::resetGlobalInstance( new GlobalVarConfig(), 'quick' );
-// Apply $wgSharedDB table aliases for the local LB (all non-foreign DB
connections)
+
if ( $wgSharedDB && $wgSharedTables ) {
+ // Apply $wgSharedDB table aliases for the local LB (all non-foreign DB
connections)
MediaWikiServices::getInstance()->getDBLoadBalancer()->setTableAliases(
array_fill_keys(
$wgSharedTables,
@@ -516,6 +517,12 @@
]
)
);
+ // Set user IP/agent information for causal consistency purposes
+
MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->setRequestInfo( [
+ 'IPAddress' => $wgRequest->getIP(),
+ 'UserAgent' => $wgRequest->getHeader( 'User-Agent' ),
+ 'ChronologyProtection' => $wgRequest->getHeader(
'ChronologyProtection' )
+ ] );
}
// Define a constant that indicates that the bootstrapping of the service
locator
diff --git a/includes/db/loadbalancer/LBFactoryMW.php
b/includes/db/loadbalancer/LBFactoryMW.php
index 87fd81b..3523a93 100644
--- a/includes/db/loadbalancer/LBFactoryMW.php
+++ b/includes/db/loadbalancer/LBFactoryMW.php
@@ -93,57 +93,4 @@
return $class;
}
-
- /**
- * @return bool
- * @since 1.27
- * @deprecated Since 1.28; use laggedReplicaUsed()
- */
- public function laggedSlaveUsed() {
- return $this->laggedReplicaUsed();
- }
-
- protected function newChronologyProtector() {
- $request = RequestContext::getMain()->getRequest();
- $chronProt = new ChronologyProtector(
- ObjectCache::getMainStashInstance(),
- [
- 'ip' => $request->getIP(),
- 'agent' => $request->getHeader( 'User-Agent' ),
- ],
- $request->getFloat( 'cpPosTime', $request->getCookie(
'cpPosTime', '' ) )
- );
- if ( PHP_SAPI === 'cli' ) {
- $chronProt->setEnabled( false );
- } elseif ( $request->getHeader( 'ChronologyProtection' ) ===
'false' ) {
- // Request opted out of using position wait logic. This
is useful for requests
- // done by the job queue or background ETL that do not
have a meaningful session.
- $chronProt->setWaitEnabled( false );
- }
-
- return $chronProt;
- }
-
- /**
- * Append ?cpPosTime parameter to a URL for ChronologyProtector
purposes if needed
- *
- * Note that unlike cookies, this works accross domains
- *
- * @param string $url
- * @param float $time UNIX timestamp just before shutdown() was called
- * @return string
- * @since 1.28
- */
- public function appendPreShutdownTimeAsQuery( $url, $time ) {
- $usedCluster = 0;
- $this->forEachLB( function ( LoadBalancer $lb ) use (
&$usedCluster ) {
- $usedCluster |= ( $lb->getServerCount() > 1 );
- } );
-
- if ( !$usedCluster ) {
- return $url; // no master/replica clusters touched
- }
-
- return wfAppendQuery( $url, [ 'cpPosTime' => $time ] );
- }
}
diff --git a/includes/db/loadbalancer/LBFactoryMulti.php
b/includes/db/loadbalancer/LBFactoryMulti.php
index 95bc8f4..1f7f528 100644
--- a/includes/db/loadbalancer/LBFactoryMulti.php
+++ b/includes/db/loadbalancer/LBFactoryMulti.php
@@ -254,7 +254,7 @@
$section = $this->getSectionForWiki( $wiki );
if ( !isset( $this->mainLBs[$section] ) ) {
$lb = $this->newMainLB( $wiki );
- $this->chronProt->initLB( $lb );
+ $this->getChronologyProtector()->initLB( $lb );
$this->mainLBs[$section] = $lb;
}
@@ -295,7 +295,7 @@
public function getExternalLB( $cluster, $wiki = false ) {
if ( !isset( $this->extLBs[$cluster] ) ) {
$this->extLBs[$cluster] = $this->newExternalLB(
$cluster, $wiki );
- $this->chronProt->initLB( $this->extLBs[$cluster] );
+ $this->getChronologyProtector()->initLB(
$this->extLBs[$cluster] );
}
return $this->extLBs[$cluster];
diff --git a/includes/libs/rdbms/lbfactory/LBFactory.php
b/includes/libs/rdbms/lbfactory/LBFactory.php
index feae4bd..fe520d5 100644
--- a/includes/libs/rdbms/lbfactory/LBFactory.php
+++ b/includes/libs/rdbms/lbfactory/LBFactory.php
@@ -49,10 +49,13 @@
/** @var WANObjectCache */
protected $wanCache;
- /** @var string Local domain */
- protected $domain;
/** @var string Local hostname of the app server */
protected $hostname;
+ /** @var array Web request information about the client */
+ protected $requestInfo;
+
+ /** @var string Local domain */
+ protected $domain;
/** @var mixed */
protected $ticket;
/** @var string|bool String if a requested DBO_TRX transaction round is
active */
@@ -99,10 +102,16 @@
$this->chronProt = isset( $conf['chronProt'] )
? $conf['chronProt']
- : $this->newChronologyProtector();
+ : null;
$this->trxProfiler = isset( $conf['trxProfiler'] )
? $conf['trxProfiler']
: new TransactionProfiler();
+
+ $this->requestInfo = [
+ 'IPAddress' => isset( $_SERVER[ 'REMOTE_ADDR' ] ) ?
$_SERVER[ 'REMOTE_ADDR' ] : '',
+ 'UserAgent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ?
$_SERVER['HTTP_USER_AGENT'] : '',
+ 'ChronologyProtection' => 'true'
+ ];
$this->ticket = mt_rand();
}
@@ -527,7 +536,7 @@
* @since 1.28
*/
public function getChronologyProtectorTouched( $dbName ) {
- return $this->chronProt->getTouched( $dbName );
+ return $this->getChronologyProtector()->getTouched( $dbName );
}
/**
@@ -538,27 +547,38 @@
* @since 1.27
*/
public function disableChronologyProtection() {
- $this->chronProt->setEnabled( false );
+ $this->getChronologyProtector()->setEnabled( false );
}
/**
* @return ChronologyProtector
*/
- protected function newChronologyProtector() {
- $chronProt = new ChronologyProtector(
+ protected function getChronologyProtector() {
+ if ( $this->chronProt ) {
+ return $this->chronProt;
+ }
+
+ $this->chronProt = new ChronologyProtector(
$this->memCache,
[
- 'ip' => isset( $_SERVER[ 'REMOTE_ADDR' ] ) ?
$_SERVER[ 'REMOTE_ADDR' ] : '',
- 'agent' => isset( $_SERVER['HTTP_USER_AGENT'] )
? $_SERVER['HTTP_USER_AGENT'] : ''
+ 'ip' => $this->requestInfo['IPAddress'],
+ 'agent' => $this->requestInfo['UserAgent'],
],
isset( $_GET['cpPosTime'] ) ? $_GET['cpPosTime'] : null
);
- $chronProt->setLogger( $this->replLogger );
+ $this->chronProt->setLogger( $this->replLogger );
if ( PHP_SAPI === 'cli' ) {
- $chronProt->setEnabled( false );
+ $this->chronProt->setEnabled( false );
+ } elseif ( $this->requestInfo['ChronologyProtection'] ===
'false' ) {
+ // Request opted out of using position wait logic. This
is useful for requests
+ // done by the job queue or background ETL that do not
have a meaningful session.
+ $this->chronProt->setWaitEnabled( false );
}
- return $chronProt;
+ $this->replLogger->debug( __METHOD__ . ': using request info ' .
+ json_encode( $this->requestInfo, JSON_PRETTY_PRINT ) );
+
+ return $this->chronProt;
}
/**
@@ -641,4 +661,38 @@
public function closeAll() {
$this->forEachLBCallMethod( 'closeAll', [] );
}
+
+ /**
+ * Append ?cpPosTime parameter to a URL for ChronologyProtector
purposes if needed
+ *
+ * Note that unlike cookies, this works accross domains
+ *
+ * @param string $url
+ * @param float $time UNIX timestamp just before shutdown() was called
+ * @return string
+ * @since 1.28
+ */
+ public function appendPreShutdownTimeAsQuery( $url, $time ) {
+ $usedCluster = 0;
+ $this->forEachLB( function ( ILoadBalancer $lb ) use (
&$usedCluster ) {
+ $usedCluster |= ( $lb->getServerCount() > 1 );
+ } );
+
+ if ( !$usedCluster ) {
+ return $url; // no master/replica clusters touched
+ }
+
+ return strpos( $url, '?' ) === false ? "$url?cpPosTime=$time" :
"$url&cpPosTime=$time";
+ }
+
+ /**
+ * @param array $info Map of fields, including:
+ * - IPAddress : IP address
+ * - UserAgent : User-Agent HTTP header
+ * - ChronologyProtection : cookie/header value specifying
ChronologyProtector usage
+ * @since 1.28
+ */
+ public function setRequestInfo( array $info ) {
+ $this->requestInfo = $info + $this->requestInfo;
+ }
}
diff --git a/includes/db/loadbalancer/LBFactorySimple.php
b/includes/libs/rdbms/lbfactory/LBFactorySimple.php
similarity index 60%
rename from includes/db/loadbalancer/LBFactorySimple.php
rename to includes/libs/rdbms/lbfactory/LBFactorySimple.php
index 09533eb..40579ab 100644
--- a/includes/db/loadbalancer/LBFactorySimple.php
+++ b/includes/libs/rdbms/lbfactory/LBFactorySimple.php
@@ -30,78 +30,44 @@
/** @var LoadBalancer[] */
private $extLBs = [];
+ /** @var array[] Map of (server index => server config) */
+ private $servers = [];
+ /** @var array[] Map of (cluster => (server index => server config)) */
+ private $externalClusters = [];
+
/** @var string */
private $loadMonitorClass;
public function __construct( array $conf ) {
parent::__construct( $conf );
+ $this->servers = isset( $conf['servers'] )
+ ? $conf['servers']
+ : [];
+ $this->externalClusters = isset( $conf['externalClusters'] )
+ ? $conf['externalClusters']
+ : [];
$this->loadMonitorClass = isset( $conf['loadMonitorClass'] )
? $conf['loadMonitorClass']
: null;
}
/**
- * @param bool|string $wiki
+ * @param bool|string $domain
* @return LoadBalancer
*/
- public function newMainLB( $wiki = false ) {
- global $wgDBservers, $wgDBprefix, $wgDBmwschema;
-
- if ( is_array( $wgDBservers ) ) {
- $servers = $wgDBservers;
- foreach ( $servers as $i => &$server ) {
- if ( $i == 0 ) {
- $server['master'] = true;
- } else {
- $server['replica'] = true;
- }
- $server += [
- 'schema' => $wgDBmwschema,
- 'tablePrefix' => $wgDBprefix,
- 'flags' => DBO_DEFAULT
- ];
- }
- } else {
- global $wgDBserver, $wgDBuser, $wgDBpassword,
$wgDBname, $wgDBtype, $wgDebugDumpSql;
- global $wgDBssl, $wgDBcompress;
-
- $flags = DBO_DEFAULT;
- if ( $wgDebugDumpSql ) {
- $flags |= DBO_DEBUG;
- }
- if ( $wgDBssl ) {
- $flags |= DBO_SSL;
- }
- if ( $wgDBcompress ) {
- $flags |= DBO_COMPRESS;
- }
-
- $servers = [ [
- 'host' => $wgDBserver,
- 'user' => $wgDBuser,
- 'password' => $wgDBpassword,
- 'dbname' => $wgDBname,
- 'schema' => $wgDBmwschema,
- 'tablePrefix' => $wgDBprefix,
- 'type' => $wgDBtype,
- 'load' => 1,
- 'flags' => $flags,
- 'master' => true
- ] ];
- }
-
- return $this->newLoadBalancer( $servers );
+ public function newMainLB( $domain = false ) {
+ return $this->newLoadBalancer( $this->servers );
}
/**
- * @param bool|string $wiki
+ * @param bool|string $domain
* @return LoadBalancer
*/
- public function getMainLB( $wiki = false ) {
+ public function getMainLB( $domain = false ) {
if ( !isset( $this->mainLB ) ) {
- $this->mainLB = $this->newMainLB( $wiki );
- $this->chronProt->initLB( $this->mainLB );
+ $this->mainLB = $this->newMainLB( $domain );
+ $this->getChronologyProtector()->initLB( $this->mainLB
);
}
return $this->mainLB;
@@ -109,28 +75,27 @@
/**
* @param string $cluster
- * @param bool|string $wiki
+ * @param bool|string $domain
* @return LoadBalancer
* @throws InvalidArgumentException
*/
- protected function newExternalLB( $cluster, $wiki = false ) {
- global $wgExternalServers;
- if ( !isset( $wgExternalServers[$cluster] ) ) {
+ protected function newExternalLB( $cluster, $domain = false ) {
+ if ( !isset( $this->externalClusters[$cluster] ) ) {
throw new InvalidArgumentException( __METHOD__ . ":
Unknown cluster \"$cluster\"" );
}
- return $this->newLoadBalancer( $wgExternalServers[$cluster] );
+ return $this->newLoadBalancer(
$this->externalClusters[$cluster] );
}
/**
* @param string $cluster
- * @param bool|string $wiki
+ * @param bool|string $domain
* @return array
*/
- public function getExternalLB( $cluster, $wiki = false ) {
+ public function getExternalLB( $cluster, $domain = false ) {
if ( !isset( $this->extLBs[$cluster] ) ) {
- $this->extLBs[$cluster] = $this->newExternalLB(
$cluster, $wiki );
- $this->chronProt->initLB( $this->extLBs[$cluster] );
+ $this->extLBs[$cluster] = $this->newExternalLB(
$cluster, $domain );
+ $this->getChronologyProtector()->initLB(
$this->extLBs[$cluster] );
}
return $this->extLBs[$cluster];
--
To view, visit https://gerrit.wikimedia.org/r/310924
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie8a38a6f4d6359680eb6a5be24a34e30b9816479
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits