3 * Pick a database that has pending jobs
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
21 * @todo Make this work on PostgreSQL and maybe other database servers
22 * @ingroup Maintenance
25 require_once( __DIR__
. '/Maintenance.php' );
28 * Maintenance script that picks a database that has pending jobs.
30 * @ingroup Maintenance
32 class nextJobDB
extends Maintenance
{
33 public function __construct() {
34 parent
::__construct();
35 $this->mDescription
= "Pick a database that has pending jobs";
36 $this->addOption( 'type', "The type of job to search for", false, true );
39 public function execute() {
42 $type = $this->getOption( 'type', false );
44 $memcKey = 'jobqueue:dbs:v3';
45 $pendingDbInfo = $wgMemc->get( $memcKey );
47 // If the cache entry wasn't present, or in 1% of cases otherwise,
48 // regenerate the cache. Use any available stale cache if another
49 // process is currently regenerating the pending DB information.
50 if ( !$pendingDbInfo ||
mt_rand( 0, 100 ) == 0 ) {
51 $lock = $wgMemc->add( 'jobqueue:dbs:v3:lock', 1, 1800 ); // lock
53 $pendingDbInfo = array(
54 'pendingDBs' => $this->getPendingDbs(),
57 $wgMemc->set( $memcKey, $pendingDbInfo );
58 $wgMemc->delete( 'jobqueue:dbs:v3:lock' ); // unlock
62 if ( !$pendingDbInfo ||
!$pendingDbInfo['pendingDBs'] ) {
63 return; // no DBs with jobs or cache is both empty and locked
65 $pendingDBs = $pendingDbInfo['pendingDBs'];
70 if ( $type === false ) {
71 $candidates = call_user_func_array( 'array_merge', $pendingDBs );
72 } elseif ( isset( $pendingDBs[$type] ) ) {
73 $candidates = $pendingDBs[$type];
75 $candidates = array();
81 $candidates = array_values( $candidates );
82 $db = $candidates[ mt_rand( 0, count( $candidates ) - 1 ) ];
83 if ( !$this->checkJob( $type, $db ) ) {
84 if ( $type === false ) {
85 // There are no jobs available in the current database
86 foreach ( $pendingDBs as $type2 => $dbs ) {
87 $pendingDBs[$type2] = array_diff( $pendingDBs[$type2], array( $db ) );
90 // There are no jobs of this type available in the current database
91 $pendingDBs[$type] = array_diff( $pendingDBs[$type], array( $db ) );
93 // Update the cache to remove the outdated information
94 $pendingDbInfo['pendingDBs'] = $pendingDBs;
95 // @TODO: fix race condition with these updates
96 $wgMemc->set( $memcKey, $pendingDbInfo );
101 $this->output( $db . "\n" );
105 * Check if the specified database has a job of the specified type in it.
106 * The type may be false to indicate "all".
107 * @param $type string
108 * @param $dbName string
111 function checkJob( $type, $dbName ) {
112 $group = JobQueueGroup
::singleton( $dbName );
113 if ( $type === false ) {
114 foreach ( $group->getDefaultQueueTypes() as $type ) {
115 if ( !$group->get( $type )->isEmpty() ) {
121 return !$group->get( $type )->isEmpty();
126 * Get all databases that have a pending job
129 private function getPendingDbs() {
130 global $wgLocalDatabases;
132 $pendingDBs = array(); // (job type => (db list))
133 foreach ( $wgLocalDatabases as $db ) {
134 $types = JobQueueGroup
::singleton( $db )->getQueuesWithJobs();
135 foreach ( $types as $type ) {
136 $pendingDBs[$type][] = $db;
144 $maintClass = "nextJobDb";
145 require_once( RUN_MAINTENANCE_IF_MAIN
);