MediaWiki  REL1_19
PoolCounter.php
Go to the documentation of this file.
00001 <?php
00002 
00021 abstract class PoolCounter {
00022 
00023         /* Return codes */
00024         const LOCKED   = 1; /* Lock acquired */
00025         const RELEASED = 2; /* Lock released */
00026         const DONE     = 3; /* Another worker did the work for you */
00027 
00028         const ERROR      = -1; /* Indeterminate error */
00029         const NOT_LOCKED = -2; /* Called release() with no lock held */
00030         const QUEUE_FULL = -3; /* There are already maxqueue workers on this lock */
00031         const TIMEOUT    = -4; /* Timeout exceeded */
00032         const LOCK_HELD  = -5; /* Cannot acquire another lock while you have one lock held */
00033 
00039         abstract function acquireForMe();
00040 
00047         abstract function acquireForAnyone();
00048 
00056         abstract function release();
00057 
00066         protected $key, $workers, $maxqueue, $timeout;
00067 
00076         public static function factory( $type, $key ) {
00077                 global $wgPoolCounterConf;
00078                 if ( !isset( $wgPoolCounterConf[$type] ) ) {
00079                         return new PoolCounter_Stub;
00080                 }
00081                 $conf = $wgPoolCounterConf[$type];
00082                 $class = $conf['class'];
00083 
00084                 return new $class( $conf, $type, $key );
00085         }
00086 
00087         protected function __construct( $conf, $type, $key ) {
00088                 $this->key = $key;
00089                 $this->workers  = $conf['workers'];
00090                 $this->maxqueue = $conf['maxqueue'];
00091                 $this->timeout  = $conf['timeout'];
00092         }
00093 }
00094 
00095 class PoolCounter_Stub extends PoolCounter {
00096 
00100         function acquireForMe() {
00101                 return Status::newGood( PoolCounter::LOCKED );
00102         }
00103 
00107         function acquireForAnyone() {
00108                 return Status::newGood( PoolCounter::LOCKED );
00109         }
00110 
00114         function release() {
00115                 return Status::newGood( PoolCounter::RELEASED );
00116         }
00117 
00118         public function __construct() {
00119                 /* No parameters needed */
00120         }
00121 }
00122 
00126 abstract class PoolCounterWork {
00127         protected $cacheable = false; //Does this override getCachedWork() ?
00128 
00132         abstract function doWork();
00133 
00138         function getCachedWork() {
00139                 return false;
00140         }
00141 
00147         function fallback() {
00148                 return false;
00149         }
00150 
00154         function error( $status ) {
00155                 return false;
00156         }
00157 
00163         function logError( $status ) {
00164                 wfDebugLog( 'poolcounter', $status->getWikiText() );
00165         }
00166 
00172         function execute( $skipcache = false ) {
00173                 if ( $this->cacheable && !$skipcache ) {
00174                         $status = $this->poolCounter->acquireForAnyone();
00175                 } else {
00176                         $status = $this->poolCounter->acquireForMe();
00177                 }
00178 
00179                 if ( !$status->isOK() ) {
00180                         // Respond gracefully to complete server breakage: just log it and do the work
00181                         $this->logError( $status );
00182                         return $this->doWork();
00183                 }
00184 
00185                 switch ( $status->value ) {
00186                         case PoolCounter::LOCKED:
00187                                 $result = $this->doWork();
00188                                 $this->poolCounter->release();
00189                                 return $result;
00190 
00191                         case PoolCounter::DONE:
00192                                 $result = $this->getCachedWork();
00193                                 if ( $result === false ) {
00194                                         /* That someone else work didn't serve us.
00195                                          * Acquire the lock for me
00196                                          */
00197                                         return $this->execute( true );
00198                                 }
00199                                 return $result;
00200 
00201                         case PoolCounter::QUEUE_FULL:
00202                         case PoolCounter::TIMEOUT:
00203                                 $result = $this->fallback();
00204 
00205                                 if ( $result !== false ) {
00206                                         return $result;
00207                                 }
00208                                 /* no break */
00209 
00210                         /* These two cases should never be hit... */
00211                         case PoolCounter::ERROR:
00212                         default:
00213                                 $errors = array( PoolCounter::QUEUE_FULL => 'pool-queuefull', PoolCounter::TIMEOUT => 'pool-timeout' );
00214 
00215                                 $status = Status::newFatal( isset( $errors[$status->value] ) ? $errors[$status->value] : 'pool-errorunknown' );
00216                                 $this->logError( $status );
00217                                 return $this->error( $status );
00218                 }
00219         }
00220 
00221         function __construct( $type, $key ) {
00222                 $this->poolCounter = PoolCounter::factory( $type, $key );
00223         }
00224 }