MediaWiki
REL1_20
|
00001 <?php 00028 abstract class LBFactory { 00029 00033 static $instance; 00034 00039 public static function disableBackend() { 00040 global $wgLBFactoryConf; 00041 self::$instance = new LBFactory_Fake( $wgLBFactoryConf ); 00042 } 00043 00049 static function &singleton() { 00050 if ( is_null( self::$instance ) ) { 00051 global $wgLBFactoryConf; 00052 $class = $wgLBFactoryConf['class']; 00053 self::$instance = new $class( $wgLBFactoryConf ); 00054 } 00055 return self::$instance; 00056 } 00057 00061 static function destroyInstance() { 00062 if ( self::$instance ) { 00063 self::$instance->shutdown(); 00064 self::$instance->forEachLBCallMethod( 'closeAll' ); 00065 self::$instance = null; 00066 } 00067 } 00068 00074 static function setInstance( $instance ) { 00075 self::destroyInstance(); 00076 self::$instance = $instance; 00077 } 00078 00083 abstract function __construct( $conf ); 00084 00092 abstract function newMainLB( $wiki = false ); 00093 00100 abstract function getMainLB( $wiki = false ); 00101 00112 abstract function newExternalLB( $cluster, $wiki = false ); 00113 00122 abstract function &getExternalLB( $cluster, $wiki = false ); 00123 00131 abstract function forEachLB( $callback, $params = array() ); 00132 00137 function shutdown() {} 00138 00144 function forEachLBCallMethod( $methodName, $args = array() ) { 00145 $this->forEachLB( array( $this, 'callMethod' ), array( $methodName, $args ) ); 00146 } 00147 00154 function callMethod( $loadBalancer, $methodName, $args ) { 00155 call_user_func_array( array( $loadBalancer, $methodName ), $args ); 00156 } 00157 00161 function commitMasterChanges() { 00162 $this->forEachLBCallMethod( 'commitMasterChanges' ); 00163 } 00164 } 00165 00169 class LBFactory_Simple extends LBFactory { 00170 00174 var $mainLB; 00175 var $extLBs = array(); 00176 00177 # Chronology protector 00178 var $chronProt; 00179 00180 function __construct( $conf ) { 00181 $this->chronProt = new ChronologyProtector; 00182 } 00183 00188 function newMainLB( $wiki = false ) { 00189 global $wgDBservers, $wgMasterWaitTimeout; 00190 if ( $wgDBservers ) { 00191 $servers = $wgDBservers; 00192 } else { 00193 global $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, $wgDBtype, $wgDebugDumpSql; 00194 global $wgDBssl, $wgDBcompress; 00195 00196 $flags = ( $wgDebugDumpSql ? DBO_DEBUG : 0 ) | DBO_DEFAULT; 00197 if ( $wgDBssl ) { 00198 $flags |= DBO_SSL; 00199 } 00200 if ( $wgDBcompress ) { 00201 $flags |= DBO_COMPRESS; 00202 } 00203 00204 $servers = array(array( 00205 'host' => $wgDBserver, 00206 'user' => $wgDBuser, 00207 'password' => $wgDBpassword, 00208 'dbname' => $wgDBname, 00209 'type' => $wgDBtype, 00210 'load' => 1, 00211 'flags' => $flags 00212 )); 00213 } 00214 00215 return new LoadBalancer( array( 00216 'servers' => $servers, 00217 'masterWaitTimeout' => $wgMasterWaitTimeout 00218 )); 00219 } 00220 00225 function getMainLB( $wiki = false ) { 00226 if ( !isset( $this->mainLB ) ) { 00227 $this->mainLB = $this->newMainLB( $wiki ); 00228 $this->mainLB->parentInfo( array( 'id' => 'main' ) ); 00229 $this->chronProt->initLB( $this->mainLB ); 00230 } 00231 return $this->mainLB; 00232 } 00233 00240 function newExternalLB( $cluster, $wiki = false ) { 00241 global $wgExternalServers; 00242 if ( !isset( $wgExternalServers[$cluster] ) ) { 00243 throw new MWException( __METHOD__.": Unknown cluster \"$cluster\"" ); 00244 } 00245 return new LoadBalancer( array( 00246 'servers' => $wgExternalServers[$cluster] 00247 )); 00248 } 00249 00255 function &getExternalLB( $cluster, $wiki = false ) { 00256 if ( !isset( $this->extLBs[$cluster] ) ) { 00257 $this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki ); 00258 $this->extLBs[$cluster]->parentInfo( array( 'id' => "ext-$cluster" ) ); 00259 } 00260 return $this->extLBs[$cluster]; 00261 } 00262 00270 function forEachLB( $callback, $params = array() ) { 00271 if ( isset( $this->mainLB ) ) { 00272 call_user_func_array( $callback, array_merge( array( $this->mainLB ), $params ) ); 00273 } 00274 foreach ( $this->extLBs as $lb ) { 00275 call_user_func_array( $callback, array_merge( array( $lb ), $params ) ); 00276 } 00277 } 00278 00279 function shutdown() { 00280 if ( $this->mainLB ) { 00281 $this->chronProt->shutdownLB( $this->mainLB ); 00282 } 00283 $this->chronProt->shutdown(); 00284 $this->commitMasterChanges(); 00285 } 00286 } 00287 00294 class LBFactory_Fake extends LBFactory { 00295 function __construct( $conf ) {} 00296 00297 function newMainLB( $wiki = false) { 00298 throw new DBAccessError; 00299 } 00300 function getMainLB( $wiki = false ) { 00301 throw new DBAccessError; 00302 } 00303 function newExternalLB( $cluster, $wiki = false ) { 00304 throw new DBAccessError; 00305 } 00306 function &getExternalLB( $cluster, $wiki = false ) { 00307 throw new DBAccessError; 00308 } 00309 function forEachLB( $callback, $params = array() ) {} 00310 } 00311 00315 class DBAccessError extends MWException { 00316 function __construct() { 00317 parent::__construct( "Mediawiki tried to access the database via wfGetDB(). This is not allowed." ); 00318 } 00319 } 00320 00325 class ChronologyProtector { 00326 var $startupPos; 00327 var $shutdownPos = array(); 00328 00334 function initLB( $lb ) { 00335 if ( $this->startupPos === null ) { 00336 if ( !empty( $_SESSION[__CLASS__] ) ) { 00337 $this->startupPos = $_SESSION[__CLASS__]; 00338 } 00339 } 00340 if ( !$this->startupPos ) { 00341 return; 00342 } 00343 $masterName = $lb->getServerName( 0 ); 00344 00345 if ( $lb->getServerCount() > 1 && !empty( $this->startupPos[$masterName] ) ) { 00346 $info = $lb->parentInfo(); 00347 $pos = $this->startupPos[$masterName]; 00348 wfDebug( __METHOD__.": LB " . $info['id'] . " waiting for master pos $pos\n" ); 00349 $lb->waitFor( $this->startupPos[$masterName] ); 00350 } 00351 } 00352 00359 function shutdownLB( $lb ) { 00360 // Don't start a session, don't bother with non-replicated setups 00361 if ( strval( session_id() ) == '' || $lb->getServerCount() <= 1 ) { 00362 return; 00363 } 00364 $masterName = $lb->getServerName( 0 ); 00365 if ( isset( $this->shutdownPos[$masterName] ) ) { 00366 // Already done 00367 return; 00368 } 00369 // Only save the position if writes have been done on the connection 00370 $db = $lb->getAnyOpenConnection( 0 ); 00371 $info = $lb->parentInfo(); 00372 if ( !$db || !$db->doneWrites() ) { 00373 wfDebug( __METHOD__.": LB {$info['id']}, no writes done\n" ); 00374 return; 00375 } 00376 $pos = $db->getMasterPos(); 00377 wfDebug( __METHOD__.": LB {$info['id']} has master pos $pos\n" ); 00378 $this->shutdownPos[$masterName] = $pos; 00379 } 00380 00385 function shutdown() { 00386 if ( session_id() != '' && count( $this->shutdownPos ) ) { 00387 wfDebug( __METHOD__.": saving master pos for " . 00388 count( $this->shutdownPos ) . " master(s)\n" ); 00389 $_SESSION[__CLASS__] = $this->shutdownPos; 00390 } 00391 } 00392 }