2 # Database load balancing object
4 # Valid database indexes
5 # Operation-based indexes
6 define( "DB_READ", -1 ); # Read from the slave (or only server)
7 define( "DB_WRITE", -2 ); # Write to master (or only server)
8 define( "DB_LAST", -3 ); # Whatever database was used last
11 # ***NOT USED YET, EXPERIMENTAL***
12 # These may be defined in $wgDBservers. If they aren't, the default reader or writer will be used
13 # Even numbers are always readers, odd numbers are writers
14 define( "DB_TASK_FIRST", 1000 ); # First in list
15 define( "DB_SEARCH_R", 1000 ); # Search read
16 define( "DB_SEARCH_W", 1001 ); # Search write
17 define( "DB_ASKSQL_R", 1002 ); # Special:Asksql read
18 define( "DB_WATCHLIST_R", 1004 ); # Watchlist read
19 define( "DB_TASK_LAST", 1004) ; # Last in list
22 /* private */ var $mServers, $mConnections, $mLoads;
23 /* private */ var $mUser, $mPassword, $mDbName, $mFailFunction;
24 /* private */ var $mForce, $mReadIndex, $mLastConn;
26 function LoadBalancer()
28 $this->mServers
= array();
29 $this->mLoads
= array();
30 $this->mConnections
= array();
32 $this->mPassword
= false;
33 $this->mDbName
= false;
34 $this->mFailFunction
= false;
35 $this->mReadIndex
= -1;
37 $this->mLastConn
= false;
40 function newFromParams( $servers, $loads, $user, $password, $dbName, $failFunction = false )
42 $lb = new LoadBalancer
;
43 $lb->initialise( $servers, $loads, $user, $password, $dbName, $failFunction = false );
47 function initialise( $servers, $loads, $user, $password, $dbName, $failFunction = false )
49 $this->mServers
= $servers;
50 $this->mLoads
= $loads;
52 $this->mPassword
= $password;
53 $this->mDbName
= $dbName;
54 $this->mFailFunction
= $failFunction;
55 $this->mReadIndex
= -1;
56 $this->mWriteIndex
= -1;
58 $this->mConnections
= array();
59 $this->mLastConn
= false;
63 # Given an array of non-normalised probabilities, this function will select
64 # an element and return the appropriate key
65 function pickRandom( $weights )
67 if ( !is_array( $weights ) ||
count( $weights ) == 0 ) {
72 foreach ( $weights as $w ) {
75 $max = mt_getrandmax();
76 $rand = mt_rand(0, $max) / $max * $sum;
79 foreach ( $weights as $i => $w ) {
81 if ( $sum >= $rand ) {
90 if ( $this->mForce
>= 0 ) {
91 $conn =& $this->getConnection( $this->mForce
);
93 if ( $this->mReadIndex
>= 0 ) {
94 $conn =& $this->getConnection( $this->mReadIndex
);
96 # $loads is $this->mLoads except with elements knocked out if they
98 $loads = $this->mLoads
;
100 $i = $this->pickRandom( $loads );
101 if ( $i !== false ) {
102 wfDebug( "Using reader #$i: {$this->mServers[$i]}\n" );
104 $conn =& $this->getConnection( $i );
105 if ( !$conn->isOpen() ) {
109 } while ( $i !== false && !$conn->isOpen() );
110 if ( $conn->isOpen() ) {
111 $this->mReadIndex
= $i;
115 if ( $conn === false ||
!$conn->isOpen() ) {
116 $this->reportConnectionError( $conn );
122 function &getConnection( $i, $fail = false )
126 if ( $i >= DB_TASK_FIRST && $i < DB_TASK_LAST ) {
128 # Odd index use writer
131 # Even index use reader
136 # Operation-based index
137 # Note, getReader() and getWriter() will re-enter this function
138 if ( $i == DB_READ
) {
139 $this->mLastConn
=& $this->getReader();
140 } elseif ( $i == DB_WRITE
) {
141 $this->mLastConn
=& $this->getWriter();
142 } elseif ( $i == DB_LAST
) {
143 # Just use $this->mLastConn, which should already be set
144 if ( $this->mLastConn
=== false ) {
145 # Oh dear, not set, best to use the writer for safety
146 $this->mLastConn
=& $this->getWriter();
150 if ( !array_key_exists( $i, $this->mConnections
) ||
!$this->mConnections
[$i]->isOpen() ) {
151 $this->mConnections
[$i] = Database
::newFromParams( $this->mServers
[$i], $this->mUser
,
152 $this->mPassword
, $this->mDbName
, 1 );
154 if ( !$this->mConnections
[$i]->isOpen() ) {
155 wfDebug( "Failed to connect to database $i at {$this->mServers[$i]}\n" );
157 $this->reportConnectionError( $this->mConnections
[$i] );
159 $this->mConnections
[$i] = false;
161 $this->mLastConn
=& $this->mConnections
[$i];
163 return $this->mLastConn
;
166 function reportConnectionError( &$conn )
168 if ( !is_object( $conn ) ) {
169 $conn = new Database
;
171 if ( $this->mFailFunction
) {
172 $conn->setFailFunction( $this->mFailFunction
);
174 $conn->setFailFunction( "wfEmergencyAbort" );
176 $conn->reportConnectionError();
179 function &getWriter()
181 $c =& $this->getConnection( 0 );
182 if ( $c === false ||
!$c->isOpen() ) {
183 $this->reportConnectionError( $c );
194 function haveIndex( $i )
196 return array_key_exists( $i, $this->mServers
);