Fix for compatibility with short_open_tag = Off
[lhc/web/wiklou.git] / includes / LoadBalancer.php
1 <?php
2 # Database load balancing object
3
4 class LoadBalancer {
5 /* private */ var $mServers, $mConnections, $mLoads;
6 /* private */ var $mUser, $mPassword, $mDbName, $mFailFunction;
7 /* private */ var $mForce, $mReadIndex;
8
9 function LoadBalancer()
10 {
11 $this->mServers = array();
12 $this->mLoads = array();
13 $this->mConnections = array();
14 $this->mUser = false;
15 $this->mPassword = false;
16 $this->mDbName = false;
17 $this->mFailFunction = false;
18 $this->mReadIndex = -1;
19 $this->mForce = -1;
20 }
21
22 function newFromParams( $servers, $loads, $user, $password, $dbName, $failFunction = false )
23 {
24 $lb = new LoadBalancer;
25 $lb->initialise( $servers, $loads, $user, $password, $dbName, $failFunction = false );
26 return $lb;
27 }
28
29 function initialise( $servers, $loads, $user, $password, $dbName, $failFunction = false )
30 {
31 $this->mServers = $servers;
32 $this->mLoads = $loads;
33 $this->mUser = $user;
34 $this->mPassword = $password;
35 $this->mDbName = $dbName;
36 $this->mFailFunction = $failFunction;
37 $this->mReadIndex = -1;
38 $this->mWriteIndex = -1;
39 $this->mForce = -1;
40 $this->mConnections = array();
41 wfSeedRandom();
42 }
43
44 # Given an array of non-normalised probabilities, this function will select
45 # an element and return the appropriate key
46 function pickRandom( $weights )
47 {
48 if ( !is_array( $weights ) || count( $weights ) == 0 ) {
49 return false;
50 }
51
52 $sum = 0;
53 foreach ( $weights as $w ) {
54 $sum += $w;
55 }
56 $rand = mt_rand() / RAND_MAX * $sum;
57
58 $sum = 0;
59 foreach ( $weights as $i => $w ) {
60 $sum += $w;
61 if ( $sum >= $rand ) {
62 break;
63 }
64 }
65 return $i;
66 }
67
68 function &getReader()
69 {
70 if ( $this->mForce >= 0 ) {
71 $conn =& $this->getConnection( $this->mForce );
72 } else {
73 if ( $this->mReadIndex >= 0 ) {
74 $conn =& $this->getConnection( $this->mReadIndex );
75 } else {
76 # $loads is $this->mLoads except with elements knocked out if they
77 # don't work
78 $loads = $this->mLoads;
79 do {
80 $i = pickRandom( $loads );
81 if ( $i !== false ) {
82 $conn =& $this->getConnection( $i );
83 if ( !$conn->isOpen() ) {
84 unset( $loads[$i] );
85 }
86 }
87 } while ( $i !== false && !$conn->isOpen() );
88 if ( $conn->isOpen() ) {
89 $this->mReadIndex = $i;
90 }
91 }
92 }
93 if ( $conn === false || !$conn->isOpen() ) {
94 $this->reportConnectionError( $conn );
95 $conn = false;
96 }
97 return $conn;
98 }
99
100 function &getConnection( $i, $fail = false )
101 {
102 if ( !array_key_exists( $i, $this->mConnections) || !$this->mConnections[$i]->isOpen() ) {
103 $this->mConnections[$i] = Database::newFromParams( $this->mServers[$i], $this->mUser,
104 $this->mPassword, $this->mDbName, 1 );
105 }
106 if ( !$this->mConnections[$i]->isOpen() ) {
107 wfDebug( "Failed to connect to database $i at {$this->mServers[$i]}\n" );
108 if ( $fail ) {
109 $this->reportConnectionError( $this->mConnections[$i] );
110 }
111 $this->mConnections[$i] = false;
112 }
113 return $this->mConnections[$i];
114 }
115
116 function reportConnectionError( &$conn )
117 {
118 if ( !is_object( $conn ) ) {
119 $conn = new Database;
120 }
121 if ( $this->mFailFunction ) {
122 $conn->setFailFunction( $this->mFailFunction );
123 } else {
124 $conn->setFailFunction( "wfEmergencyAbort" );
125 }
126 $conn->reportConnectionError();
127 }
128
129 function &getWriter()
130 {
131 $c =& $this->getConnection( 0 );
132 if ( !$c->isOpen() ) {
133 reportConnectionError( $conn );
134 $c = false;
135 }
136 return $c;
137 }
138
139 function force( $i )
140 {
141 $this->mForce = $i;
142 }
143 }