Merge "Migrate remaining usages of Title::userCan() to PermissionManager"
[lhc/web/wiklou.git] / includes / jobqueue / JobQueueDB.php
index 74a6559..7c78f40 100644 (file)
@@ -55,6 +55,7 @@ class JobQueueDB extends JobQueue {
         *               If not specified, the primary DB cluster for the wiki will be used.
         *               This can be overridden with a custom cluster so that DB handles will
         *               be retrieved via LBFactory::getExternalLB() and getConnection().
+        *   - wanCache : An instance of WANObjectCache to use for caching.
         * @param array $params
         */
        protected function __construct( array $params ) {
@@ -66,7 +67,7 @@ class JobQueueDB extends JobQueue {
                        $this->cluster = $params['cluster'];
                }
 
-               $this->cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+               $this->cache = $params['wanCache'] ?? WANObjectCache::newEmpty();
        }
 
        protected function supportedOrders() {
@@ -90,7 +91,7 @@ class JobQueueDB extends JobQueue {
                                'job', '1', [ 'job_cmd' => $this->type, 'job_token' => '' ], __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return !$found;
@@ -117,7 +118,7 @@ class JobQueueDB extends JobQueue {
                                __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
                $this->cache->set( $key, $size, self::CACHE_TTL_SHORT );
 
@@ -149,7 +150,7 @@ class JobQueueDB extends JobQueue {
                                __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
                $this->cache->set( $key, $count, self::CACHE_TTL_SHORT );
 
@@ -186,7 +187,7 @@ class JobQueueDB extends JobQueue {
                                __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                $this->cache->set( $key, $count, self::CACHE_TTL_SHORT );
@@ -275,12 +276,12 @@ class JobQueueDB extends JobQueue {
                        foreach ( array_chunk( $rows, 50 ) as $rowBatch ) {
                                $dbw->insert( 'job', $rowBatch, $method );
                        }
-                       JobQueue::incrStats( 'inserts', $this->type, count( $rows ) );
-                       JobQueue::incrStats( 'dupe_inserts', $this->type,
+                       $this->incrStats( 'inserts', $this->type, count( $rows ) );
+                       $this->incrStats( 'dupe_inserts', $this->type,
                                count( $rowSet ) + count( $rowList ) - count( $rows )
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
                if ( $flags & self::QOS_ATOMIC ) {
                        $dbw->endAtomic( $method );
@@ -289,7 +290,7 @@ class JobQueueDB extends JobQueue {
 
        /**
         * @see JobQueue::doPop()
-        * @return Job|bool
+        * @return RunnableJob|bool
         */
        protected function doPop() {
                $dbw = $this->getMasterDB();
@@ -312,13 +313,10 @@ class JobQueueDB extends JobQueue {
                                if ( !$row ) {
                                        break; // nothing to do
                                }
-                               JobQueue::incrStats( 'pops', $this->type );
+                               $this->incrStats( 'pops', $this->type );
+
                                // Get the job object from the row...
-                               $title = Title::makeTitle( $row->job_namespace, $row->job_title );
-                               $job = Job::factory( $row->job_cmd, $title,
-                                       self::extractBlob( $row->job_params ) );
-                               $job->metadata['id'] = $row->job_id;
-                               $job->metadata['timestamp'] = $row->job_timestamp;
+                               $job = $this->jobFromRow( $row );
                                break; // done
                        } while ( true );
 
@@ -328,7 +326,7 @@ class JobQueueDB extends JobQueue {
                                $this->recycleAndDeleteStaleJobs();
                        }
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return $job;
@@ -349,7 +347,6 @@ class JobQueueDB extends JobQueue {
                // Check cache to see if the queue has <= OFFSET items
                $tinyQueue = $this->cache->get( $this->getCacheKey( 'small' ) );
 
-               $row = false; // the row acquired
                $invertedDirection = false; // whether one job_random direction was already scanned
                // This uses a replication safe method for acquiring jobs. One could use UPDATE+LIMIT
                // instead, but that either uses ORDER BY (in which case it deadlocks in MySQL) or is
@@ -480,11 +477,12 @@ class JobQueueDB extends JobQueue {
 
        /**
         * @see JobQueue::doAck()
-        * @param Job $job
+        * @param RunnableJob $job
         * @throws MWException
         */
-       protected function doAck( Job $job ) {
-               if ( !isset( $job->metadata['id'] ) ) {
+       protected function doAck( RunnableJob $job ) {
+               $id = $job->getMetadata( 'id' );
+               if ( $id === null ) {
                        throw new MWException( "Job of type '{$job->getType()}' has no ID." );
                }
 
@@ -493,12 +491,15 @@ class JobQueueDB extends JobQueue {
                $scope = $this->getScopedNoTrxFlag( $dbw );
                try {
                        // Delete a row with a single DELETE without holding row locks over RTTs...
-                       $dbw->delete( 'job',
-                               [ 'job_cmd' => $this->type, 'job_id' => $job->metadata['id'] ], __METHOD__ );
+                       $dbw->delete(
+                               'job',
+                               [ 'job_cmd' => $this->type, 'job_id' => $id ],
+                               __METHOD__
+                       );
 
-                       JobQueue::incrStats( 'acks', $this->type );
+                       $this->incrStats( 'acks', $this->type );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
        }
 
@@ -553,7 +554,7 @@ class JobQueueDB extends JobQueue {
                try {
                        $dbw->delete( 'job', [ 'job_cmd' => $this->type ] );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return true;
@@ -612,19 +613,11 @@ class JobQueueDB extends JobQueue {
                        return new MappedIterator(
                                $dbr->select( 'job', self::selectFields(), $conds ),
                                function ( $row ) {
-                                       $job = Job::factory(
-                                               $row->job_cmd,
-                                               Title::makeTitle( $row->job_namespace, $row->job_title ),
-                                               strlen( $row->job_params ) ? unserialize( $row->job_params ) : []
-                                       );
-                                       $job->metadata['id'] = $row->job_id;
-                                       $job->metadata['timestamp'] = $row->job_timestamp;
-
-                                       return $job;
+                                       return $this->jobFromRow( $row );
                                }
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
        }
 
@@ -723,8 +716,7 @@ class JobQueueDB extends JobQueue {
                                        );
                                        $affected = $dbw->affectedRows();
                                        $count += $affected;
-                                       JobQueue::incrStats( 'recycles', $this->type, $affected );
-                                       $this->aggr->notifyQueueNonEmpty( $this->domain, $this->type );
+                                       $this->incrStats( 'recycles', $this->type, $affected );
                                }
                        }
 
@@ -750,12 +742,12 @@ class JobQueueDB extends JobQueue {
                                $dbw->delete( 'job', [ 'job_id' => $ids ], __METHOD__ );
                                $affected = $dbw->affectedRows();
                                $count += $affected;
-                               JobQueue::incrStats( 'abandons', $this->type, $affected );
+                               $this->incrStats( 'abandons', $this->type, $affected );
                        }
 
                        $dbw->unlock( "jobqueue-recycle-{$this->type}", __METHOD__ );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return $count;
@@ -770,8 +762,8 @@ class JobQueueDB extends JobQueue {
                return [
                        // Fields that describe the nature of the job
                        'job_cmd' => $job->getType(),
-                       'job_namespace' => $job->getTitle()->getNamespace(),
-                       'job_title' => $job->getTitle()->getDBkey(),
+                       'job_namespace' => $job->getParams()['namespace'] ?? NS_SPECIAL,
+                       'job_title' => $job->getParams()['title'] ?? '',
                        'job_params' => self::makeBlob( $job->getParams() ),
                        // Additional job metadata
                        'job_timestamp' => $db->timestamp(),
@@ -886,23 +878,30 @@ class JobQueueDB extends JobQueue {
        }
 
        /**
-        * @param string $blob
-        * @return bool|mixed
+        * @param stdClass $row
+        * @return RunnableJob|null
         */
-       protected static function extractBlob( $blob ) {
-               if ( (string)$blob !== '' ) {
-                       return unserialize( $blob );
-               } else {
-                       return false;
+       protected function jobFromRow( $row ) {
+               $params = ( (string)$row->job_params !== '' ) ? unserialize( $row->job_params ) : [];
+               if ( !is_array( $params ) ) { // this shouldn't happen
+                       throw new UnexpectedValueException(
+                               "Could not unserialize job with ID '{$row->job_id}'." );
                }
+
+               $params += [ 'namespace' => $row->job_namespace, 'title' => $row->job_title ];
+               $job = $this->factoryJob( $row->job_cmd, $params );
+               $job->setMetadata( 'id', $row->job_id );
+               $job->setMetadata( 'timestamp', $row->job_timestamp );
+
+               return $job;
        }
 
        /**
         * @param DBError $e
-        * @throws JobQueueError
+        * @return JobQueueError
         */
-       protected function throwDBException( DBError $e ) {
-               throw new JobQueueError( get_class( $e ) . ": " . $e->getMessage() );
+       protected function getDBException( DBError $e ) {
+               return new JobQueueError( get_class( $e ) . ": " . $e->getMessage() );
        }
 
        /**