Expose changed links in LinksUpdate
authorNik Everett <neverett@wikimedia.org>
Wed, 9 Oct 2013 18:48:37 +0000 (18:48 +0000)
committerNik Everett <neverett@wikimedia.org>
Tue, 15 Oct 2013 17:43:14 +0000 (17:43 +0000)
These links are only really available during the LinksUpdateComplete
hook.

To make sure they are always available this also removes dump links
updates which would prevent this data from being built.

Change-Id: I115f8cf9d3b0a1dba979ceb58b5f14dd0b76ec49

includes/DefaultSettings.php
includes/LinksUpdate.php
tests/phpunit/includes/LinksUpdateTest.php

index 21cd1ff..7763961 100644 (file)
@@ -1872,11 +1872,6 @@ $wgAllowSlowParserFunctions = false;
  */
 $wgAllowSchemaUpdates = true;
 
-/**
- * Do DELETE/INSERT for link updates instead of incremental
- */
-$wgUseDumbLinkUpdate = false;
-
 /**
  * Anti-lock flags - bitfield
  *   - ALF_NO_LINK_LOCK:
index 24f1679..fdd0e3c 100644 (file)
@@ -43,6 +43,16 @@ class LinksUpdate extends SqlDataUpdate {
                $mOptions,       //!< SELECT options to be used (array)
                $mRecursive;     //!< Whether to queue jobs for recursive updates
 
+       /**
+        * @var null|array Added links if calculated.
+        */
+       private $linkInsertions = null;
+
+       /**
+        * @var null|array Deleted links if calculated.
+        */
+       private $linkDeletions = null;
+
        /**
         * Constructor
         *
@@ -112,14 +122,8 @@ class LinksUpdate extends SqlDataUpdate {
         * Update link tables with outgoing links from an updated article
         */
        public function doUpdate() {
-               global $wgUseDumbLinkUpdate;
-
                wfRunHooks( 'LinksUpdate', array( &$this ) );
-               if ( $wgUseDumbLinkUpdate ) {
-                       $this->doDumbUpdate();
-               } else {
-                       $this->doIncrementalUpdate();
-               }
+               $this->doIncrementalUpdate();
                wfRunHooks( 'LinksUpdateComplete', array( &$this ) );
        }
 
