MediaWiki  REL1_22
LoadMonitor.php
Go to the documentation of this file.
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 }