2004-02-18 02:15:00 +00:00
|
|
|
<?php
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
/**
|
2012-04-26 08:47:10 +00:00
|
|
|
* Database load balancing.
|
|
|
|
|
*
|
|
|
|
|
* 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
|
2010-08-08 11:55:47 +00:00
|
|
|
*
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @file
|
|
|
|
|
* @ingroup Database
|
|
|
|
|
*/
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Database load balancing object
|
2004-09-03 23:00:01 +00:00
|
|
|
*
|
2004-09-02 23:28:24 +00:00
|
|
|
* @todo document
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @ingroup Database
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2004-01-25 13:27:53 +00:00
|
|
|
class LoadBalancer {
|
2011-04-18 23:12:58 +00:00
|
|
|
private $mServers, $mConns, $mLoads, $mGroupLoads;
|
|
|
|
|
private $mErrorConnection;
|
|
|
|
|
private $mReadIndex, $mAllowLagged;
|
|
|
|
|
private $mWaitForPos, $mWaitTimeout;
|
|
|
|
|
private $mLaggedSlaveMode, $mLastError = 'Unknown error';
|
|
|
|
|
private $mParentInfo, $mLagTimes;
|
|
|
|
|
private $mLoadMonitorClass, $mLoadMonitor;
|
2004-01-25 13:27:53 +00:00
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
/**
|
2010-03-11 20:59:25 +00:00
|
|
|
* @param $params Array with keys:
|
2010-10-05 15:10:14 +00:00
|
|
|
* servers Required. Array of server info structures.
|
|
|
|
|
* masterWaitTimeout Replication lag wait timeout
|
|
|
|
|
* loadMonitor Name of a class used to fetch server lag and load.
|
2008-07-07 03:31:00 +00:00
|
|
|
*/
|
2011-05-19 00:03:31 +00:00
|
|
|
function __construct( $params ) {
|
2008-07-07 03:31:00 +00:00
|
|
|
if ( !isset( $params['servers'] ) ) {
|
|
|
|
|
throw new MWException( __CLASS__.': missing servers parameter' );
|
|
|
|
|
}
|
|
|
|
|
$this->mServers = $params['servers'];
|
|
|
|
|
|
|
|
|
|
if ( isset( $params['waitTimeout'] ) ) {
|
|
|
|
|
$this->mWaitTimeout = $params['waitTimeout'];
|
|
|
|
|
} else {
|
|
|
|
|
$this->mWaitTimeout = 10;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-25 13:27:53 +00:00
|
|
|
$this->mReadIndex = -1;
|
|
|
|
|
$this->mWriteIndex = -1;
|
2008-03-30 09:48:15 +00:00
|
|
|
$this->mConns = array(
|
|
|
|
|
'local' => array(),
|
|
|
|
|
'foreignUsed' => array(),
|
|
|
|
|
'foreignFree' => array() );
|
2004-07-10 03:09:26 +00:00
|
|
|
$this->mLoads = array();
|
2004-07-18 08:48:43 +00:00
|
|
|
$this->mWaitForPos = false;
|
2005-01-15 10:13:36 +00:00
|
|
|
$this->mLaggedSlaveMode = false;
|
2006-07-26 07:15:39 +00:00
|
|
|
$this->mErrorConnection = false;
|
2010-11-27 22:36:05 +00:00
|
|
|
$this->mAllowLagged = false;
|
2011-06-23 03:14:11 +00:00
|
|
|
|
|
|
|
|
if ( isset( $params['loadMonitor'] ) ) {
|
|
|
|
|
$this->mLoadMonitorClass = $params['loadMonitor'];
|
|
|
|
|
} else {
|
|
|
|
|
$master = reset( $params['servers'] );
|
|
|
|
|
if ( isset( $master['type'] ) && $master['type'] === 'mysql' ) {
|
|
|
|
|
$this->mLoadMonitorClass = 'LoadMonitor_MySQL';
|
|
|
|
|
} else {
|
|
|
|
|
$this->mLoadMonitorClass = 'LoadMonitor_Null';
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-07-10 03:09:26 +00:00
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
foreach( $params['servers'] as $i => $server ) {
|
2004-07-10 03:09:26 +00:00
|
|
|
$this->mLoads[$i] = $server['load'];
|
2005-04-23 11:49:33 +00:00
|
|
|
if ( isset( $server['groupLoads'] ) ) {
|
|
|
|
|
foreach ( $server['groupLoads'] as $group => $ratio ) {
|
|
|
|
|
if ( !isset( $this->mGroupLoads[$group] ) ) {
|
|
|
|
|
$this->mGroupLoads[$group] = array();
|
|
|
|
|
}
|
|
|
|
|
$this->mGroupLoads[$group][$i] = $ratio;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
/**
|
|
|
|
|
* Get a LoadMonitor instance
|
2011-03-09 17:09:10 +00:00
|
|
|
*
|
|
|
|
|
* @return LoadMonitor
|
2008-07-07 03:31:00 +00:00
|
|
|
*/
|
|
|
|
|
function getLoadMonitor() {
|
|
|
|
|
if ( !isset( $this->mLoadMonitor ) ) {
|
|
|
|
|
$class = $this->mLoadMonitorClass;
|
|
|
|
|
$this->mLoadMonitor = new $class( $this );
|
|
|
|
|
}
|
|
|
|
|
return $this->mLoadMonitor;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
/**
|
|
|
|
|
* Get or set arbitrary data used by the parent object, usually an LBFactory
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $x
|
2012-02-13 16:35:59 +00:00
|
|
|
* @return Mixed
|
2008-03-30 09:48:15 +00:00
|
|
|
*/
|
|
|
|
|
function parentInfo( $x = null ) {
|
|
|
|
|
return wfSetVar( $this->mParentInfo, $x );
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Given an array of non-normalised probabilities, this function will select
|
|
|
|
|
* an element and return the appropriate key
|
2011-05-25 18:41:31 +00:00
|
|
|
*
|
2011-12-05 16:50:58 +00:00
|
|
|
* @param $weights array
|
2011-05-25 18:41:31 +00:00
|
|
|
*
|
|
|
|
|
* @return int
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2011-04-18 23:12:58 +00:00
|
|
|
function pickRandom( $weights ) {
|
2004-01-25 13:27:53 +00:00
|
|
|
if ( !is_array( $weights ) || count( $weights ) == 0 ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-11 19:49:46 +00:00
|
|
|
$sum = array_sum( $weights );
|
2005-06-01 06:18:49 +00:00
|
|
|
if ( $sum == 0 ) {
|
|
|
|
|
# No loads on any of them
|
2006-04-11 19:49:46 +00:00
|
|
|
# In previous versions, this triggered an unweighted random selection,
|
2008-04-14 07:45:50 +00:00
|
|
|
# but this feature has been removed as of April 2006 to allow for strict
|
|
|
|
|
# separation of query groups.
|
2006-04-11 19:49:46 +00:00
|
|
|
return false;
|
2005-06-01 06:18:49 +00:00
|
|
|
}
|
2004-06-22 08:54:26 +00:00
|
|
|
$max = mt_getrandmax();
|
2011-08-24 12:47:42 +00:00
|
|
|
$rand = mt_rand( 0, $max ) / $max * $sum;
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2004-01-25 13:27:53 +00:00
|
|
|
$sum = 0;
|
|
|
|
|
foreach ( $weights as $i => $w ) {
|
|
|
|
|
$sum += $w;
|
|
|
|
|
if ( $sum >= $rand ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $i;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-25 18:41:31 +00:00
|
|
|
/**
|
2011-12-05 16:50:58 +00:00
|
|
|
* @param $loads array
|
2011-05-25 18:41:31 +00:00
|
|
|
* @param $wiki bool
|
|
|
|
|
* @return bool|int|string
|
|
|
|
|
*/
|
2008-04-06 10:08:58 +00:00
|
|
|
function getRandomNonLagged( $loads, $wiki = false ) {
|
2005-06-01 06:18:49 +00:00
|
|
|
# Unset excessively lagged servers
|
2008-04-06 10:08:58 +00:00
|
|
|
$lags = $this->getLagTimes( $wiki );
|
2005-06-01 06:18:49 +00:00
|
|
|
foreach ( $lags as $i => $lag ) {
|
2010-11-27 22:39:56 +00:00
|
|
|
if ( $i != 0 ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $lag === false ) {
|
2011-08-19 23:19:26 +00:00
|
|
|
wfDebugLog( 'replication', "Server #$i is not replicating\n" );
|
2008-03-30 09:48:15 +00:00
|
|
|
unset( $loads[$i] );
|
2010-11-27 22:39:56 +00:00
|
|
|
} elseif ( isset( $this->mServers[$i]['max lag'] ) && $lag > $this->mServers[$i]['max lag'] ) {
|
2011-08-19 23:19:26 +00:00
|
|
|
wfDebugLog( 'replication', "Server #$i is excessively lagged ($lag seconds)\n" );
|
2008-03-30 09:48:15 +00:00
|
|
|
unset( $loads[$i] );
|
|
|
|
|
}
|
2005-06-01 06:18:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Find out if all the slaves with non-zero load are lagged
|
|
|
|
|
$sum = 0;
|
|
|
|
|
foreach ( $loads as $load ) {
|
|
|
|
|
$sum += $load;
|
|
|
|
|
}
|
|
|
|
|
if ( $sum == 0 ) {
|
|
|
|
|
# No appropriate DB servers except maybe the master and some slaves with zero load
|
|
|
|
|
# Do NOT use the master
|
2005-08-02 13:35:19 +00:00
|
|
|
# Instead, this function will return false, triggering read-only mode,
|
2005-06-01 06:18:49 +00:00
|
|
|
# and a lagged slave will be used instead.
|
2006-04-11 19:49:46 +00:00
|
|
|
return false;
|
2005-06-01 06:18:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( count( $loads ) == 0 ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-17 20:07:33 +00:00
|
|
|
#wfDebugLog( 'connect', var_export( $loads, true ) );
|
2005-06-01 06:18:49 +00:00
|
|
|
|
|
|
|
|
# Return a random representative of the remainder
|
|
|
|
|
return $this->pickRandom( $loads );
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-25 13:48:02 +00:00
|
|
|
/**
|
|
|
|
|
* Get the index of the reader connection, which may be a slave
|
2005-08-02 13:35:19 +00:00
|
|
|
* This takes into account load ratios and lag times. It should
|
2005-06-25 13:48:02 +00:00
|
|
|
* always return a consistent index during a given invocation
|
|
|
|
|
*
|
|
|
|
|
* Side effect: opens connections to databases
|
2011-05-25 18:41:31 +00:00
|
|
|
* @param $group bool
|
|
|
|
|
* @param $wiki bool
|
|
|
|
|
* @return bool|int|string
|
2005-06-25 13:48:02 +00:00
|
|
|
*/
|
2008-09-21 06:42:46 +00:00
|
|
|
function getReaderIndex( $group = false, $wiki = false ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
global $wgReadOnly, $wgDBClusterTimeout, $wgDBAvgStatusPoll, $wgDBtype;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2011-05-17 22:03:20 +00:00
|
|
|
# @todo FIXME: For now, only go through all this for mysql databases
|
2008-03-30 09:48:15 +00:00
|
|
|
if ($wgDBtype != 'mysql') {
|
|
|
|
|
return $this->getWriterIndex();
|
|
|
|
|
}
|
2004-08-07 03:53:19 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( count( $this->mServers ) == 1 ) {
|
2006-10-14 06:49:22 +00:00
|
|
|
# Skip the load balancing if there's only one server
|
2008-03-30 09:48:15 +00:00
|
|
|
return 0;
|
2008-04-13 06:23:39 +00:00
|
|
|
} elseif ( $group === false and $this->mReadIndex >= 0 ) {
|
|
|
|
|
# Shortcut if generic reader exists already
|
2008-03-30 09:48:15 +00:00
|
|
|
return $this->mReadIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$totalElapsed = 0;
|
|
|
|
|
|
|
|
|
|
# convert from seconds to microseconds
|
2008-04-14 07:45:50 +00:00
|
|
|
$timeout = $wgDBClusterTimeout * 1e6;
|
2008-03-30 09:48:15 +00:00
|
|
|
|
|
|
|
|
# Find the relevant load array
|
|
|
|
|
if ( $group !== false ) {
|
|
|
|
|
if ( isset( $this->mGroupLoads[$group] ) ) {
|
|
|
|
|
$nonErrorLoads = $this->mGroupLoads[$group];
|
2004-01-25 13:27:53 +00:00
|
|
|
} else {
|
2008-03-30 09:48:15 +00:00
|
|
|
# No loads for this group, return false and the caller can use some other group
|
|
|
|
|
wfDebug( __METHOD__.": no loads for group $group\n" );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$nonErrorLoads = $this->mLoads;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !$nonErrorLoads ) {
|
|
|
|
|
throw new MWException( "Empty server array given to LoadBalancer" );
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
# Scale the configured load ratios according to the dynamic load (if the load monitor supports it)
|
|
|
|
|
$this->getLoadMonitor()->scaleLoads( $nonErrorLoads, $group, $wiki );
|
|
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
$laggedSlaveMode = false;
|
|
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
# First try quickly looking through the available servers for a server that
|
2008-03-30 09:48:15 +00:00
|
|
|
# meets our criteria
|
|
|
|
|
do {
|
|
|
|
|
$totalThreadsConnected = 0;
|
|
|
|
|
$overloadedServers = 0;
|
|
|
|
|
$currentLoads = $nonErrorLoads;
|
|
|
|
|
while ( count( $currentLoads ) ) {
|
|
|
|
|
if ( $wgReadOnly || $this->mAllowLagged || $laggedSlaveMode ) {
|
|
|
|
|
$i = $this->pickRandom( $currentLoads );
|
|
|
|
|
} else {
|
2008-04-06 10:08:58 +00:00
|
|
|
$i = $this->getRandomNonLagged( $currentLoads, $wiki );
|
2010-10-05 15:10:14 +00:00
|
|
|
if ( $i === false && count( $currentLoads ) != 0 ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
# All slaves lagged. Switch to read-only mode
|
2011-08-21 15:24:44 +00:00
|
|
|
wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode\n" );
|
2011-09-07 23:21:41 +00:00
|
|
|
$wgReadOnly = 'The database has been automatically locked ' .
|
|
|
|
|
'while the slave database servers catch up to the master';
|
2008-03-30 09:48:15 +00:00
|
|
|
$i = $this->pickRandom( $currentLoads );
|
|
|
|
|
$laggedSlaveMode = true;
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $i === false ) {
|
|
|
|
|
# pickRandom() returned false
|
2011-06-17 15:59:55 +00:00
|
|
|
# This is permanent and means the configuration or the load monitor
|
2008-07-07 03:31:00 +00:00
|
|
|
# wants us to return false.
|
2008-03-30 09:48:15 +00:00
|
|
|
wfDebugLog( 'connect', __METHOD__.": pickRandom() returned false\n" );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wfDebugLog( 'connect', __METHOD__.": Using reader #$i: {$this->mServers[$i]['host']}...\n" );
|
2008-09-21 06:42:46 +00:00
|
|
|
$conn = $this->openConnection( $i, $wiki );
|
2004-07-24 08:33:37 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( !$conn ) {
|
|
|
|
|
wfDebugLog( 'connect', __METHOD__.": Failed connecting to $i/$wiki\n" );
|
|
|
|
|
unset( $nonErrorLoads[$i] );
|
|
|
|
|
unset( $currentLoads[$i] );
|
|
|
|
|
continue;
|
2005-10-24 20:38:46 +00:00
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
// Perform post-connection backoff
|
2011-06-17 15:59:55 +00:00
|
|
|
$threshold = isset( $this->mServers[$i]['max threads'] )
|
2008-07-07 03:31:00 +00:00
|
|
|
? $this->mServers[$i]['max threads'] : false;
|
|
|
|
|
$backoff = $this->getLoadMonitor()->postConnectionBackoff( $conn, $threshold );
|
|
|
|
|
|
|
|
|
|
// Decrement reference counter, we are finished with this connection.
|
|
|
|
|
// It will be incremented for the caller later.
|
|
|
|
|
if ( $wiki !== false ) {
|
|
|
|
|
$this->reuseConnection( $conn );
|
|
|
|
|
}
|
2011-06-17 15:59:55 +00:00
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
if ( $backoff ) {
|
|
|
|
|
# Post-connection overload, don't use this server for now
|
|
|
|
|
$totalThreadsConnected += $backoff;
|
|
|
|
|
$overloadedServers++;
|
|
|
|
|
unset( $currentLoads[$i] );
|
2004-07-24 07:24:04 +00:00
|
|
|
} else {
|
2008-07-07 03:31:00 +00:00
|
|
|
# Return this server
|
2008-03-30 09:48:15 +00:00
|
|
|
break 2;
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
|
|
|
|
|
# No server found yet
|
|
|
|
|
$i = false;
|
|
|
|
|
|
|
|
|
|
# If all servers were down, quit now
|
|
|
|
|
if ( !count( $nonErrorLoads ) ) {
|
|
|
|
|
wfDebugLog( 'connect', "All servers down\n" );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Some servers must have been overloaded
|
|
|
|
|
if ( $overloadedServers == 0 ) {
|
|
|
|
|
throw new MWException( __METHOD__.": unexpectedly found no overloaded servers" );
|
|
|
|
|
}
|
|
|
|
|
# Back off for a while
|
2008-04-14 07:45:50 +00:00
|
|
|
# Scale the sleep time by the number of connected threads, to produce a
|
2008-03-30 09:48:15 +00:00
|
|
|
# roughly constant global poll rate
|
|
|
|
|
$avgThreads = $totalThreadsConnected / $overloadedServers;
|
|
|
|
|
$totalElapsed += $this->sleep( $wgDBAvgStatusPoll * $avgThreads );
|
|
|
|
|
} while ( $totalElapsed < $timeout );
|
|
|
|
|
|
|
|
|
|
if ( $totalElapsed >= $timeout ) {
|
|
|
|
|
wfDebugLog( 'connect', "All servers busy\n" );
|
|
|
|
|
$this->mErrorConnection = false;
|
|
|
|
|
$this->mLastError = 'All servers busy';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $i !== false ) {
|
2008-07-07 03:31:00 +00:00
|
|
|
# Slave connection successful
|
2008-03-30 09:48:15 +00:00
|
|
|
# Wait for the session master pos for a short time
|
|
|
|
|
if ( $this->mWaitForPos && $i > 0 ) {
|
|
|
|
|
if ( !$this->doWait( $i ) ) {
|
|
|
|
|
$this->mServers[$i]['slave pos'] = $conn->getSlavePos();
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-04-13 06:23:39 +00:00
|
|
|
if ( $this->mReadIndex <=0 && $this->mLoads[$i]>0 && $i !== false ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
$this->mReadIndex = $i;
|
|
|
|
|
}
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2004-07-24 07:24:04 +00:00
|
|
|
return $i;
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
/**
|
|
|
|
|
* Wait for a specified number of microseconds, and return the period waited
|
2011-12-05 16:50:58 +00:00
|
|
|
* @param $t int
|
|
|
|
|
* @return int
|
2008-03-30 09:48:15 +00:00
|
|
|
*/
|
|
|
|
|
function sleep( $t ) {
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
wfDebug( __METHOD__.": waiting $t us\n" );
|
|
|
|
|
usleep( $t );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $t;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Set the master wait position
|
|
|
|
|
* If a DB_SLAVE connection has been opened already, waits
|
|
|
|
|
* Otherwise sets a variable telling it to wait if such a connection is opened
|
2011-12-05 16:50:58 +00:00
|
|
|
* @param $pos int
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-03-30 09:48:15 +00:00
|
|
|
public function waitFor( $pos ) {
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
$this->mWaitForPos = $pos;
|
|
|
|
|
$i = $this->mReadIndex;
|
2004-07-18 08:48:43 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $i > 0 ) {
|
|
|
|
|
if ( !$this->doWait( $i ) ) {
|
|
|
|
|
$this->mServers[$i]['slave pos'] = $this->getAnyOpenConnection( $i )->getSlavePos();
|
|
|
|
|
$this->mLaggedSlaveMode = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
}
|
2011-06-17 15:59:55 +00:00
|
|
|
|
2011-03-08 16:47:26 +00:00
|
|
|
/**
|
|
|
|
|
* Set the master wait position and wait for ALL slaves to catch up to it
|
2011-12-05 16:50:58 +00:00
|
|
|
* @param $pos int
|
2011-03-08 16:47:26 +00:00
|
|
|
*/
|
|
|
|
|
public function waitForAll( $pos ) {
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
$this->mWaitForPos = $pos;
|
|
|
|
|
for ( $i = 1; $i < count( $this->mServers ); $i++ ) {
|
2011-03-09 00:24:21 +00:00
|
|
|
$this->doWait( $i , true );
|
2011-03-08 16:47:26 +00:00
|
|
|
}
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
}
|
2004-07-18 08:48:43 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
/**
|
|
|
|
|
* Get any open connection to a given server index, local or foreign
|
|
|
|
|
* Returns false if there is no connection open
|
2011-03-09 17:09:10 +00:00
|
|
|
*
|
2011-12-05 16:50:58 +00:00
|
|
|
* @param $i int
|
2012-02-10 15:37:33 +00:00
|
|
|
* @return DatabaseBase|bool False on failure
|
2008-03-30 09:48:15 +00:00
|
|
|
*/
|
|
|
|
|
function getAnyOpenConnection( $i ) {
|
2010-10-14 20:53:04 +00:00
|
|
|
foreach ( $this->mConns as $conns ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( !empty( $conns[$i] ) ) {
|
|
|
|
|
return reset( $conns[$i] );
|
2005-08-02 13:35:19 +00:00
|
|
|
}
|
2004-08-07 03:53:19 +00:00
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
return false;
|
2004-07-18 08:48:43 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Wait for a given slave to catch up to the master pos stored in $this
|
2011-09-16 17:58:50 +00:00
|
|
|
* @param $index
|
|
|
|
|
* @param $open bool
|
|
|
|
|
* @return bool
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2011-03-09 16:37:39 +00:00
|
|
|
function doWait( $index, $open = false ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
# Find a connection to wait on
|
|
|
|
|
$conn = $this->getAnyOpenConnection( $index );
|
|
|
|
|
if ( !$conn ) {
|
2011-03-09 00:24:21 +00:00
|
|
|
if ( !$open ) {
|
|
|
|
|
wfDebug( __METHOD__ . ": no connection open\n" );
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
$conn = $this->openConnection( $index );
|
|
|
|
|
if ( !$conn ) {
|
|
|
|
|
wfDebug( __METHOD__ . ": failed to open connection\n" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-07-18 08:48:43 +00:00
|
|
|
}
|
|
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
wfDebug( __METHOD__.": Waiting for slave #$index to catch up...\n" );
|
|
|
|
|
$result = $conn->masterPosWait( $this->mWaitForPos, $this->mWaitTimeout );
|
2004-07-23 12:37:55 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $result == -1 || is_null( $result ) ) {
|
|
|
|
|
# Timed out waiting for slave, use master instead
|
|
|
|
|
wfDebug( __METHOD__.": Timed out waiting for slave #$index pos {$this->mWaitForPos}\n" );
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
wfDebug( __METHOD__.": Done\n" );
|
|
|
|
|
return true;
|
2004-07-23 12:37:55 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
}
|
2004-07-18 08:48:43 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Get a connection by index
|
2008-03-30 09:48:15 +00:00
|
|
|
* This is the main entry point for this class.
|
2011-06-17 15:59:55 +00:00
|
|
|
*
|
2010-03-11 20:59:25 +00:00
|
|
|
* @param $i Integer: server index
|
|
|
|
|
* @param $groups Array: query groups
|
|
|
|
|
* @param $wiki String: wiki ID
|
2011-06-17 15:59:55 +00:00
|
|
|
*
|
2010-08-10 06:17:49 +00:00
|
|
|
* @return DatabaseBase
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-09-21 06:42:46 +00:00
|
|
|
public function &getConnection( $i, $groups = array(), $wiki = false ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2008-09-28 01:42:55 +00:00
|
|
|
if ( $i == DB_LAST ) {
|
|
|
|
|
throw new MWException( 'Attempt to call ' . __METHOD__ . ' with deprecated server index DB_LAST' );
|
|
|
|
|
} elseif ( $i === null || $i === false ) {
|
|
|
|
|
throw new MWException( 'Attempt to call ' . __METHOD__ . ' with invalid server index' );
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $wiki === wfWikiID() ) {
|
|
|
|
|
$wiki = false;
|
|
|
|
|
}
|
2006-04-11 19:49:46 +00:00
|
|
|
|
2005-04-23 11:49:33 +00:00
|
|
|
# Query groups
|
2008-04-14 07:45:50 +00:00
|
|
|
if ( $i == DB_MASTER ) {
|
2008-04-08 11:54:34 +00:00
|
|
|
$i = $this->getWriterIndex();
|
|
|
|
|
} elseif ( !is_array( $groups ) ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
$groupIndex = $this->getReaderIndex( $groups, $wiki );
|
2005-04-23 11:49:33 +00:00
|
|
|
if ( $groupIndex !== false ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
$serverName = $this->getServerName( $groupIndex );
|
|
|
|
|
wfDebug( __METHOD__.": using server $serverName for group $groups\n" );
|
2005-04-23 11:49:33 +00:00
|
|
|
$i = $groupIndex;
|
2006-04-11 19:49:46 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
foreach ( $groups as $group ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
$groupIndex = $this->getReaderIndex( $group, $wiki );
|
2006-04-11 19:49:46 +00:00
|
|
|
if ( $groupIndex !== false ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
$serverName = $this->getServerName( $groupIndex );
|
|
|
|
|
wfDebug( __METHOD__.": using server $serverName for group $group\n" );
|
2006-04-11 19:49:46 +00:00
|
|
|
$i = $groupIndex;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-06-15 15:00:54 +00:00
|
|
|
}
|
2005-04-23 11:49:33 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2004-06-15 15:00:54 +00:00
|
|
|
# Operation-based index
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $i == DB_SLAVE ) {
|
2008-09-21 06:42:46 +00:00
|
|
|
$i = $this->getReaderIndex( false, $wiki );
|
2008-09-28 01:42:55 +00:00
|
|
|
# Couldn't find a working server in getReaderIndex()?
|
|
|
|
|
if ( $i === false ) {
|
|
|
|
|
$this->mLastError = 'No working slave server: ' . $this->mLastError;
|
|
|
|
|
$this->reportConnectionError( $this->mErrorConnection );
|
2011-02-10 16:39:53 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2008-09-28 01:42:55 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-08-14 04:42:55 +00:00
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
|
2004-07-24 07:24:04 +00:00
|
|
|
# Now we have an explicit index into the servers array
|
2008-09-21 06:42:46 +00:00
|
|
|
$conn = $this->openConnection( $i, $wiki );
|
|
|
|
|
if ( !$conn ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
$this->reportConnectionError( $this->mErrorConnection );
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $conn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-04-14 07:45:50 +00:00
|
|
|
* Mark a foreign connection as being available for reuse under a different
|
|
|
|
|
* DB name or prefix. This mechanism is reference-counted, and must be called
|
2008-03-30 09:48:15 +00:00
|
|
|
* the same number of times as getConnection() to work.
|
2011-03-09 17:09:10 +00:00
|
|
|
*
|
|
|
|
|
* @param DatabaseBase $conn
|
2008-03-30 09:48:15 +00:00
|
|
|
*/
|
|
|
|
|
public function reuseConnection( $conn ) {
|
|
|
|
|
$serverIndex = $conn->getLBInfo('serverIndex');
|
|
|
|
|
$refCount = $conn->getLBInfo('foreignPoolRefCount');
|
|
|
|
|
$dbName = $conn->getDBname();
|
|
|
|
|
$prefix = $conn->tablePrefix();
|
|
|
|
|
if ( strval( $prefix ) !== '' ) {
|
|
|
|
|
$wiki = "$dbName-$prefix";
|
|
|
|
|
} else {
|
|
|
|
|
$wiki = $dbName;
|
|
|
|
|
}
|
|
|
|
|
if ( $serverIndex === null || $refCount === null ) {
|
|
|
|
|
wfDebug( __METHOD__.": this connection was not opened as a foreign connection\n" );
|
|
|
|
|
/**
|
|
|
|
|
* This can happen in code like:
|
2010-10-05 15:10:14 +00:00
|
|
|
* foreach ( $dbs as $db ) {
|
|
|
|
|
* $conn = $lb->getConnection( DB_SLAVE, array(), $db );
|
|
|
|
|
* ...
|
|
|
|
|
* $lb->reuseConnection( $conn );
|
|
|
|
|
* }
|
2008-03-30 09:48:15 +00:00
|
|
|
* When a connection to the local DB is opened in this way, reuseConnection()
|
|
|
|
|
* should be ignored
|
|
|
|
|
*/
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( $this->mConns['foreignUsed'][$serverIndex][$wiki] !== $conn ) {
|
|
|
|
|
throw new MWException( __METHOD__.": connection not found, has the connection been freed already?" );
|
|
|
|
|
}
|
|
|
|
|
$conn->setLBInfo( 'foreignPoolRefCount', --$refCount );
|
|
|
|
|
if ( $refCount <= 0 ) {
|
|
|
|
|
$this->mConns['foreignFree'][$serverIndex][$wiki] = $conn;
|
|
|
|
|
unset( $this->mConns['foreignUsed'][$serverIndex][$wiki] );
|
|
|
|
|
wfDebug( __METHOD__.": freed connection $serverIndex/$wiki\n" );
|
|
|
|
|
} else {
|
|
|
|
|
wfDebug( __METHOD__.": reference count for $serverIndex/$wiki reduced to $refCount\n" );
|
|
|
|
|
}
|
2004-08-07 03:53:19 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Open a connection to the server given by the specified index
|
2008-03-30 09:48:15 +00:00
|
|
|
* Index must be an actual index into the array.
|
|
|
|
|
* If the server is already open, returns it.
|
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
* On error, returns false, and the connection which caused the
|
2008-03-30 09:48:15 +00:00
|
|
|
* error will be available via $this->mErrorConnection.
|
|
|
|
|
*
|
2011-05-25 18:41:31 +00:00
|
|
|
* @param $i Integer server index
|
|
|
|
|
* @param $wiki String wiki ID to open
|
2010-03-11 20:59:25 +00:00
|
|
|
* @return DatabaseBase
|
2008-03-30 09:48:15 +00:00
|
|
|
*
|
2006-01-07 12:48:44 +00:00
|
|
|
* @access private
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-09-21 06:42:46 +00:00
|
|
|
function openConnection( $i, $wiki = false ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
if ( $wiki !== false ) {
|
2008-04-13 16:46:22 +00:00
|
|
|
$conn = $this->openForeignConnection( $i, $wiki );
|
|
|
|
|
wfProfileOut( __METHOD__);
|
|
|
|
|
return $conn;
|
2004-07-24 07:24:04 +00:00
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( isset( $this->mConns['local'][$i][0] ) ) {
|
|
|
|
|
$conn = $this->mConns['local'][$i][0];
|
|
|
|
|
} else {
|
|
|
|
|
$server = $this->mServers[$i];
|
|
|
|
|
$server['serverIndex'] = $i;
|
2008-09-28 01:42:55 +00:00
|
|
|
$conn = $this->reallyOpenConnection( $server, false );
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $conn->isOpen() ) {
|
|
|
|
|
$this->mConns['local'][$i][0] = $conn;
|
|
|
|
|
} else {
|
|
|
|
|
wfDebug( "Failed to connect to database $i at {$this->mServers[$i]['host']}\n" );
|
|
|
|
|
$this->mErrorConnection = $conn;
|
|
|
|
|
$conn = false;
|
2004-06-15 15:00:54 +00:00
|
|
|
}
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $conn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Open a connection to a foreign DB, or return one if it is already open.
|
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
* Increments a reference count on the returned connection which locks the
|
|
|
|
|
* connection to the requested wiki. This reference count can be
|
2008-03-30 09:48:15 +00:00
|
|
|
* decremented by calling reuseConnection().
|
|
|
|
|
*
|
|
|
|
|
* If a connection is open to the appropriate server already, but with the wrong
|
|
|
|
|
* database, it will be switched to the right database and returned, as long as
|
|
|
|
|
* it has been freed first with reuseConnection().
|
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
* On error, returns false, and the connection which caused the
|
2008-03-30 09:48:15 +00:00
|
|
|
* error will be available via $this->mErrorConnection.
|
|
|
|
|
*
|
2010-03-11 20:59:25 +00:00
|
|
|
* @param $i Integer: server index
|
|
|
|
|
* @param $wiki String: wiki ID to open
|
|
|
|
|
* @return DatabaseBase
|
2008-03-30 09:48:15 +00:00
|
|
|
*/
|
|
|
|
|
function openForeignConnection( $i, $wiki ) {
|
2008-04-13 16:46:22 +00:00
|
|
|
wfProfileIn(__METHOD__);
|
2008-03-30 09:48:15 +00:00
|
|
|
list( $dbName, $prefix ) = wfSplitWikiID( $wiki );
|
|
|
|
|
if ( isset( $this->mConns['foreignUsed'][$i][$wiki] ) ) {
|
|
|
|
|
// Reuse an already-used connection
|
|
|
|
|
$conn = $this->mConns['foreignUsed'][$i][$wiki];
|
|
|
|
|
wfDebug( __METHOD__.": reusing connection $i/$wiki\n" );
|
|
|
|
|
} elseif ( isset( $this->mConns['foreignFree'][$i][$wiki] ) ) {
|
|
|
|
|
// Reuse a free connection for the same wiki
|
|
|
|
|
$conn = $this->mConns['foreignFree'][$i][$wiki];
|
|
|
|
|
unset( $this->mConns['foreignFree'][$i][$wiki] );
|
|
|
|
|
$this->mConns['foreignUsed'][$i][$wiki] = $conn;
|
|
|
|
|
wfDebug( __METHOD__.": reusing free connection $i/$wiki\n" );
|
|
|
|
|
} elseif ( !empty( $this->mConns['foreignFree'][$i] ) ) {
|
|
|
|
|
// Reuse a connection from another wiki
|
|
|
|
|
$conn = reset( $this->mConns['foreignFree'][$i] );
|
|
|
|
|
$oldWiki = key( $this->mConns['foreignFree'][$i] );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( !$conn->selectDB( $dbName ) ) {
|
2008-04-14 07:45:50 +00:00
|
|
|
$this->mLastError = "Error selecting database $dbName on server " .
|
2008-10-06 07:30:38 +00:00
|
|
|
$conn->getServer() . " from client host " . wfHostname() . "\n";
|
2008-03-30 09:48:15 +00:00
|
|
|
$this->mErrorConnection = $conn;
|
|
|
|
|
$conn = false;
|
|
|
|
|
} else {
|
|
|
|
|
$conn->tablePrefix( $prefix );
|
|
|
|
|
unset( $this->mConns['foreignFree'][$i][$oldWiki] );
|
|
|
|
|
$this->mConns['foreignUsed'][$i][$wiki] = $conn;
|
|
|
|
|
wfDebug( __METHOD__.": reusing free connection from $oldWiki for $wiki\n" );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Open a new connection
|
|
|
|
|
$server = $this->mServers[$i];
|
|
|
|
|
$server['serverIndex'] = $i;
|
|
|
|
|
$server['foreignPoolRefCount'] = 0;
|
|
|
|
|
$conn = $this->reallyOpenConnection( $server, $dbName );
|
|
|
|
|
if ( !$conn->isOpen() ) {
|
|
|
|
|
wfDebug( __METHOD__.": error opening connection for $i/$wiki\n" );
|
|
|
|
|
$this->mErrorConnection = $conn;
|
|
|
|
|
$conn = false;
|
|
|
|
|
} else {
|
2008-10-13 18:38:01 +00:00
|
|
|
$conn->tablePrefix( $prefix );
|
2008-03-30 09:48:15 +00:00
|
|
|
$this->mConns['foreignUsed'][$i][$wiki] = $conn;
|
|
|
|
|
wfDebug( __METHOD__.": opened new connection for $i/$wiki\n" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Increment reference count
|
|
|
|
|
if ( $conn ) {
|
|
|
|
|
$refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
|
|
|
|
|
$conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 );
|
|
|
|
|
}
|
2008-04-13 16:46:22 +00:00
|
|
|
wfProfileOut(__METHOD__);
|
2008-03-30 09:48:15 +00:00
|
|
|
return $conn;
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Test if the specified index represents an open connection
|
2010-03-11 20:59:25 +00:00
|
|
|
*
|
|
|
|
|
* @param $index Integer: server index
|
2006-01-07 12:48:44 +00:00
|
|
|
* @access private
|
2011-05-25 18:41:31 +00:00
|
|
|
* @return bool
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
|
|
|
|
function isOpen( $index ) {
|
2004-08-08 01:07:56 +00:00
|
|
|
if( !is_integer( $index ) ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
return (bool)$this->getAnyOpenConnection( $index );
|
2004-07-24 07:24:04 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2008-03-30 09:48:15 +00:00
|
|
|
* Really opens a connection. Uncached.
|
|
|
|
|
* Returns a Database object whether or not the connection was successful.
|
2006-01-07 12:48:44 +00:00
|
|
|
* @access private
|
2011-05-25 18:41:31 +00:00
|
|
|
*
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $server
|
|
|
|
|
* @param $dbNameOverride bool
|
2011-05-25 18:41:31 +00:00
|
|
|
* @return DatabaseBase
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-09-21 06:42:46 +00:00
|
|
|
function reallyOpenConnection( $server, $dbNameOverride = false ) {
|
2004-12-06 01:14:53 +00:00
|
|
|
if( !is_array( $server ) ) {
|
2010-12-30 02:48:27 +00:00
|
|
|
throw new MWException( 'You must update your load-balancing configuration. ' .
|
2011-09-16 17:58:50 +00:00
|
|
|
'See DefaultSettings.php entry for $wgDBservers.' );
|
2004-12-06 01:14:53 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2010-12-30 02:48:27 +00:00
|
|
|
$host = $server['host'];
|
2010-12-30 07:24:41 +00:00
|
|
|
$dbname = $server['dbname'];
|
2010-12-30 02:48:27 +00:00
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $dbNameOverride !== false ) {
|
2011-01-24 18:45:59 +00:00
|
|
|
$server['dbname'] = $dbname = $dbNameOverride;
|
2008-03-30 09:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
2004-12-06 01:14:53 +00:00
|
|
|
# Create object
|
2010-10-19 06:27:25 +00:00
|
|
|
wfDebug( "Connecting to $host $dbname...\n" );
|
2011-09-07 23:21:41 +00:00
|
|
|
try {
|
|
|
|
|
$db = DatabaseBase::factory( $server['type'], $server );
|
|
|
|
|
} catch ( DBConnectionError $e ) {
|
|
|
|
|
// FIXME: This is probably the ugliest thing I have ever done to
|
|
|
|
|
// PHP. I'm half-expecting it to segfault, just out of disgust. -- TS
|
|
|
|
|
$db = $e->db;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( $db->isOpen() ) {
|
2010-10-19 06:27:25 +00:00
|
|
|
wfDebug( "Connected to $host $dbname.\n" );
|
2008-03-30 09:48:15 +00:00
|
|
|
} else {
|
2010-10-19 06:27:25 +00:00
|
|
|
wfDebug( "Connection failed to $host $dbname.\n" );
|
2008-03-30 09:48:15 +00:00
|
|
|
}
|
2005-10-29 01:41:36 +00:00
|
|
|
$db->setLBInfo( $server );
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( isset( $server['fakeSlaveLag'] ) ) {
|
|
|
|
|
$db->setFakeSlaveLag( $server['fakeSlaveLag'] );
|
|
|
|
|
}
|
|
|
|
|
if ( isset( $server['fakeMaster'] ) ) {
|
|
|
|
|
$db->setFakeMaster( true );
|
|
|
|
|
}
|
2005-10-29 01:41:36 +00:00
|
|
|
return $db;
|
2004-07-10 03:09:26 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2011-11-29 21:04:20 +00:00
|
|
|
/**
|
|
|
|
|
* @param $conn
|
|
|
|
|
* @throws DBConnectionError
|
|
|
|
|
*/
|
2008-01-20 18:42:21 +00:00
|
|
|
function reportConnectionError( &$conn ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2008-09-28 01:42:55 +00:00
|
|
|
|
|
|
|
|
if ( !is_object( $conn ) ) {
|
|
|
|
|
// No last connection, probably due to all servers being too busy
|
2011-08-01 23:28:06 +00:00
|
|
|
wfLogDBError( "LB failure with no last connection. Connection error: {$this->mLastError}\n" );
|
2008-09-28 01:42:55 +00:00
|
|
|
$conn = new Database;
|
2010-10-24 20:48:48 +00:00
|
|
|
// If all servers were busy, mLastError will contain something sensible
|
|
|
|
|
throw new DBConnectionError( $conn, $this->mLastError );
|
2008-09-28 01:42:55 +00:00
|
|
|
} else {
|
|
|
|
|
$server = $conn->getProperty( 'mServer' );
|
|
|
|
|
wfLogDBError( "Connection error: {$this->mLastError} ({$server})\n" );
|
|
|
|
|
$conn->reportConnectionError( "{$this->mLastError} ({$server})" );
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2011-10-14 21:18:38 +00:00
|
|
|
/**
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
2006-06-03 22:20:31 +00:00
|
|
|
function getWriterIndex() {
|
2004-07-24 07:24:04 +00:00
|
|
|
return 0;
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|
|
|
|
|
|
2006-06-03 22:20:31 +00:00
|
|
|
/**
|
|
|
|
|
* Returns true if the specified index is a valid server index
|
2011-05-25 18:41:31 +00:00
|
|
|
*
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $i
|
2011-05-25 18:41:31 +00:00
|
|
|
* @return bool
|
2006-06-03 22:20:31 +00:00
|
|
|
*/
|
|
|
|
|
function haveIndex( $i ) {
|
2004-06-15 15:00:54 +00:00
|
|
|
return array_key_exists( $i, $this->mServers );
|
|
|
|
|
}
|
2004-07-18 08:48:43 +00:00
|
|
|
|
2006-06-03 22:20:31 +00:00
|
|
|
/**
|
|
|
|
|
* Returns true if the specified index is valid and has non-zero load
|
2011-05-25 18:41:31 +00:00
|
|
|
*
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $i
|
2011-05-25 18:41:31 +00:00
|
|
|
* @return bool
|
2006-06-03 22:20:31 +00:00
|
|
|
*/
|
|
|
|
|
function isNonZeroLoad( $i ) {
|
|
|
|
|
return array_key_exists( $i, $this->mServers ) && $this->mLoads[$i] != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Get the number of defined servers (not the number of open connections)
|
2011-05-25 18:41:31 +00:00
|
|
|
*
|
|
|
|
|
* @return int
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2004-07-18 08:48:43 +00:00
|
|
|
function getServerCount() {
|
|
|
|
|
return count( $this->mServers );
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2008-03-30 09:48:15 +00:00
|
|
|
* Get the host name or IP address of the server with the specified index
|
2008-07-07 03:31:00 +00:00
|
|
|
* Prefer a readable name if available.
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $i
|
|
|
|
|
* @return string
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-03-30 09:48:15 +00:00
|
|
|
function getServerName( $i ) {
|
|
|
|
|
if ( isset( $this->mServers[$i]['hostName'] ) ) {
|
|
|
|
|
return $this->mServers[$i]['hostName'];
|
|
|
|
|
} elseif ( isset( $this->mServers[$i]['host'] ) ) {
|
|
|
|
|
return $this->mServers[$i]['host'];
|
|
|
|
|
} else {
|
|
|
|
|
return '';
|
2004-07-18 08:48:43 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
/**
|
|
|
|
|
* Return the server info structure for a given index, or false if the index is invalid.
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $i
|
|
|
|
|
* @return bool
|
2008-07-07 03:31:00 +00:00
|
|
|
*/
|
|
|
|
|
function getServerInfo( $i ) {
|
|
|
|
|
if ( isset( $this->mServers[$i] ) ) {
|
|
|
|
|
return $this->mServers[$i];
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-18 23:12:58 +00:00
|
|
|
/**
|
|
|
|
|
* Sets the server info structure for the given index. Entry at index $i is created if it doesn't exist
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $i
|
|
|
|
|
* @param $serverInfo
|
2011-04-18 23:12:58 +00:00
|
|
|
*/
|
|
|
|
|
function setServerInfo( $i, $serverInfo ) {
|
2011-05-02 07:42:14 +00:00
|
|
|
$this->mServers[$i] = $serverInfo;
|
2011-04-18 23:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2008-03-30 09:48:15 +00:00
|
|
|
* Get the current master position for chronology control purposes
|
|
|
|
|
* @return mixed
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-03-30 09:48:15 +00:00
|
|
|
function getMasterPos() {
|
|
|
|
|
# If this entire request was served from a slave without opening a connection to the
|
|
|
|
|
# master (however unlikely that may be), then we can fetch the position from the slave.
|
|
|
|
|
$masterConn = $this->getAnyOpenConnection( 0 );
|
|
|
|
|
if ( !$masterConn ) {
|
2008-04-06 10:08:58 +00:00
|
|
|
for ( $i = 1; $i < count( $this->mServers ); $i++ ) {
|
|
|
|
|
$conn = $this->getAnyOpenConnection( $i );
|
|
|
|
|
if ( $conn ) {
|
|
|
|
|
wfDebug( "Master pos fetched from slave\n" );
|
|
|
|
|
return $conn->getSlavePos();
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
} else {
|
|
|
|
|
wfDebug( "Master pos fetched from master\n" );
|
2008-04-06 10:08:58 +00:00
|
|
|
return $masterConn->getMasterPos();
|
2004-07-18 08:48:43 +00:00
|
|
|
}
|
2008-04-06 10:08:58 +00:00
|
|
|
return false;
|
2004-07-18 08:48:43 +00:00
|
|
|
}
|
2004-07-24 07:24:04 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Close all open connections
|
|
|
|
|
*/
|
2004-07-24 07:24:04 +00:00
|
|
|
function closeAll() {
|
2008-03-30 09:48:15 +00:00
|
|
|
foreach ( $this->mConns as $conns2 ) {
|
2010-10-05 15:10:14 +00:00
|
|
|
foreach ( $conns2 as $conns3 ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
foreach ( $conns3 as $conn ) {
|
|
|
|
|
$conn->close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->mConns = array(
|
|
|
|
|
'local' => array(),
|
|
|
|
|
'foreignFree' => array(),
|
|
|
|
|
'foreignUsed' => array(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-24 01:00:29 +00:00
|
|
|
/**
|
|
|
|
|
* Deprecated function, typo in function name
|
2011-05-25 18:41:31 +00:00
|
|
|
*
|
|
|
|
|
* @deprecated in 1.18
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $conn
|
2011-01-24 01:00:29 +00:00
|
|
|
*/
|
|
|
|
|
function closeConnecton( $conn ) {
|
2011-12-13 05:19:05 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.18' );
|
2011-01-24 01:00:29 +00:00
|
|
|
$this->closeConnection( $conn );
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
/**
|
|
|
|
|
* Close a connection
|
|
|
|
|
* Using this function makes sure the LoadBalancer knows the connection is closed.
|
|
|
|
|
* If you use $conn->close() directly, the load balancer won't update its state.
|
2011-09-16 17:58:50 +00:00
|
|
|
* @param $conn DatabaseBase
|
2008-03-30 09:48:15 +00:00
|
|
|
*/
|
2011-01-24 01:00:29 +00:00
|
|
|
function closeConnection( $conn ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
$done = false;
|
|
|
|
|
foreach ( $this->mConns as $i1 => $conns2 ) {
|
|
|
|
|
foreach ( $conns2 as $i2 => $conns3 ) {
|
|
|
|
|
foreach ( $conns3 as $i3 => $candidateConn ) {
|
|
|
|
|
if ( $conn === $candidateConn ) {
|
|
|
|
|
$conn->close();
|
|
|
|
|
unset( $this->mConns[$i1][$i2][$i3] );
|
|
|
|
|
$done = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-07-24 07:24:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( !$done ) {
|
|
|
|
|
$conn->close();
|
|
|
|
|
}
|
2004-07-24 07:24:04 +00:00
|
|
|
}
|
|
|
|
|
|
2008-03-30 09:48:15 +00:00
|
|
|
/**
|
|
|
|
|
* Commit transactions on all open connections
|
|
|
|
|
*/
|
2004-07-24 07:24:04 +00:00
|
|
|
function commitAll() {
|
2008-03-30 09:48:15 +00:00
|
|
|
foreach ( $this->mConns as $conns2 ) {
|
|
|
|
|
foreach ( $conns2 as $conns3 ) {
|
|
|
|
|
foreach ( $conns3 as $conn ) {
|
2012-02-25 13:23:43 +00:00
|
|
|
$conn->commit( __METHOD__ );
|
2008-03-30 09:48:15 +00:00
|
|
|
}
|
2004-07-24 07:24:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2011-05-25 18:41:31 +00:00
|
|
|
/**
|
|
|
|
|
* Issue COMMIT only on master, only if queries were done on connection
|
|
|
|
|
*/
|
2008-01-12 22:51:16 +00:00
|
|
|
function commitMasterChanges() {
|
|
|
|
|
// Always 0, but who knows.. :)
|
2008-03-30 09:48:15 +00:00
|
|
|
$masterIndex = $this->getWriterIndex();
|
2010-10-14 20:53:04 +00:00
|
|
|
foreach ( $this->mConns as $conns2 ) {
|
2008-03-30 09:48:15 +00:00
|
|
|
if ( empty( $conns2[$masterIndex] ) ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
foreach ( $conns2[$masterIndex] as $conn ) {
|
2009-02-17 14:06:42 +00:00
|
|
|
if ( $conn->doneWrites() ) {
|
2012-01-18 12:10:16 +00:00
|
|
|
$conn->commit( __METHOD__ );
|
2008-03-30 09:48:15 +00:00
|
|
|
}
|
2008-01-12 22:51:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-01-15 10:13:36 +00:00
|
|
|
|
2011-09-16 17:58:50 +00:00
|
|
|
/**
|
|
|
|
|
* @param $value null
|
|
|
|
|
* @return Mixed
|
|
|
|
|
*/
|
2009-12-11 21:07:27 +00:00
|
|
|
function waitTimeout( $value = null ) {
|
2005-01-15 10:13:36 +00:00
|
|
|
return wfSetVar( $this->mWaitTimeout, $value );
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-16 17:58:50 +00:00
|
|
|
/**
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2005-01-15 10:13:36 +00:00
|
|
|
function getLaggedSlaveMode() {
|
|
|
|
|
return $this->mLaggedSlaveMode;
|
|
|
|
|
}
|
2005-04-24 08:31:12 +00:00
|
|
|
|
2011-11-29 21:04:20 +00:00
|
|
|
/**
|
|
|
|
|
* Disables/enables lag checks
|
|
|
|
|
* @param $mode null
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2011-05-25 18:41:31 +00:00
|
|
|
function allowLagged( $mode = null ) {
|
|
|
|
|
if ( $mode === null) {
|
2006-01-23 15:27:44 +00:00
|
|
|
return $this->mAllowLagged;
|
2011-05-25 18:41:31 +00:00
|
|
|
}
|
|
|
|
|
$this->mAllowLagged = $mode;
|
2006-01-23 15:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
2011-09-16 17:58:50 +00:00
|
|
|
/**
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2005-04-24 08:31:12 +00:00
|
|
|
function pingAll() {
|
|
|
|
|
$success = true;
|
2008-03-30 09:48:15 +00:00
|
|
|
foreach ( $this->mConns as $conns2 ) {
|
|
|
|
|
foreach ( $conns2 as $conns3 ) {
|
|
|
|
|
foreach ( $conns3 as $conn ) {
|
|
|
|
|
if ( !$conn->ping() ) {
|
|
|
|
|
$success = false;
|
|
|
|
|
}
|
2005-04-24 08:31:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $success;
|
|
|
|
|
}
|
2005-06-01 06:18:49 +00:00
|
|
|
|
2008-07-07 03:31:00 +00:00
|
|
|
/**
|
|
|
|
|
* Call a function with each open connection object
|
2011-11-29 21:04:20 +00:00
|
|
|
* @param $callback
|
|
|
|
|
* @param array $params
|
2008-07-07 03:31:00 +00:00
|
|
|
*/
|
|
|
|
|
function forEachOpenConnection( $callback, $params = array() ) {
|
|
|
|
|
foreach ( $this->mConns as $conns2 ) {
|
|
|
|
|
foreach ( $conns2 as $conns3 ) {
|
|
|
|
|
foreach ( $conns3 as $conn ) {
|
|
|
|
|
$mergedParams = array_merge( array( $conn ), $params );
|
|
|
|
|
call_user_func_array( $callback, $mergedParams );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-01 06:18:49 +00:00
|
|
|
/**
|
2008-04-06 10:08:58 +00:00
|
|
|
* Get the hostname and lag time of the most-lagged slave.
|
|
|
|
|
* This is useful for maintenance scripts that need to throttle their updates.
|
2011-09-07 23:21:41 +00:00
|
|
|
* May attempt to open connections to slaves on the default DB. If there is
|
2011-08-29 04:42:26 +00:00
|
|
|
* no lag, the maximum lag will be reported as -1.
|
|
|
|
|
*
|
2010-01-05 23:39:16 +00:00
|
|
|
* @param $wiki string Wiki ID, or false for the default database
|
2011-06-03 22:59:34 +00:00
|
|
|
*
|
|
|
|
|
* @return array ( host, max lag, index of max lagged host )
|
2005-06-01 06:18:49 +00:00
|
|
|
*/
|
2010-01-05 23:39:16 +00:00
|
|
|
function getMaxLag( $wiki = false ) {
|
2005-06-01 06:18:49 +00:00
|
|
|
$maxLag = -1;
|
|
|
|
|
$host = '';
|
2011-06-03 22:59:34 +00:00
|
|
|
$maxIndex = 0;
|
2011-08-29 04:42:26 +00:00
|
|
|
if ( $this->getServerCount() > 1 ) { // no replication = no lag
|
|
|
|
|
foreach ( $this->mServers as $i => $conn ) {
|
|
|
|
|
$conn = false;
|
|
|
|
|
if ( $wiki === false ) {
|
|
|
|
|
$conn = $this->getAnyOpenConnection( $i );
|
|
|
|
|
}
|
|
|
|
|
if ( !$conn ) {
|
|
|
|
|
$conn = $this->openConnection( $i, $wiki );
|
|
|
|
|
}
|
|
|
|
|
if ( !$conn ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$lag = $conn->getLag();
|
|
|
|
|
if ( $lag > $maxLag ) {
|
|
|
|
|
$maxLag = $lag;
|
|
|
|
|
$host = $this->mServers[$i]['host'];
|
|
|
|
|
$maxIndex = $i;
|
|
|
|
|
}
|
2005-06-01 06:18:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
2011-06-03 22:59:34 +00:00
|
|
|
return array( $host, $maxLag, $maxIndex );
|
2005-06-01 06:18:49 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2005-06-01 06:18:49 +00:00
|
|
|
/**
|
2008-03-30 09:48:15 +00:00
|
|
|
* Get lag time for each server
|
|
|
|
|
* Results are cached for a short time in memcached, and indefinitely in the process cache
|
2011-05-28 18:58:51 +00:00
|
|
|
*
|
|
|
|
|
* @param $wiki
|
2011-06-17 15:59:55 +00:00
|
|
|
*
|
2011-05-28 18:58:51 +00:00
|
|
|
* @return array
|
2005-06-01 06:18:49 +00:00
|
|
|
*/
|
2008-04-06 10:08:58 +00:00
|
|
|
function getLagTimes( $wiki = false ) {
|
2008-07-07 03:31:00 +00:00
|
|
|
# Try process cache
|
|
|
|
|
if ( isset( $this->mLagTimes ) ) {
|
|
|
|
|
return $this->mLagTimes;
|
2008-03-30 09:48:15 +00:00
|
|
|
}
|
2011-08-29 04:42:26 +00:00
|
|
|
if ( $this->getServerCount() == 1 ) {
|
|
|
|
|
# No replication
|
|
|
|
|
$this->mLagTimes = array( 0 => 0 );
|
|
|
|
|
} else {
|
|
|
|
|
# Send the request to the load monitor
|
2011-09-07 23:21:41 +00:00
|
|
|
$this->mLagTimes = $this->getLoadMonitor()->getLagTimes(
|
2011-08-29 04:42:26 +00:00
|
|
|
array_keys( $this->mServers ), $wiki );
|
|
|
|
|
}
|
2008-03-30 09:48:15 +00:00
|
|
|
return $this->mLagTimes;
|
2005-06-01 06:18:49 +00:00
|
|
|
}
|
2010-03-18 05:23:46 +00:00
|
|
|
|
2011-08-29 05:04:55 +00:00
|
|
|
/**
|
2011-09-07 23:21:41 +00:00
|
|
|
* Get the lag in seconds for a given connection, or zero if this load
|
|
|
|
|
* balancer does not have replication enabled.
|
2011-08-29 05:04:55 +00:00
|
|
|
*
|
2011-09-07 23:21:41 +00:00
|
|
|
* This should be used in preference to Database::getLag() in cases where
|
|
|
|
|
* replication may not be in use, since there is no way to determine if
|
|
|
|
|
* replication is in use at the connection level without running
|
2011-08-29 05:04:55 +00:00
|
|
|
* potentially restricted queries such as SHOW SLAVE STATUS. Using this
|
|
|
|
|
* function instead of Database::getLag() avoids a fatal error in this
|
|
|
|
|
* case on many installations.
|
2011-09-16 17:58:50 +00:00
|
|
|
*
|
|
|
|
|
* @param $conn DatabaseBase
|
|
|
|
|
*
|
|
|
|
|
* @return int
|
2011-08-29 05:04:55 +00:00
|
|
|
*/
|
|
|
|
|
function safeGetLag( $conn ) {
|
|
|
|
|
if ( $this->getServerCount() == 1 ) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
return $conn->getLag();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-18 05:23:46 +00:00
|
|
|
/**
|
|
|
|
|
* Clear the cache for getLagTimes
|
|
|
|
|
*/
|
|
|
|
|
function clearLagTimeCache() {
|
|
|
|
|
$this->mLagTimes = null;
|
|
|
|
|
}
|
2004-01-25 13:27:53 +00:00
|
|
|
}
|