Replacing var keyword with private / public as we now require PHP5.
[lhc/web/wiklou.git] / includes / JobQueue.php
1 <?php
2
3 if ( !defined( 'MEDIAWIKI' ) ) {
4 die( "This file is part of MediaWiki, it is not a valid entry point\n" );
5 }
6
7 class Job {
8 private
9 $command,
10 $title,
11 $params,
12 $id,
13 $removeDuplicates,
14 $error;
15
16 /*-------------------------------------------------------------------------
17 * Static functions
18 *------------------------------------------------------------------------*/
19 /**
20 * Add an array of refreshLinks jobs to the queue
21 * @param array $titles Array of title objects.
22 * @static
23 */
24 function queueLinksJobs( $titles ) {
25 $fname = 'Job::queueLinksJobs';
26 wfProfileIn( $fname );
27 foreach ( $titles as $title ) {
28 $job = new Job( 'refreshLinks', $title );
29 $job->insert();
30 }
31 wfProfileOut( $fname );
32 }
33
34 /**
35 * Pop a job off the front of the queue
36 * @static
37 * @return Job or false if there's no jobs
38 */
39 function pop() {
40 $fname = 'Job::pop';
41 wfProfileIn( $fname );
42
43 $dbr =& wfGetDB( DB_SLAVE );
44
45 // Get a job from the slave
46 $row = $dbr->selectRow( 'job', '*', '', $fname,
47 array( 'ORDER BY' => 'job_id', 'LIMIT' => 1 )
48 );
49
50 if ( $row === false ) {
51 wfProfileOut( $fname );
52 return false;
53 }
54
55 // Try to delete it from the master
56 $dbw =& wfGetDB( DB_MASTER );
57 $dbw->delete( 'job', array( 'job_id' => $row->job_id ), $fname );
58 $affected = $dbw->affectedRows();
59 $dbw->immediateCommit();
60
61 if ( !$affected ) {
62 // Failed, someone else beat us to it
63 // Try getting a random row
64 $row = $dbw->selectRow( 'job', array( 'MIN(job_id) as minjob',
65 'MAX(job_id) as maxjob' ), '', $fname );
66 if ( $row === false || is_null( $row->minjob ) || is_null( $row->maxjob ) ) {
67 // No jobs to get
68 wfProfileOut( $fname );
69 return false;
70 }
71 // Get the random row
72 $row = $dbw->selectRow( 'job', '*',
73 array( 'job_id' => mt_rand( $row->minjob, $row->maxjob ) ), $fname );
74 if ( $row === false ) {
75 // Random job gone before we got the chance to select it
76 // Give up
77 wfProfileOut( $fname );
78 return false;
79 }
80 // Delete the random row
81 $dbw->delete( 'job', array( 'job_id' => $row->job_id ), $fname );
82 $affected = $dbw->affectedRows();
83 $dbw->immediateCommit();
84
85 if ( !$affected ) {
86 // Random job gone before we exclusively deleted it
87 // Give up
88 wfProfileOut( $fname );
89 return false;
90 }
91 }
92
93 // If execution got to here, there's a row in $row that has been deleted from the database
94 // by this thread. Hence the concurrent pop was successful.
95 $namespace = $row->job_namespace;
96 $dbkey = $row->job_title;
97 $title = Title::makeTitleSafe( $namespace, $dbkey );
98 $job = new Job( $row->job_cmd, $title, $row->job_params, $row->job_id );
99 wfProfileOut( $fname );
100 return $job;
101 }
102
103 /*-------------------------------------------------------------------------
104 * Non-static functions
105 *------------------------------------------------------------------------*/
106
107 function Job( $command, $title, $params = '', $id = 0 ) {
108 $this->command = $command;
109 $this->title = $title;
110 $this->params = $params;
111 $this->id = $id;
112
113 // A bit of premature generalisation
114 // Oh well, the whole class is premature generalisation really
115 $this->removeDuplicates = true;
116 }
117
118 function insert() {
119 $fname = 'Job::insert';
120
121 $fields = array(
122 'job_cmd' => $this->command,
123 'job_namespace' => $this->title->getNamespace(),
124 'job_title' => $this->title->getDBkey(),
125 'job_params' => $this->params
126 );
127
128 $dbw =& wfGetDB( DB_MASTER );
129
130 if ( $this->removeDuplicates ) {
131 $res = $dbw->select( 'job', array( '1' ), $fields, $fname );
132 if ( $dbw->numRows( $res ) ) {
133 return;
134 }
135 }
136 $fields['job_id'] = $dbw->nextSequenceValue( 'job_job_id_seq' );
137 $dbw->insert( 'job', $fields, $fname );
138 }
139
140 /**
141 * Run the job
142 * @return boolean success
143 */
144 function run() {
145 $fname = 'Job::run';
146 wfProfileIn( $fname );
147 switch ( $this->command ) {
148 case 'refreshLinks':
149 $retval = $this->refreshLinks();
150 break;
151 default:
152 $this->error = "Invalid job type {$this->command}, ignoring";
153 wfDebug( $this->error . "\n" );
154 $retval = false;
155 }
156 wfProfileOut( $fname );
157 return $retval;
158 }
159
160 /**
161 * Run a refreshLinks job
162 * @return boolean success
163 */
164 function refreshLinks() {
165 global $wgParser;
166 $fname = 'Job::refreshLinks';
167 wfProfileIn( $fname );
168
169 # FIXME: $dbw never used.
170 $dbw =& wfGetDB( DB_MASTER );
171
172 $linkCache =& LinkCache::singleton();
173 $linkCache->clear();
174
175 if ( is_null( $this->title ) ) {
176 $this->error = "refreshLinks: Invalid title";
177 wfProfileOut( $fname );
178 return false;
179 }
180
181 $revision = Revision::newFromTitle( $this->title );
182 if ( !$revision ) {
183 $this->error = 'refreshLinks: Article not found "' . $this->title->getPrefixedDBkey() . '"';
184 wfProfileOut( $fname );
185 return false;
186 }
187
188 wfProfileIn( "$fname-parse" );
189 $options = new ParserOptions;
190 $parserOutput = $wgParser->parse( $revision->getText(), $this->title, $options, true, true, $revision->getId() );
191 wfProfileOut( "$fname-parse" );
192 wfProfileIn( "$fname-update" );
193 $update = new LinksUpdate( $this->title, $parserOutput, false );
194 $update->doUpdate();
195 wfProfileOut( "$fname-update" );
196 wfProfileOut( $fname );
197 return true;
198 }
199
200 function toString() {
201 if ( is_object( $this->title ) ) {
202 $s = "{$this->command} " . $this->title->getPrefixedDBkey();
203 if ( $this->params !== '' ) {
204 $s .= ', ' . $this->params;
205 }
206 return $s;
207 } else {
208 return "{$this->command} {$this->params}";
209 }
210 }
211
212 function getLastError() {
213 return $this->error;
214 }
215 }
216 ?>