MediaWiki  REL1_24
RefreshLinksJob2.php
Go to the documentation of this file.
00001 <?php
00031 class RefreshLinksJob2 extends Job {
00032     function __construct( $title, $params ) {
00033         parent::__construct( 'refreshLinks2', $title, $params );
00034         // Base jobs for large templates can easily be de-duplicated
00035         $this->removeDuplicates = !isset( $params['start'] ) && !isset( $params['end'] );
00036     }
00037 
00042     function run() {
00043         global $wgUpdateRowsPerJob;
00044 
00045         $linkCache = LinkCache::singleton();
00046         $linkCache->clear();
00047 
00048         if ( is_null( $this->title ) ) {
00049             $this->error = "refreshLinks2: Invalid title";
00050             return false;
00051         }
00052 
00053         // Back compat for pre-r94435 jobs
00054         $table = isset( $this->params['table'] ) ? $this->params['table'] : 'templatelinks';
00055 
00056         // Avoid slave lag when fetching templates.
00057         // When the outermost job is run, we know that the caller that enqueued it must have
00058         // committed the relevant changes to the DB by now. At that point, record the master
00059         // position and pass it along as the job recursively breaks into smaller range jobs.
00060         // Hopefully, when leaf jobs are popped, the slaves will have reached that position.
00061         if ( isset( $this->params['masterPos'] ) ) {
00062             $masterPos = $this->params['masterPos'];
00063         } elseif ( wfGetLB()->getServerCount() > 1 ) {
00064             $masterPos = wfGetLB()->getMasterPos();
00065         } else {
00066             $masterPos = false;
00067         }
00068 
00069         $tbc = $this->title->getBacklinkCache();
00070 
00071         $jobs = array(); // jobs to insert
00072         if ( isset( $this->params['start'] ) && isset( $this->params['end'] ) ) {
00073             # This is a partition job to trigger the insertion of leaf jobs...
00074             $jobs = array_merge( $jobs, $this->getSingleTitleJobs( $table, $masterPos ) );
00075         } else {
00076             # This is a base job to trigger the insertion of partitioned jobs...
00077             if ( $tbc->getNumLinks( $table, $wgUpdateRowsPerJob + 1 ) <= $wgUpdateRowsPerJob ) {
00078                 # Just directly insert the single per-title jobs
00079                 $jobs = array_merge( $jobs, $this->getSingleTitleJobs( $table, $masterPos ) );
00080             } else {
00081                 # Insert the partition jobs to make per-title jobs
00082                 foreach ( $tbc->partition( $table, $wgUpdateRowsPerJob ) as $batch ) {
00083                     list( $start, $end ) = $batch;
00084                     $jobs[] = new RefreshLinksJob2( $this->title,
00085                         array(
00086                             'table' => $table,
00087                             'start' => $start,
00088                             'end' => $end,
00089                             'masterPos' => $masterPos,
00090                         ) + $this->getRootJobParams() // carry over information for de-duplication
00091                     );
00092                 }
00093             }
00094         }
00095 
00096         if ( count( $jobs ) ) {
00097             JobQueueGroup::singleton()->push( $jobs );
00098         }
00099 
00100         return true;
00101     }
00102 
00108     protected function getSingleTitleJobs( $table, $masterPos ) {
00109         # The "start"/"end" fields are not set for the base jobs
00110         $start = isset( $this->params['start'] ) ? $this->params['start'] : false;
00111         $end = isset( $this->params['end'] ) ? $this->params['end'] : false;
00112         $titles = $this->title->getBacklinkCache()->getLinks( $table, $start, $end );
00113         # Convert into single page refresh links jobs.
00114         # This handles well when in sapi mode and is useful in any case for job
00115         # de-duplication. If many pages use template A, and that template itself
00116         # uses template B, then an edit to both will create many duplicate jobs.
00117         # Roughly speaking, for each page, one of the "RefreshLinksJob" jobs will
00118         # get run first, and when it does, it will remove the duplicates. Of course,
00119         # one page could have its job popped when the other page's job is still
00120         # buried within the logic of a refreshLinks2 job.
00121         $jobs = array();
00122         foreach ( $titles as $title ) {
00123             $jobs[] = new RefreshLinksJob( $title,
00124                 array( 'masterPos' => $masterPos ) + $this->getRootJobParams()
00125             ); // carry over information for de-duplication
00126         }
00127         return $jobs;
00128     }
00129 
00133     public function getDeduplicationInfo() {
00134         $info = parent::getDeduplicationInfo();
00135         // Don't let highly unique "masterPos" values ruin duplicate detection
00136         if ( is_array( $info['params'] ) ) {
00137             unset( $info['params']['masterPos'] );
00138         }
00139         return $info;
00140     }
00141 }