MediaWiki
REL1_24
|
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 }