MediaWiki
REL1_22
|
00001 <?php 00042 abstract class PoolCounter { 00043 /* Return codes */ 00044 const LOCKED = 1; /* Lock acquired */ 00045 const RELEASED = 2; /* Lock released */ 00046 const DONE = 3; /* Another worker did the work for you */ 00047 00048 const ERROR = -1; /* Indeterminate error */ 00049 const NOT_LOCKED = -2; /* Called release() with no lock held */ 00050 const QUEUE_FULL = -3; /* There are already maxqueue workers on this lock */ 00051 const TIMEOUT = -4; /* Timeout exceeded */ 00052 const LOCK_HELD = -5; /* Cannot acquire another lock while you have one lock held */ 00053 00055 protected $key; 00057 protected $workers; 00059 protected $maxqueue; 00061 protected $timeout; 00062 00068 protected function __construct( $conf, $type, $key ) { 00069 $this->key = $key; 00070 $this->workers = $conf['workers']; 00071 $this->maxqueue = $conf['maxqueue']; 00072 $this->timeout = $conf['timeout']; 00073 } 00074 00083 public static function factory( $type, $key ) { 00084 global $wgPoolCounterConf; 00085 if ( !isset( $wgPoolCounterConf[$type] ) ) { 00086 return new PoolCounter_Stub; 00087 } 00088 $conf = $wgPoolCounterConf[$type]; 00089 $class = $conf['class']; 00090 00091 return new $class( $conf, $type, $key ); 00092 } 00093 00099 abstract public function acquireForMe(); 00100 00107 abstract public function acquireForAnyone(); 00108 00116 abstract public function release(); 00117 } 00118 00119 class PoolCounter_Stub extends PoolCounter { 00120 public function __construct() { 00121 /* No parameters needed */ 00122 } 00123 00124 public function acquireForMe() { 00125 return Status::newGood( PoolCounter::LOCKED ); 00126 } 00127 00128 public function acquireForAnyone() { 00129 return Status::newGood( PoolCounter::LOCKED ); 00130 } 00131 00132 public function release() { 00133 return Status::newGood( PoolCounter::RELEASED ); 00134 } 00135 } 00136 00140 abstract class PoolCounterWork { 00141 protected $cacheable = false; //Does this override getCachedWork() ? 00142 00147 public function __construct( $type, $key ) { 00148 $this->poolCounter = PoolCounter::factory( $type, $key ); 00149 } 00150 00155 abstract public function doWork(); 00156 00161 public function getCachedWork() { 00162 return false; 00163 } 00164 00170 public function fallback() { 00171 return false; 00172 } 00173 00178 function error( $status ) { 00179 return false; 00180 } 00181 00188 function logError( $status ) { 00189 wfDebugLog( 'poolcounter', $status->getWikiText() ); 00190 } 00191 00207 public function execute( $skipcache = false ) { 00208 if ( $this->cacheable && !$skipcache ) { 00209 $status = $this->poolCounter->acquireForAnyone(); 00210 } else { 00211 $status = $this->poolCounter->acquireForMe(); 00212 } 00213 00214 if ( !$status->isOK() ) { 00215 // Respond gracefully to complete server breakage: just log it and do the work 00216 $this->logError( $status ); 00217 return $this->doWork(); 00218 } 00219 00220 switch ( $status->value ) { 00221 case PoolCounter::LOCKED: 00222 $result = $this->doWork(); 00223 $this->poolCounter->release(); 00224 return $result; 00225 00226 case PoolCounter::DONE: 00227 $result = $this->getCachedWork(); 00228 if ( $result === false ) { 00229 /* That someone else work didn't serve us. 00230 * Acquire the lock for me 00231 */ 00232 return $this->execute( true ); 00233 } 00234 return $result; 00235 00236 case PoolCounter::QUEUE_FULL: 00237 case PoolCounter::TIMEOUT: 00238 $result = $this->fallback(); 00239 00240 if ( $result !== false ) { 00241 return $result; 00242 } 00243 /* no break */ 00244 00245 /* These two cases should never be hit... */ 00246 case PoolCounter::ERROR: 00247 default: 00248 $errors = array( 00249 PoolCounter::QUEUE_FULL => 'pool-queuefull', 00250 PoolCounter::TIMEOUT => 'pool-timeout' ); 00251 00252 $status = Status::newFatal( isset( $errors[$status->value] ) 00253 ? $errors[$status->value] 00254 : 'pool-errorunknown' ); 00255 $this->logError( $status ); 00256 return $this->error( $status ); 00257 } 00258 } 00259 } 00260 00265 class PoolCounterWorkViaCallback extends PoolCounterWork { 00267 protected $doWork; 00269 protected $doCachedWork; 00271 protected $fallback; 00273 protected $error; 00274 00289 public function __construct( $type, $key, array $callbacks ) { 00290 parent::__construct( $type, $key ); 00291 foreach ( array( 'doWork', 'doCachedWork', 'fallback', 'error' ) as $name ) { 00292 if ( isset( $callbacks[$name] ) ) { 00293 if ( !is_callable( $callbacks[$name] ) ) { 00294 throw new MWException( "Invalid callback provided for '$name' function." ); 00295 } 00296 $this->$name = $callbacks[$name]; 00297 } 00298 } 00299 if ( !isset( $this->doWork ) ) { 00300 throw new MWException( "No callback provided for 'doWork' function." ); 00301 } 00302 $this->cacheable = isset( $this->doCachedWork ); 00303 } 00304 00305 public function doWork() { 00306 return call_user_func_array( $this->doWork, array() ); 00307 } 00308 00309 public function getCachedWork() { 00310 if ( $this->doCachedWork ) { 00311 return call_user_func_array( $this->doCachedWork, array() ); 00312 } 00313 return false; 00314 } 00315 00316 function fallback() { 00317 if ( $this->fallback ) { 00318 return call_user_func_array( $this->fallback, array() ); 00319 } 00320 return false; 00321 } 00322 00323 function error( $status ) { 00324 if ( $this->error ) { 00325 return call_user_func_array( $this->error, array( $status ) ); 00326 } 00327 return false; 00328 } 00329 }