MediaWiki  REL1_19
HTMLCacheUpdate.php
Go to the documentation of this file.
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 }