MediaWiki
REL1_19
|
00001 <?php 00002 00026 class HTMLCacheUpdate implements DeferrableUpdate { 00030 public $mTitle; 00031 00032 public $mTable, $mPrefix, $mStart, $mEnd; 00033 public $mRowsPerJob, $mRowsPerQuery; 00034 00041 function __construct( $titleTo, $table, $start = false, $end = false ) { 00042 global $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery; 00043 00044 $this->mTitle = $titleTo; 00045 $this->mTable = $table; 00046 $this->mStart = $start; 00047 $this->mEnd = $end; 00048 $this->mRowsPerJob = $wgUpdateRowsPerJob; 00049 $this->mRowsPerQuery = $wgUpdateRowsPerQuery; 00050 $this->mCache = $this->mTitle->getBacklinkCache(); 00051 } 00052 00053 public function doUpdate() { 00054 if ( $this->mStart || $this->mEnd ) { 00055 $this->doPartialUpdate(); 00056 return; 00057 } 00058 00059 # Get an estimate of the number of rows from the BacklinkCache 00060 $numRows = $this->mCache->getNumLinks( $this->mTable ); 00061 if ( $numRows > $this->mRowsPerJob * 2 ) { 00062 # Do fast cached partition 00063 $this->insertJobs(); 00064 } else { 00065 # Get the links from the DB 00066 $titleArray = $this->mCache->getLinks( $this->mTable ); 00067 # Check if the row count estimate was correct 00068 if ( $titleArray->count() > $this->mRowsPerJob * 2 ) { 00069 # Not correct, do accurate partition 00070 wfDebug( __METHOD__.": row count estimate was incorrect, repartitioning\n" ); 00071 $this->insertJobsFromTitles( $titleArray ); 00072 } else { 00073 $this->invalidateTitles( $titleArray ); 00074 } 00075 } 00076 } 00077 00081 protected function doPartialUpdate() { 00082 $titleArray = $this->mCache->getLinks( $this->mTable, $this->mStart, $this->mEnd ); 00083 if ( $titleArray->count() <= $this->mRowsPerJob * 2 ) { 00084 # This partition is small enough, do the update 00085 $this->invalidateTitles( $titleArray ); 00086 } else { 00087 # Partitioning was excessively inaccurate. Divide the job further. 00088 # This can occur when a large number of links are added in a short 00089 # period of time, say by updating a heavily-used template. 00090 $this->insertJobsFromTitles( $titleArray ); 00091 } 00092 } 00093 00101 protected function insertJobsFromTitles( $titleArray ) { 00102 # We make subpartitions in the sense that the start of the first job 00103 # will be the start of the parent partition, and the end of the last 00104 # job will be the end of the parent partition. 00105 $jobs = array(); 00106 $start = $this->mStart; # start of the current job 00107 $numTitles = 0; 00108 foreach ( $titleArray as $title ) { 00109 $id = $title->getArticleID(); 00110 # $numTitles is now the number of titles in the current job not 00111 # including the current ID 00112 if ( $numTitles >= $this->mRowsPerJob ) { 00113 # Add a job up to but not including the current ID 00114 $params = array( 00115 'table' => $this->mTable, 00116 'start' => $start, 00117 'end' => $id - 1 00118 ); 00119 $jobs[] = new HTMLCacheUpdateJob( $this->mTitle, $params ); 00120 $start = $id; 00121 $numTitles = 0; 00122 } 00123 $numTitles++; 00124 } 00125 # Last job 00126 $params = array( 00127 'table' => $this->mTable, 00128 'start' => $start, 00129 'end' => $this->mEnd 00130 ); 00131 $jobs[] = new HTMLCacheUpdateJob( $this->mTitle, $params ); 00132 wfDebug( __METHOD__.": repartitioning into " . count( $jobs ) . " jobs\n" ); 00133 00134 if ( count( $jobs ) < 2 ) { 00135 # I don't think this is possible at present, but handling this case 00136 # makes the code a bit more robust against future code updates and 00137 # avoids a potential infinite loop of repartitioning 00138 wfDebug( __METHOD__.": repartitioning failed!\n" ); 00139 $this->invalidateTitles( $titleArray ); 00140 return; 00141 } 00142 00143 Job::batchInsert( $jobs ); 00144 } 00145 00149 protected function insertJobs() { 00150 $batches = $this->mCache->partition( $this->mTable, $this->mRowsPerJob ); 00151 if ( !$batches ) { 00152 return; 00153 } 00154 $jobs = array(); 00155 foreach ( $batches as $batch ) { 00156 $params = array( 00157 'table' => $this->mTable, 00158 'start' => $batch[0], 00159 'end' => $batch[1], 00160 ); 00161 $jobs[] = new HTMLCacheUpdateJob( $this->mTitle, $params ); 00162 } 00163 Job::batchInsert( $jobs ); 00164 } 00165 00170 protected function invalidateTitles( $titleArray ) { 00171 global $wgUseFileCache, $wgUseSquid; 00172 00173 $dbw = wfGetDB( DB_MASTER ); 00174 $timestamp = $dbw->timestamp(); 00175 00176 # Get all IDs in this query into an array 00177 $ids = array(); 00178 foreach ( $titleArray as $title ) { 00179 $ids[] = $title->getArticleID(); 00180 } 00181 00182 if ( !$ids ) { 00183 return; 00184 } 00185 00186 # Update page_touched 00187 $batches = array_chunk( $ids, $this->mRowsPerQuery ); 00188 foreach ( $batches as $batch ) { 00189 $dbw->update( 'page', 00190 array( 'page_touched' => $timestamp ), 00191 array( 'page_id' => $batch ), 00192 __METHOD__ 00193 ); 00194 } 00195 00196 # Update squid 00197 if ( $wgUseSquid ) { 00198 $u = SquidUpdate::newFromTitles( $titleArray ); 00199 $u->doUpdate(); 00200 } 00201 00202 # Update file cache 00203 if ( $wgUseFileCache ) { 00204 foreach ( $titleArray as $title ) { 00205 HTMLFileCache::clearFileCache( $title ); 00206 } 00207 } 00208 } 00209 } 00210 00211 00218 class HTMLCacheUpdateJob extends Job { 00219 var $table, $start, $end; 00220 00227 function __construct( $title, $params, $id = 0 ) { 00228 parent::__construct( 'htmlCacheUpdate', $title, $params, $id ); 00229 $this->table = $params['table']; 00230 $this->start = $params['start']; 00231 $this->end = $params['end']; 00232 } 00233 00234 public function run() { 00235 $update = new HTMLCacheUpdate( $this->title, $this->table, $this->start, $this->end ); 00236 $update->doUpdate(); 00237 return true; 00238 } 00239 }