From: Aaron Schulz Date: Fri, 25 Mar 2016 19:52:39 +0000 (-0700) Subject: Enforce $wgReadOnly for job queues X-Git-Tag: 1.31.0-rc.0~7255^2 X-Git-Url: http://git.cyclocoop.org/url?a=commitdiff_plain;h=b4ab40d2e89d06cde132c06f56d49fc30d5da702;p=lhc%2Fweb%2Fwiklou.git Enforce $wgReadOnly for job queues Bug: T130795 Change-Id: I9d8cf919de80dbe855086b9c590c0a0f20dc33b9 --- diff --git a/autoload.php b/autoload.php index 22411cd7e9..b851e39bc6 100644 --- a/autoload.php +++ b/autoload.php @@ -617,6 +617,7 @@ $wgAutoloadLocalClasses = [ 'JobQueueFederated' => __DIR__ . '/includes/jobqueue/JobQueueFederated.php', 'JobQueueGroup' => __DIR__ . '/includes/jobqueue/JobQueueGroup.php', 'JobQueueMemory' => __DIR__ . '/includes/jobqueue/JobQueueMemory.php', + 'JobQueueReadOnlyError' => __DIR__ . '/includes/jobqueue/JobQueue.php', 'JobQueueRedis' => __DIR__ . '/includes/jobqueue/JobQueueRedis.php', 'JobRunner' => __DIR__ . '/includes/jobqueue/JobRunner.php', 'JobSpecification' => __DIR__ . '/includes/jobqueue/JobSpecification.php', diff --git a/includes/jobqueue/JobQueue.php b/includes/jobqueue/JobQueue.php index 5b7193856d..d64be3c409 100644 --- a/includes/jobqueue/JobQueue.php +++ b/includes/jobqueue/JobQueue.php @@ -31,18 +31,16 @@ abstract class JobQueue { /** @var string Wiki ID */ protected $wiki; - /** @var string Job type */ protected $type; - /** @var string Job priority for pop() */ protected $order; - /** @var int Time to live in seconds */ protected $claimTTL; - /** @var int Maximum number of times to try a job */ protected $maxTries; + /** @var string|bool Read only rationale (or false if r/w) */ + protected $readOnlyReason; /** @var BagOStuff */ protected $dupCache; @@ -74,6 +72,9 @@ abstract class JobQueue { $this->aggr = isset( $params['aggregator'] ) ? $params['aggregator'] : new JobQueueAggregatorNull( [] ); + $this->readOnlyReason = isset( $params['readOnlyReason'] ) + ? $params['readOnlyReason'] + : false; } /** @@ -96,6 +97,7 @@ abstract class JobQueue { * but not acknowledged as completed after this many seconds. Recycling * of jobs simply means re-inserting them into the queue. Jobs can be * attempted up to three times before being discarded. + * - readOnlyReason : Set this to a string to make the queue read-only. * * Queue classes should throw an exception if they do not support the options given. * @@ -168,6 +170,14 @@ abstract class JobQueue { return $this->supportsDelayedJobs(); } + /** + * @return string|bool Read-only rational or false if r/w + * @since 1.27 + */ + public function getReadOnlyReason() { + return $this->readOnlyReason; + } + /** * Quickly check if the queue has no available (unacquired, non-delayed) jobs. * Queue classes should use caching if they are any slower without memcached. @@ -307,6 +317,8 @@ abstract class JobQueue { * @throws MWException */ final public function batchPush( array $jobs, $flags = 0 ) { + $this->assertNotReadOnly(); + if ( !count( $jobs ) ) { return; // nothing to do } @@ -349,6 +361,7 @@ abstract class JobQueue { final public function pop() { global $wgJobClasses; + $this->assertNotReadOnly(); if ( $this->wiki !== wfWikiID() ) { throw new MWException( "Cannot pop '{$this->type}' job off foreign wiki queue." ); } elseif ( !isset( $wgJobClasses[$this->type] ) ) { @@ -392,9 +405,11 @@ abstract class JobQueue { * @throws MWException */ final public function ack( Job $job ) { + $this->assertNotReadOnly(); if ( $job->getType() !== $this->type ) { throw new MWException( "Got '{$job->getType()}' job; expected '{$this->type}'." ); } + $this->doAck( $job ); } @@ -436,12 +451,12 @@ abstract class JobQueue { * @return bool */ final public function deduplicateRootJob( IJobSpecification $job ) { + $this->assertNotReadOnly(); if ( $job->getType() !== $this->type ) { throw new MWException( "Got '{$job->getType()}' job; expected '{$this->type}'." ); } - $ok = $this->doDeduplicateRootJob( $job ); - return $ok; + return $this->doDeduplicateRootJob( $job ); } /** @@ -524,6 +539,8 @@ abstract class JobQueue { * @return void */ final public function delete() { + $this->assertNotReadOnly(); + $this->doDelete(); } @@ -672,6 +689,15 @@ abstract class JobQueue { return null; // not supported } + /** + * @throws JobQueueReadOnlyError + */ + protected function assertNotReadOnly() { + if ( $this->readOnlyReason !== false ) { + throw new JobQueueReadOnlyError( "Job queue is read-only: {$this->readOnlyReason}" ); + } + } + /** * Call wfIncrStats() for the queue overall and for the queue type * @@ -699,3 +725,7 @@ class JobQueueError extends MWException { class JobQueueConnectionError extends JobQueueError { } + +class JobQueueReadOnlyError extends JobQueueError { + +} diff --git a/includes/jobqueue/JobQueueGroup.php b/includes/jobqueue/JobQueueGroup.php index 8b6c7f08f2..982a3a0a87 100644 --- a/includes/jobqueue/JobQueueGroup.php +++ b/includes/jobqueue/JobQueueGroup.php @@ -36,6 +36,8 @@ class JobQueueGroup { /** @var string Wiki ID */ protected $wiki; + /** @var string|bool Read only rationale (or false if r/w) */ + protected $readOnlyReason; /** @var array Map of (bucket => (queue => JobQueue, types => list of types) */ protected $coalescedQueues; @@ -54,9 +56,11 @@ class JobQueueGroup { /** * @param string $wiki Wiki ID + * @param string|bool $readOnlyReason Read-only reason or false */ - protected function __construct( $wiki ) { + protected function __construct( $wiki, $readOnlyReason ) { $this->wiki = $wiki; + $this->readOnlyReason = $readOnlyReason; $this->cache = new ProcessCacheLRU( 10 ); } @@ -67,7 +71,7 @@ class JobQueueGroup { public static function singleton( $wiki = false ) { $wiki = ( $wiki === false ) ? wfWikiID() : $wiki; if ( !isset( self::$instances[$wiki] ) ) { - self::$instances[$wiki] = new self( $wiki ); + self::$instances[$wiki] = new self( $wiki, wfConfiguredReadOnlyReason() ); } return self::$instances[$wiki]; @@ -98,6 +102,9 @@ class JobQueueGroup { $conf = $conf + $wgJobTypeConf['default']; } $conf['aggregator'] = JobQueueAggregator::singleton(); + if ( $this->readOnlyReason !== false ) { + $conf['readOnlyReason'] = $this->readOnlyReason; + } return JobQueue::factory( $conf ); }