From 25369c83ff221f4d1df7dc1b90ada19d8c2944e2 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 9 Oct 2013 18:48:37 +0000 Subject: [PATCH] Expose changed links in LinksUpdate 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 | 5 - includes/LinksUpdate.php | 112 +++++++++------------ tests/phpunit/includes/LinksUpdateTest.php | 17 +++- 3 files changed, 63 insertions(+), 71 deletions(-) diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 21cd1ff53d..7763961a83 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -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: diff --git a/includes/LinksUpdate.php b/includes/LinksUpdate.php index 24f1679e7d..fdd0e3c116 100644 --- a/includes/LinksUpdate.php +++ b/includes/LinksUpdate.php @@ -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; + } } /** diff --git a/tests/phpunit/includes/LinksUpdateTest.php b/tests/phpunit/includes/LinksUpdateTest.php index 4e6d3eab6b..5ade250e2f 100644 --- a/tests/phpunit/includes/LinksUpdateTest.php +++ b/tests/phpunit/includes/LinksUpdateTest.php @@ -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; } } -- 2.20.1