MediaWiki
REL1_20
|
00001 <?php 00042 abstract class PoolCounter { 00043 00044 /* Return codes */ 00045 const LOCKED = 1; /* Lock acquired */ 00046 const RELEASED = 2; /* Lock released */ 00047 const DONE = 3; /* Another worker did the work for you */ 00048 00049 const ERROR = -1; /* Indeterminate error */ 00050 const NOT_LOCKED = -2; /* Called release() with no lock held */ 00051 const QUEUE_FULL = -3; /* There are already maxqueue workers on this lock */ 00052 const TIMEOUT = -4; /* Timeout exceeded */ 00053 const LOCK_HELD = -5; /* Cannot acquire another lock while you have one lock held */ 00054 00060 abstract function acquireForMe(); 00061 00068 abstract function acquireForAnyone(); 00069 00077 abstract function release(); 00078 00087 protected $key, $workers, $maxqueue, $timeout; 00088 00097 public static function factory( $type, $key ) { 00098 global $wgPoolCounterConf; 00099 if ( !isset( $wgPoolCounterConf[$type] ) ) { 00100 return new PoolCounter_Stub; 00101 } 00102 $conf = $wgPoolCounterConf[$type]; 00103 $class = $conf['class']; 00104 00105 return new $class( $conf, $type, $key ); 00106 } 00107 00108 protected function __construct( $conf, $type, $key ) { 00109 $this->key = $key; 00110 $this->workers = $conf['workers']; 00111 $this->maxqueue = $conf['maxqueue']; 00112 $this->timeout = $conf['timeout']; 00113 } 00114 } 00115 00116 class PoolCounter_Stub extends PoolCounter { 00117 00121 function acquireForMe() { 00122 return Status::newGood( PoolCounter::LOCKED ); 00123 } 00124 00128 function acquireForAnyone() { 00129 return Status::newGood( PoolCounter::LOCKED ); 00130 } 00131 00135 function release() { 00136 return Status::newGood( PoolCounter::RELEASED ); 00137 } 00138 00139 public function __construct() { 00140 /* No parameters needed */ 00141 } 00142 } 00143 00147 abstract class PoolCounterWork { 00148 protected $cacheable = false; //Does this override getCachedWork() ? 00149 00153 abstract function doWork(); 00154 00159 function getCachedWork() { 00160 return false; 00161 } 00162 00168 function fallback() { 00169 return false; 00170 } 00171 00176 function error( $status ) { 00177 return false; 00178 } 00179 00185 function logError( $status ) { 00186 wfDebugLog( 'poolcounter', $status->getWikiText() ); 00187 } 00188 00194 function execute( $skipcache = false ) { 00195 if ( $this->cacheable && !$skipcache ) { 00196 $status = $this->poolCounter->acquireForAnyone(); 00197 } else { 00198 $status = $this->poolCounter->acquireForMe(); 00199 } 00200 00201 if ( !$status->isOK() ) { 00202 // Respond gracefully to complete server breakage: just log it and do the work 00203 $this->logError( $status ); 00204 return $this->doWork(); 00205 } 00206 00207 switch ( $status->value ) { 00208 case PoolCounter::LOCKED: 00209 $result = $this->doWork(); 00210 $this->poolCounter->release(); 00211 return $result; 00212 00213 case PoolCounter::DONE: 00214 $result = $this->getCachedWork(); 00215 if ( $result === false ) { 00216 /* That someone else work didn't serve us. 00217 * Acquire the lock for me 00218 */ 00219 return $this->execute( true ); 00220 } 00221 return $result; 00222 00223 case PoolCounter::QUEUE_FULL: 00224 case PoolCounter::TIMEOUT: 00225 $result = $this->fallback(); 00226 00227 if ( $result !== false ) { 00228 return $result; 00229 } 00230 /* no break */ 00231 00232 /* These two cases should never be hit... */ 00233 case PoolCounter::ERROR: 00234 default: 00235 $errors = array( PoolCounter::QUEUE_FULL => 'pool-queuefull', PoolCounter::TIMEOUT => 'pool-timeout' ); 00236 00237 $status = Status::newFatal( isset( $errors[$status->value] ) ? $errors[$status->value] : 'pool-errorunknown' ); 00238 $this->logError( $status ); 00239 return $this->error( $status ); 00240 } 00241 } 00242 00243 function __construct( $type, $key ) { 00244 $this->poolCounter = PoolCounter::factory( $type, $key ); 00245 } 00246 }