wiki.techinc.nl/includes/LoadBalancer.php

144 lines
3.4 KiB
PHP
Raw Normal View History

<?php
2004-01-25 13:27:53 +00:00
# Database load balancing object
class LoadBalancer {
/* private */ var $mServers, $mConnections, $mLoads;
/* private */ var $mUser, $mPassword, $mDbName, $mFailFunction;
/* private */ var $mForce, $mReadIndex;
function LoadBalancer()
{
$this->mServers = array();
$this->mLoads = array();
$this->mConnections = array();
$this->mUser = false;
$this->mPassword = false;
$this->mDbName = false;
$this->mFailFunction = false;
$this->mReadIndex = -1;
$this->mForce = -1;
}
function newFromParams( $servers, $loads, $user, $password, $dbName, $failFunction = false )
{
$lb = new LoadBalancer;
$lb->initialise( $servers, $loads, $user, $password, $dbName, $failFunction = false );
return $lb;
}
function initialise( $servers, $loads, $user, $password, $dbName, $failFunction = false )
{
$this->mServers = $servers;
$this->mLoads = $loads;
$this->mUser = $user;
$this->mPassword = $password;
$this->mDbName = $dbName;
$this->mFailFunction = $failFunction;
$this->mReadIndex = -1;
$this->mWriteIndex = -1;
$this->mForce = -1;
$this->mConnections = array();
wfSeedRandom();
}
# Given an array of non-normalised probabilities, this function will select
# an element and return the appropriate key
function pickRandom( $weights )
{
if ( !is_array( $weights ) || count( $weights ) == 0 ) {
return false;
}
$sum = 0;
foreach ( $weights as $w ) {
$sum += $w;
}
$rand = mt_rand() / RAND_MAX * $sum;
$sum = 0;
foreach ( $weights as $i => $w ) {
$sum += $w;
if ( $sum >= $rand ) {
break;
}
}
return $i;
}
function &getReader()
{
if ( $this->mForce >= 0 ) {
$conn =& $this->getConnection( $this->mForce );
} else {
if ( $this->mReadIndex >= 0 ) {
$conn =& $this->getConnection( $this->mReadIndex );
} else {
# $loads is $this->mLoads except with elements knocked out if they
# don't work
$loads = $this->mLoads;
do {
$i = pickRandom( $loads );
if ( $i !== false ) {
$conn =& $this->getConnection( $i );
if ( !$conn->isOpen() ) {
unset( $loads[$i] );
}
}
} while ( $i !== false && !$conn->isOpen() );
if ( $conn->isOpen() ) {
$this->mReadIndex = $i;
}
}
}
if ( $conn === false || !$conn->isOpen() ) {
$this->reportConnectionError( $conn );
$conn = false;
}
return $conn;
}
function &getConnection( $i, $fail = false )
{
if ( !array_key_exists( $i, $this->mConnections) || !$this->mConnections[$i]->isOpen() ) {
$this->mConnections[$i] = Database::newFromParams( $this->mServers[$i], $this->mUser,
$this->mPassword, $this->mDbName, 1 );
}
if ( !$this->mConnections[$i]->isOpen() ) {
wfDebug( "Failed to connect to database $i at {$this->mServers[$i]}\n" );
if ( $fail ) {
$this->reportConnectionError( $this->mConnections[$i] );
}
$this->mConnections[$i] = false;
}
return $this->mConnections[$i];
}
function reportConnectionError( &$conn )
{
if ( !is_object( $conn ) ) {
$conn = new Database;
}
if ( $this->mFailFunction ) {
$conn->setFailFunction( $this->mFailFunction );
} else {
$conn->setFailFunction( "wfEmergencyAbort" );
}
$conn->reportConnectionError();
}
function &getWriter()
{
$c =& $this->getConnection( 0 );
if ( !$c->isOpen() ) {
reportConnectionError( $conn );
$c = false;
}
return $c;
}
function force( $i )
{
$this->mForce = $i;
}
}