MediaWiki  REL1_24
LoadMonitor.php
Go to the documentation of this file.
00001 <?php
00029 interface LoadMonitor {
00035     public function __construct( $parent );
00036 
00043     public function scaleLoads( &$loads, $group = false, $wiki = false );
00044 
00053     public function getLagTimes( $serverIndexes, $wiki );
00054 }
00055 
00056 class LoadMonitorNull implements LoadMonitor {
00057     public function __construct( $parent ) {
00058     }
00059 
00060     public function scaleLoads( &$loads, $group = false, $wiki = false ) {
00061     }
00062 
00063     public function getLagTimes( $serverIndexes, $wiki ) {
00064         return array_fill_keys( $serverIndexes, 0 );
00065     }
00066 }
00067 
00074 class LoadMonitorMySQL implements LoadMonitor {
00076     public $parent;
00078     protected $cache;
00079 
00080     public function __construct( $parent ) {
00081         global $wgMemc;
00082 
00083         $this->parent = $parent;
00084         $this->cache = $wgMemc ?: wfGetMainCache();
00085     }
00086 
00087     public function scaleLoads( &$loads, $group = false, $wiki = false ) {
00088     }
00089 
00090     public function getLagTimes( $serverIndexes, $wiki ) {
00091         if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
00092             // Single server only, just return zero without caching
00093             return array( 0 => 0 );
00094         }
00095 
00096         $section = new ProfileSection( __METHOD__ );
00097 
00098         $expiry = 5;
00099         $requestRate = 10;
00100 
00101         $cache = $this->cache;
00102         $masterName = $this->parent->getServerName( 0 );
00103         $memcKey = wfMemcKey( 'lag_times', $masterName );
00104         $times = $cache->get( $memcKey );
00105         if ( is_array( $times ) ) {
00106             # Randomly recache with probability rising over $expiry
00107             $elapsed = time() - $times['timestamp'];
00108             $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
00109             if ( mt_rand( 0, $chance ) != 0 ) {
00110                 unset( $times['timestamp'] ); // hide from caller
00111 
00112                 return $times;
00113             }
00114             wfIncrStats( 'lag_cache_miss_expired' );
00115         } else {
00116             wfIncrStats( 'lag_cache_miss_absent' );
00117         }
00118 
00119         # Cache key missing or expired
00120         if ( $cache->add( "$memcKey:lock", 1, 10 ) ) {
00121             # Let this process alone update the cache value
00122             $unlocker = new ScopedCallback( function () use ( $cache, $memcKey ) {
00123                 $cache->delete( $memcKey );
00124             } );
00125         } elseif ( is_array( $times ) ) {
00126             # Could not acquire lock but an old cache exists, so use it
00127             unset( $times['timestamp'] ); // hide from caller
00128 
00129             return $times;
00130         }
00131 
00132         $times = array();
00133         foreach ( $serverIndexes as $i ) {
00134             if ( $i == 0 ) { # Master
00135                 $times[$i] = 0;
00136             } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
00137                 $times[$i] = $conn->getLag();
00138             } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
00139                 $times[$i] = $conn->getLag();
00140                 // Close the connection to avoid sleeper connections piling up.
00141                 // Note that the caller will pick one of these DBs and reconnect,
00142                 // which is slightly inefficient, but this only matters for the lag
00143                 // time cache miss cache, which is far less common that cache hits.
00144                 $this->parent->closeConnection( $conn );
00145             }
00146         }
00147 
00148         # Add a timestamp key so we know when it was cached
00149         $times['timestamp'] = time();
00150         $cache->set( $memcKey, $times, $expiry + 10 );
00151         unset( $times['timestamp'] ); // hide from caller
00152 
00153         return $times;
00154     }
00155 }