MediaWiki
REL1_19
|
00001 <?php 00013 abstract class LBFactory { 00014 00018 static $instance; 00019 00024 public static function disableBackend() { 00025 global $wgLBFactoryConf; 00026 self::$instance = new LBFactory_Fake( $wgLBFactoryConf ); 00027 } 00028 00034 static function &singleton() { 00035 if ( is_null( self::$instance ) ) { 00036 global $wgLBFactoryConf; 00037 $class = $wgLBFactoryConf['class']; 00038 self::$instance = new $class( $wgLBFactoryConf ); 00039 } 00040 return self::$instance; 00041 } 00042 00046 static function destroyInstance() { 00047 if ( self::$instance ) { 00048 self::$instance->shutdown(); 00049 self::$instance->forEachLBCallMethod( 'closeAll' ); 00050 self::$instance = null; 00051 } 00052 } 00053 00059 static function setInstance( $instance ) { 00060 self::destroyInstance(); 00061 self::$instance = $instance; 00062 } 00063 00068 abstract function __construct( $conf ); 00069 00077 abstract function newMainLB( $wiki = false ); 00078 00085 abstract function getMainLB( $wiki = false ); 00086 00097 abstract function newExternalLB( $cluster, $wiki = false ); 00098 00107 abstract function &getExternalLB( $cluster, $wiki = false ); 00108 00116 abstract function forEachLB( $callback, $params = array() ); 00117 00122 function shutdown() {} 00123 00129 function forEachLBCallMethod( $methodName, $args = array() ) { 00130 $this->forEachLB( array( $this, 'callMethod' ), array( $methodName, $args ) ); 00131 } 00132 00139 function callMethod( $loadBalancer, $methodName, $args ) { 00140 call_user_func_array( array( $loadBalancer, $methodName ), $args ); 00141 } 00142 00146 function commitMasterChanges() { 00147 $this->forEachLBCallMethod( 'commitMasterChanges' ); 00148 } 00149 } 00150 00154 class LBFactory_Simple extends LBFactory { 00155 00159 var $mainLB; 00160 var $extLBs = array(); 00161 00162 # Chronology protector 00163 var $chronProt; 00164 00165 function __construct( $conf ) { 00166 $this->chronProt = new ChronologyProtector; 00167 } 00168 00173 function newMainLB( $wiki = false ) { 00174 global $wgDBservers, $wgMasterWaitTimeout; 00175 if ( $wgDBservers ) { 00176 $servers = $wgDBservers; 00177 } else { 00178 global $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, $wgDBtype, $wgDebugDumpSql; 00179 $servers = array(array( 00180 'host' => $wgDBserver, 00181 'user' => $wgDBuser, 00182 'password' => $wgDBpassword, 00183 'dbname' => $wgDBname, 00184 'type' => $wgDBtype, 00185 'load' => 1, 00186 'flags' => ($wgDebugDumpSql ? DBO_DEBUG : 0) | DBO_DEFAULT 00187 )); 00188 } 00189 00190 return new LoadBalancer( array( 00191 'servers' => $servers, 00192 'masterWaitTimeout' => $wgMasterWaitTimeout 00193 )); 00194 } 00195 00200 function getMainLB( $wiki = false ) { 00201 if ( !isset( $this->mainLB ) ) { 00202 $this->mainLB = $this->newMainLB( $wiki ); 00203 $this->mainLB->parentInfo( array( 'id' => 'main' ) ); 00204 $this->chronProt->initLB( $this->mainLB ); 00205 } 00206 return $this->mainLB; 00207 } 00208 00215 function newExternalLB( $cluster, $wiki = false ) { 00216 global $wgExternalServers; 00217 if ( !isset( $wgExternalServers[$cluster] ) ) { 00218 throw new MWException( __METHOD__.": Unknown cluster \"$cluster\"" ); 00219 } 00220 return new LoadBalancer( array( 00221 'servers' => $wgExternalServers[$cluster] 00222 )); 00223 } 00224 00230 function &getExternalLB( $cluster, $wiki = false ) { 00231 if ( !isset( $this->extLBs[$cluster] ) ) { 00232 $this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki ); 00233 $this->extLBs[$cluster]->parentInfo( array( 'id' => "ext-$cluster" ) ); 00234 } 00235 return $this->extLBs[$cluster]; 00236 } 00237 00245 function forEachLB( $callback, $params = array() ) { 00246 if ( isset( $this->mainLB ) ) { 00247 call_user_func_array( $callback, array_merge( array( $this->mainLB ), $params ) ); 00248 } 00249 foreach ( $this->extLBs as $lb ) { 00250 call_user_func_array( $callback, array_merge( array( $lb ), $params ) ); 00251 } 00252 } 00253 00254 function shutdown() { 00255 if ( $this->mainLB ) { 00256 $this->chronProt->shutdownLB( $this->mainLB ); 00257 } 00258 $this->chronProt->shutdown(); 00259 $this->commitMasterChanges(); 00260 } 00261 } 00262 00269 class LBFactory_Fake extends LBFactory { 00270 function __construct( $conf ) {} 00271 00272 function newMainLB( $wiki = false) { 00273 throw new DBAccessError; 00274 } 00275 function getMainLB( $wiki = false ) { 00276 throw new DBAccessError; 00277 } 00278 function newExternalLB( $cluster, $wiki = false ) { 00279 throw new DBAccessError; 00280 } 00281 function &getExternalLB( $cluster, $wiki = false ) { 00282 throw new DBAccessError; 00283 } 00284 function forEachLB( $callback, $params = array() ) {} 00285 } 00286 00290 class DBAccessError extends MWException { 00291 function __construct() { 00292 parent::__construct( "Mediawiki tried to access the database via wfGetDB(). This is not allowed." ); 00293 } 00294 } 00295 00300 class ChronologyProtector { 00301 var $startupPos; 00302 var $shutdownPos = array(); 00303 00309 function initLB( $lb ) { 00310 if ( $this->startupPos === null ) { 00311 if ( !empty( $_SESSION[__CLASS__] ) ) { 00312 $this->startupPos = $_SESSION[__CLASS__]; 00313 } 00314 } 00315 if ( !$this->startupPos ) { 00316 return; 00317 } 00318 $masterName = $lb->getServerName( 0 ); 00319 00320 if ( $lb->getServerCount() > 1 && !empty( $this->startupPos[$masterName] ) ) { 00321 $info = $lb->parentInfo(); 00322 $pos = $this->startupPos[$masterName]; 00323 wfDebug( __METHOD__.": LB " . $info['id'] . " waiting for master pos $pos\n" ); 00324 $lb->waitFor( $this->startupPos[$masterName] ); 00325 } 00326 } 00327 00334 function shutdownLB( $lb ) { 00335 // Don't start a session, don't bother with non-replicated setups 00336 if ( strval( session_id() ) == '' || $lb->getServerCount() <= 1 ) { 00337 return; 00338 } 00339 $masterName = $lb->getServerName( 0 ); 00340 if ( isset( $this->shutdownPos[$masterName] ) ) { 00341 // Already done 00342 return; 00343 } 00344 // Only save the position if writes have been done on the connection 00345 $db = $lb->getAnyOpenConnection( 0 ); 00346 $info = $lb->parentInfo(); 00347 if ( !$db || !$db->doneWrites() ) { 00348 wfDebug( __METHOD__.": LB {$info['id']}, no writes done\n" ); 00349 return; 00350 } 00351 $pos = $db->getMasterPos(); 00352 wfDebug( __METHOD__.": LB {$info['id']} has master pos $pos\n" ); 00353 $this->shutdownPos[$masterName] = $pos; 00354 } 00355 00360 function shutdown() { 00361 if ( session_id() != '' && count( $this->shutdownPos ) ) { 00362 wfDebug( __METHOD__.": saving master pos for " . 00363 count( $this->shutdownPos ) . " master(s)\n" ); 00364 $_SESSION[__CLASS__] = $this->shutdownPos; 00365 } 00366 } 00367 }