diff options
Diffstat (limited to 'includes/BacklinkCache.php')
-rw-r--r-- | includes/BacklinkCache.php | 73 |
1 files changed, 50 insertions, 23 deletions
diff --git a/includes/BacklinkCache.php b/includes/BacklinkCache.php index a7bcd858..53f92dd9 100644 --- a/includes/BacklinkCache.php +++ b/includes/BacklinkCache.php @@ -1,10 +1,9 @@ <?php - /** * Class for fetching backlink lists, approximate backlink counts and partitions. * Instances of this class should typically be fetched with $title->getBacklinkCache(). * - * Ideally you should only get your backlinks from here when you think there is some + * Ideally you should only get your backlinks from here when you think there is some * advantage in caching them. Otherwise it's just a waste of memory. */ class BacklinkCache { @@ -47,44 +46,53 @@ class BacklinkCache { /** * Get the backlinks for a given table. Cached in process memory only. - * @param string $table + * @param $table String + * @param $startId Integer or false + * @param $endId Integer or false * @return TitleArray */ public function getLinks( $table, $startId = false, $endId = false ) { wfProfileIn( __METHOD__ ); + $fromField = $this->getPrefix( $table ) . '_from'; + if ( $startId || $endId ) { // Partial range, not cached - wfDebug( __METHOD__.": from DB (uncacheable range)\n" ); + wfDebug( __METHOD__ . ": from DB (uncacheable range)\n" ); $conds = $this->getConditions( $table ); // Use the from field in the condition rather than the joined page_id, // because databases are stupid and don't necessarily propagate indexes. - $fromField = $this->getPrefix( $table ) . '_from'; if ( $startId ) { $conds[] = "$fromField >= " . intval( $startId ); } if ( $endId ) { $conds[] = "$fromField <= " . intval( $endId ); } - $res = $this->getDB()->select( + $res = $this->getDB()->select( array( $table, 'page' ), - array( 'page_namespace', 'page_title', 'page_id'), + array( 'page_namespace', 'page_title', 'page_id' ), $conds, __METHOD__, - array('STRAIGHT_JOIN') ); + array( + 'STRAIGHT_JOIN', + 'ORDER BY' => $fromField + ) ); $ta = TitleArray::newFromResult( $res ); wfProfileOut( __METHOD__ ); return $ta; } if ( !isset( $this->fullResultCache[$table] ) ) { - wfDebug( __METHOD__.": from DB\n" ); - $res = $this->getDB()->select( + wfDebug( __METHOD__ . ": from DB\n" ); + $res = $this->getDB()->select( array( $table, 'page' ), array( 'page_namespace', 'page_title', 'page_id' ), $this->getConditions( $table ), __METHOD__, - array('STRAIGHT_JOIN') ); + array( + 'STRAIGHT_JOIN', + 'ORDER BY' => $fromField, + ) ); $this->fullResultCache[$table] = $res; } $ta = TitleArray::newFromResult( $this->fullResultCache[$table] ); @@ -103,6 +111,7 @@ class BacklinkCache { 'templatelinks' => 'tl', 'redirect' => 'rd', ); + if ( isset( $prefixes[$table] ) ) { return $prefixes[$table]; } else { @@ -115,6 +124,7 @@ class BacklinkCache { */ protected function getConditions( $table ) { $prefix = $this->getPrefix( $table ); + switch ( $table ) { case 'pagelinks': case 'templatelinks': @@ -126,13 +136,13 @@ class BacklinkCache { ); break; case 'imagelinks': - $conds = array( + $conds = array( 'il_to' => $this->title->getDBkey(), 'page_id=il_from' ); break; case 'categorylinks': - $conds = array( + $conds = array( 'cl_to' => $this->title->getDBkey(), 'page_id=cl_from', ); @@ -150,10 +160,12 @@ class BacklinkCache { if ( isset( $this->fullResultCache[$table] ) ) { return $this->fullResultCache[$table]->numRows(); } + if ( isset( $this->partitionCache[$table] ) ) { $entry = reset( $this->partitionCache[$table] ); return $entry['numRows']; } + $titleArray = $this->getLinks( $table ); return $titleArray->count(); } @@ -163,33 +175,40 @@ class BacklinkCache { * Returns an array giving the start and end of each range. The first batch has * a start of false, and the last batch has an end of false. * - * @param string $table The links table name - * @param integer $batchSize - * @return array + * @param $table String: the links table name + * @param $batchSize Integer + * @return Array */ public function partition( $table, $batchSize ) { // Try cache if ( isset( $this->partitionCache[$table][$batchSize] ) ) { - wfDebug( __METHOD__.": got from partition cache\n" ); + wfDebug( __METHOD__ . ": got from partition cache\n" ); return $this->partitionCache[$table][$batchSize]['batches']; } + $this->partitionCache[$table][$batchSize] = false; $cacheEntry =& $this->partitionCache[$table][$batchSize]; // Try full result cache if ( isset( $this->fullResultCache[$table] ) ) { $cacheEntry = $this->partitionResult( $this->fullResultCache[$table], $batchSize ); - wfDebug( __METHOD__.": got from full result cache\n" ); + wfDebug( __METHOD__ . ": got from full result cache\n" ); return $cacheEntry['batches']; } + // Try memcached global $wgMemc; - $memcKey = wfMemcKey( 'backlinks', md5( $this->title->getPrefixedDBkey() ), - $table, $batchSize ); + $memcKey = wfMemcKey( + 'backlinks', + md5( $this->title->getPrefixedDBkey() ), + $table, + $batchSize + ); $memcValue = $wgMemc->get( $memcKey ); + if ( is_array( $memcValue ) ) { $cacheEntry = $memcValue; - wfDebug( __METHOD__.": got from memcached $memcKey\n" ); + wfDebug( __METHOD__ . ": got from memcached $memcKey\n" ); return $cacheEntry['batches']; } // Fetch from database @@ -197,17 +216,18 @@ class BacklinkCache { $cacheEntry = $this->partitionResult( $this->fullResultCache[$table], $batchSize ); // Save to memcached $wgMemc->set( $memcKey, $cacheEntry, self::CACHE_EXPIRY ); - wfDebug( __METHOD__.": got from database\n" ); + wfDebug( __METHOD__ . ": got from database\n" ); return $cacheEntry['batches']; } - /** + /** * Partition a DB result with backlinks in it into batches */ protected function partitionResult( $res, $batchSize ) { $batches = array(); $numRows = $res->numRows(); $numBatches = ceil( $numRows / $batchSize ); + for ( $i = 0; $i < $numBatches; $i++ ) { if ( $i == 0 ) { $start = false; @@ -217,6 +237,7 @@ class BacklinkCache { $row = $res->fetchObject(); $start = $row->page_id; } + if ( $i == $numBatches - 1 ) { $end = false; } else { @@ -225,6 +246,12 @@ class BacklinkCache { $row = $res->fetchObject(); $end = $row->page_id - 1; } + + # Sanity check order + if ( $start && $end && $start > $end ) { + throw new MWException( __METHOD__ . ': Internal error: query result out of order' ); + } + $batches[] = array( $start, $end ); } return array( 'numRows' => $numRows, 'batches' => $batches ); |