MediaWiki
REL1_22
|
00001 <?php 00029 interface LoadMonitor { 00035 function __construct( $parent ); 00036 00043 function scaleLoads( &$loads, $group = false, $wiki = false ); 00044 00061 function postConnectionBackoff( $conn, $threshold ); 00062 00071 function getLagTimes( $serverIndexes, $wiki ); 00072 } 00073 00074 class LoadMonitor_Null implements LoadMonitor { 00075 function __construct( $parent ) { 00076 } 00077 00078 function scaleLoads( &$loads, $group = false, $wiki = false ) { 00079 } 00080 00081 function postConnectionBackoff( $conn, $threshold ) { 00082 } 00083 00089 function getLagTimes( $serverIndexes, $wiki ) { 00090 return array_fill_keys( $serverIndexes, 0 ); 00091 } 00092 } 00093 00100 class LoadMonitor_MySQL implements LoadMonitor { 00101 00105 var $parent; 00106 00110 function __construct( $parent ) { 00111 $this->parent = $parent; 00112 } 00113 00119 function scaleLoads( &$loads, $group = false, $wiki = false ) { 00120 } 00121 00127 function getLagTimes( $serverIndexes, $wiki ) { 00128 if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) { 00129 // Single server only, just return zero without caching 00130 return array( 0 => 0 ); 00131 } 00132 00133 wfProfileIn( __METHOD__ ); 00134 $expiry = 5; 00135 $requestRate = 10; 00136 00137 global $wgMemc; 00138 if ( empty( $wgMemc ) ) { 00139 $wgMemc = wfGetMainCache(); 00140 } 00141 00142 $masterName = $this->parent->getServerName( 0 ); 00143 $memcKey = wfMemcKey( 'lag_times', $masterName ); 00144 $times = $wgMemc->get( $memcKey ); 00145 if ( is_array( $times ) ) { 00146 # Randomly recache with probability rising over $expiry 00147 $elapsed = time() - $times['timestamp']; 00148 $chance = max( 0, ( $expiry - $elapsed ) * $requestRate ); 00149 if ( mt_rand( 0, $chance ) != 0 ) { 00150 unset( $times['timestamp'] ); // hide from caller 00151 wfProfileOut( __METHOD__ ); 00152 return $times; 00153 } 00154 wfIncrStats( 'lag_cache_miss_expired' ); 00155 } else { 00156 wfIncrStats( 'lag_cache_miss_absent' ); 00157 } 00158 00159 # Cache key missing or expired 00160 if ( $wgMemc->add( "$memcKey:lock", 1, 10 ) ) { 00161 # Let this process alone update the cache value 00162 $unlocker = new ScopedCallback( function() use ( $wgMemc, $memcKey ) { 00163 $wgMemc->delete( $memcKey ); 00164 } ); 00165 } elseif ( is_array( $times ) ) { 00166 # Could not acquire lock but an old cache exists, so use it 00167 unset( $times['timestamp'] ); // hide from caller 00168 wfProfileOut( __METHOD__ ); 00169 return $times; 00170 } 00171 00172 $times = array(); 00173 foreach ( $serverIndexes as $i ) { 00174 if ( $i == 0 ) { # Master 00175 $times[$i] = 0; 00176 } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) { 00177 $times[$i] = $conn->getLag(); 00178 } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) { 00179 $times[$i] = $conn->getLag(); 00180 } 00181 } 00182 00183 # Add a timestamp key so we know when it was cached 00184 $times['timestamp'] = time(); 00185 $wgMemc->set( $memcKey, $times, $expiry + 10 ); 00186 unset( $times['timestamp'] ); // hide from caller 00187 00188 wfProfileOut( __METHOD__ ); 00189 return $times; 00190 } 00191 00197 function postConnectionBackoff( $conn, $threshold ) { 00198 if ( !$threshold ) { 00199 return 0; 00200 } 00201 $status = $conn->getMysqlStatus( "Thread%" ); 00202 if ( $status['Threads_running'] > $threshold ) { 00203 $server = $conn->getProperty( 'mServer' ); 00204 wfLogDBError( "LB backoff from $server - Threads_running = {$status['Threads_running']}\n" ); 00205 return $status['Threads_connected']; 00206 } else { 00207 return 0; 00208 } 00209 } 00210 }