X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FPoolCounter.php;h=182520e1c99d5e0e0ac8987157ff3bd3f19eb89b;hb=95300b2e5554ee6ee7fff11f890b1dac96b42c27;hp=c24993e8350aa776b3fc6b555bd9b7b0c25237b0;hpb=3342af373caa4545c237b3870ca383d2fdf0e0c9;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/PoolCounter.php b/includes/PoolCounter.php index c24993e835..182520e1c9 100644 --- a/includes/PoolCounter.php +++ b/includes/PoolCounter.php @@ -4,9 +4,14 @@ * When you have many workers (threads/servers) giving service, and a * cached item expensive to produce expires, you may get several workers * doing the job at the same time. + * * Given enough requests and the item expiring fast (non-cacheable, * lots of edits...) that single work can end up unfairly using most (all) - * of the cpu of the pool. This is also known as 'Michael Jackson effect'. + * of the cpu of the pool. This is also known as 'Michael Jackson effect' + * since this effect triggered on the english wikipedia on the day Michael + * Jackson died, the biographical article got hit with several edits per + * minutes and hundreds of read hits. + * * The PoolCounter provides semaphore semantics for restricting the number * of workers that may be concurrently performing such single task. * @@ -16,15 +21,15 @@ abstract class PoolCounter { /* Return codes */ - const LOCKED = 1; /* Lock acquired */ + const LOCKED = 1; /* Lock acquired */ const RELEASED = 2; /* Lock released */ - const DONE = 3; /* Another one did the work for you */ + const DONE = 3; /* Another worker did the work for you */ - const ERROR = -1; /* Indeterminate error */ - const NOT_LOCKED = -2; /* Called release() with no lock held */ - const QUEUE_FULL = -3; /* There are already maxqueue workers on this lock */ - const TIMEOUT = -4; /* Timeout exceeded */ - const LOCK_HELD = -5; /* Cannot acquire another lock while you have one lock held */ + const ERROR = -1; /* Indeterminate error */ + const NOT_LOCKED = -2; /* Called release() with no lock held */ + const QUEUE_FULL = -3; /* There are already maxqueue workers on this lock */ + const TIMEOUT = -4; /* Timeout exceeded */ + const LOCK_HELD = -5; /* Cannot acquire another lock while you have one lock held */ /** * I want to do this task and I need to do it myself. @@ -62,6 +67,11 @@ abstract class PoolCounter { /** * Create a Pool counter. This should only be called from the PoolWorks. + * + * @param $type + * @param $key + * + * @return PoolCounter */ public static function factory( $type, $key ) { global $wgPoolCounterConf; @@ -83,18 +93,28 @@ abstract class PoolCounter { } class PoolCounter_Stub extends PoolCounter { + + /** + * @return Status + */ function acquireForMe() { return Status::newGood( PoolCounter::LOCKED ); } + /** + * @return Status + */ function acquireForAnyone() { return Status::newGood( PoolCounter::LOCKED ); } + /** + * @return Status + */ function release() { return Status::newGood( PoolCounter::RELEASED ); } - + public function __construct() { /* No parameters needed */ } @@ -151,44 +171,47 @@ abstract class PoolCounterWork { } else { $status = $this->poolCounter->acquireForMe(); } - - if ( $status->isOK() ) { - switch ( $status->value ) { - case PoolCounter::LOCKED: - $result = $this->doWork(); - $this->poolCounter->release(); - return $result; + + if ( !$status->isOK() ) { + // Respond gracefully to complete server breakage: just log it and do the work + $this->logError( $status ); + return $this->doWork(); + } + + switch ( $status->value ) { + case PoolCounter::LOCKED: + $result = $this->doWork(); + $this->poolCounter->release(); + return $result; + + case PoolCounter::DONE: + $result = $this->getCachedWork(); + if ( $result === false ) { + /* That someone else work didn't serve us. + * Acquire the lock for me + */ + return $this->execute( true ); + } + return $result; + + case PoolCounter::QUEUE_FULL: + case PoolCounter::TIMEOUT: + $result = $this->fallback(); - case PoolCounter::DONE: - $result = $this->getCachedWork(); - if ( $result === false ) { - /* That someone else work didn't serve us. - * Acquire the lock for me - */ - return $this->execute( true ); - } + if ( $result !== false ) { return $result; - - case PoolCounter::QUEUE_FULL: - case PoolCounter::TIMEOUT: - $result = $this->fallback(); - - if ( $result !== false ) { - return $result; - } - /* no break */ + } + /* no break */ + + /* These two cases should never be hit... */ + case PoolCounter::ERROR: + default: + $errors = array( PoolCounter::QUEUE_FULL => 'pool-queuefull', PoolCounter::TIMEOUT => 'pool-timeout' ); - /* These two cases should never be hit... */ - case PoolCounter::ERROR: - default: - $errors = array( PoolCounter::QUEUE_FULL => 'pool-queuefull', PoolCounter::TIMEOUT => 'pool-timeout' ); - - $status = Status::newFatal( isset($errors[$status->value]) ? $errors[$status->value] : 'pool-errorunknown' ); - /* continue to the error */ - } + $status = Status::newFatal( isset($errors[$status->value]) ? $errors[$status->value] : 'pool-errorunknown' ); + $this->logError( $status ); + return $this->error( $status ); } - $this->logError( $status ); - return $this->error( $status ); } function __construct( $type, $key ) {