@@ -128,8 +132,9 @@ class LinksUpdate extends SqlDataUpdate {
 
                # Page links
                $existing = $this->getExistingLinks();
-               $this->incrTableUpdate( 'pagelinks', 'pl', $this->getLinkDeletions( $existing ),
-                       $this->getLinkInsertions( $existing ) );
+               $this->linkDeletions = $this->getLinkDeletions( $existing );
+               $this->linkInsertions = $this->getLinkInsertions( $existing );
+               $this->incrTableUpdate( 'pagelinks', 'pl', $this->linkDeletions, $this->linkInsertions );
 
                # Image links
                $existing = $this->getExistingImages();
@@ -197,46 +202,6 @@ class LinksUpdate extends SqlDataUpdate {
                wfProfileOut( __METHOD__ );
        }
 
-       /**
-        * Link update which clears the previous entries and inserts new ones
-        * May be slower or faster depending on level of lock contention and write speed of DB
-        * Also useful where link table corruption needs to be repaired, e.g. in refreshLinks.php
-        */
-       protected function doDumbUpdate() {
-               wfProfileIn( __METHOD__ );
-
-               # Refresh category pages and image description pages
-               $existing = $this->getExistingCategories();
-               $categoryInserts = array_diff_assoc( $this->mCategories, $existing );
-               $categoryDeletes = array_diff_assoc( $existing, $this->mCategories );
-               $categoryUpdates = $categoryInserts + $categoryDeletes;
-               $existing = $this->getExistingImages();
-               $imageUpdates = array_diff_key( $existing, $this->mImages ) + array_diff_key( $this->mImages, $existing );
-
-               $this->dumbTableUpdate( 'pagelinks', $this->getLinkInsertions(), 'pl_from' );
-               $this->dumbTableUpdate( 'imagelinks', $this->getImageInsertions(), 'il_from' );
-               $this->dumbTableUpdate( 'categorylinks', $this->getCategoryInsertions(), 'cl_from' );
-               $this->dumbTableUpdate( 'templatelinks', $this->getTemplateInsertions(), 'tl_from' );
-               $this->dumbTableUpdate( 'externallinks', $this->getExternalInsertions(), 'el_from' );
-               $this->dumbTableUpdate( 'langlinks', $this->getInterlangInsertions(), 'll_from' );
-               $this->dumbTableUpdate( 'iwlinks', $this->getInterwikiInsertions(), 'iwl_from' );
-               $this->dumbTableUpdate( 'page_props', $this->getPropertyInsertions(), 'pp_page' );
-
-               # Update the cache of all the category pages and image description
-               # pages which were changed, and fix the category table count
-               $this->invalidateCategories( $categoryUpdates );
-               $this->updateCategoryCounts( $categoryInserts, $categoryDeletes );
-               $this->invalidateImageDescriptions( $imageUpdates );
-
-               # Refresh links of all pages including this page
-               # This will be in a separate transaction
-               if ( $this->mRecursive ) {
-                       $this->queueRecursiveJobs();
-               }
-
-               wfProfileOut( __METHOD__ );
-       }
-
        /**
         * Queue recursive jobs for this page
         *
@@ -296,21 +261,6 @@ class LinksUpdate extends SqlDataUpdate {
                $this->invalidatePages( NS_FILE, array_keys( $images ) );
        }
 
-       /**
-        * @param $table
-        * @param $insertions
-        * @param $fromField
-        */
-       private function dumbTableUpdate( $table, $insertions, $fromField ) {
-               $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ );
-               if ( count( $insertions ) ) {
-                       # The link array was constructed without FOR UPDATE, so there may
-                       # be collisions. This may cause minor link table inconsistencies,
-                       # which is better than crippling the site with lock contention.
-                       $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) );
-               }
-       }
-
        /**
         * Update a table by doing a delete query then an insert query
         * @param $table
@@ -821,6 +771,40 @@ class LinksUpdate extends SqlDataUpdate {
                        }
                }
        }
+
+       /**
+        * Fetch page links added by this LinksUpdate.  Only available after the update is complete.
+        * @since 1.22
+        * @return null|array of Titles
+        */
+       public function getAddedLinks() {
+               if ( $this->linkInsertions === null ) {
+                       return null;
+               }
+               $result = array();
+               foreach ( $this->linkInsertions as $insertion ) {
+                       $result[] = Title::makeTitle( $insertion[ 'pl_namespace' ], $insertion[ 'pl_title' ] );
+               }
+               return $result;
+       }
+
+       /**
+        * Fetch page links removed by this LinksUpdate.  Only available after the update is complete.
+        * @since 1.22
+        * @return null|array of Titles
+        */
+       public function getRemovedLinks() {
+               if ( $this->linkDeletions === null ) {
+                       return null;
+               }
+               $result = array();
+               foreach ( $this->linkDeletions as $ns => $titles ) {
+                       foreach ( $titles as $title => $unused ) {
+                               $result[] = Title::makeTitle( $ns, $title );
+                       }
+               }
+               return $result;
+       }
 }
 
 /**
index 4e6d3ea..5ade250 100644 (file)
@@ -60,18 +60,30 @@ class LinksUpdateTest extends MediaWikiTestCase {
                $po->addLink( Title::newFromText( "linksupdatetest:Foo" ) ); // interwiki link should be ignored
                $po->addLink( Title::newFromText( "#Foo" ) ); // hash link should be ignored
 
-               $this->assertLinksUpdate( $t, $po, 'pagelinks', 'pl_namespace, pl_title', 'pl_from = 111', array(
+               $update = $this->assertLinksUpdate( $t, $po, 'pagelinks', 'pl_namespace, pl_title', 'pl_from = 111', array(
                        array( NS_MAIN, 'Foo' ),
                ) );
+               $this->assertArrayEquals( array(
+                       Title::makeTitle( NS_MAIN, 'Foo' ),  // newFromText doesn't yield the same internal state....
+               ), $update->getAddedLinks() );
 
                $po = new ParserOutput();
                $po->setTitleText( $t->getPrefixedText() );
 
                $po->addLink( Title::newFromText( "Bar" ) );
+               $po->addLink( Title::newFromText( "Talk:Bar" ) );
 
-               $this->assertLinksUpdate( $t, $po, 'pagelinks', 'pl_namespace, pl_title', 'pl_from = 111', array(
+               $update = $this->assertLinksUpdate( $t, $po, 'pagelinks', 'pl_namespace, pl_title', 'pl_from = 111', array(
                        array( NS_MAIN, 'Bar' ),
+                       array( NS_TALK, 'Bar' ),
                ) );
+               $this->assertArrayEquals( array(
+                       Title::makeTitle( NS_MAIN, 'Bar' ),
+                       Title::makeTitle( NS_TALK, 'Bar' ),
+               ), $update->getAddedLinks() );
+               $this->assertArrayEquals( array(
+                       Title::makeTitle( NS_MAIN, 'Foo' ),
+               ), $update->getRemovedLinks() );
        }
 
        public function testUpdate_externallinks() {
@@ -158,5 +170,6 @@ class LinksUpdateTest extends MediaWikiTestCase {
                $update->commitTransaction();
 
                $this->assertSelect( $table, $fields, $condition, $expectedRows );
+               return $update;
        }
 }