From a438b12b8bb72ece5452caf24d5b0b46ada4359a Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Wed, 31 Aug 2016 06:06:35 -0700 Subject: [PATCH] Links update class cleanups * Avoid using deprecated functions. * Switch to DataUpdate as the direct parent class as no benefit was provided from SqlDataUpdate (which should be deprecated soon). Change-Id: I0f1c77128f3df658e6a0eaf4471ca48ac536c643 --- includes/deferred/LinksDeletionUpdate.php | 71 +++++++++++------- includes/deferred/LinksUpdate.php | 90 +++++++++++++---------- 2 files changed, 95 insertions(+), 66 deletions(-) diff --git a/includes/deferred/LinksDeletionUpdate.php b/includes/deferred/LinksDeletionUpdate.php index 47f2b21ff5..ca3500eae2 100644 --- a/includes/deferred/LinksDeletionUpdate.php +++ b/includes/deferred/LinksDeletionUpdate.php @@ -19,10 +19,12 @@ * * @file */ +use MediaWiki\MediaWikiServices; + /** * Update object handling the cleanup of links tables after a page was deleted. **/ -class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { +class LinksDeletionUpdate extends DataUpdate implements EnqueueableDataUpdate { /** @var WikiPage */ protected $page; /** @var integer */ @@ -30,6 +32,9 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate /** @var string */ protected $timestamp; + /** @var IDatabase */ + private $db; + /** * @param WikiPage $page Page we are updating * @param integer|null $pageId ID of the page we are updating [optional] @@ -37,8 +42,6 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate * @throws MWException */ function __construct( WikiPage $page, $pageId = null, $timestamp = null ) { - parent::__construct( false ); // no implicit transaction - $this->page = $page; if ( $pageId ) { $this->pageId = $pageId; // page ID at time of deletion @@ -52,23 +55,25 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate } public function doUpdate() { - $config = RequestContext::getMain()->getConfig(); + $services = MediaWikiServices::getInstance(); + $config = $services->getMainConfig(); + $lbFactory = $services->getDBLoadBalancerFactory(); $batchSize = $config->get( 'UpdateRowsPerQuery' ); - $factory = wfGetLBFactory(); // Page may already be deleted, so don't just getId() $id = $this->pageId; // Make sure all links update threads see the changes of each other. // This handles the case when updates have to batched into several COMMITs. - $scopedLock = LinksUpdate::acquirePageLock( $this->mDb, $id ); + $scopedLock = LinksUpdate::acquirePageLock( $this->getDB(), $id ); $title = $this->page->getTitle(); + $dbw = $this->getDB(); // convenience // Delete restrictions for it - $this->mDb->delete( 'page_restrictions', [ 'pr_page' => $id ], __METHOD__ ); + $dbw->delete( 'page_restrictions', [ 'pr_page' => $id ], __METHOD__ ); // Fix category table counts - $cats = $this->mDb->selectFieldValues( + $cats = $dbw->selectFieldValues( 'categorylinks', 'cl_to', [ 'cl_from' => $id ], @@ -78,8 +83,8 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate foreach ( $catBatches as $catBatch ) { $this->page->updateCategoryCounts( [], $catBatch, $id ); if ( count( $catBatches ) > 1 ) { - $factory->commitAndWaitForReplication( - __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ] + $lbFactory->commitAndWaitForReplication( + __METHOD__, $this->ticket, [ 'wiki' => $dbw->getWikiID() ] ); } } @@ -87,19 +92,19 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate // Refresh the category table entry if it seems to have no pages. Check // master for the most up-to-date cat_pages count. if ( $title->getNamespace() === NS_CATEGORY ) { - $row = $this->mDb->selectRow( + $row = $dbw->selectRow( 'category', [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ], [ 'cat_title' => $title->getDBkey(), 'cat_pages <= 0' ], __METHOD__ ); if ( $row ) { - $cat = Category::newFromRow( $row, $title )->refreshCounts(); + Category::newFromRow( $row, $title )->refreshCounts(); } } // If using cascading deletes, we can skip some explicit deletes - if ( !$this->mDb->cascadingDeletes() ) { + if ( !$dbw->cascadingDeletes() ) { // Delete outgoing links $this->batchDeleteByPK( 'pagelinks', @@ -144,14 +149,14 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate $batchSize ); // Delete any redirect entry or page props entries - $this->mDb->delete( 'redirect', [ 'rd_from' => $id ], __METHOD__ ); - $this->mDb->delete( 'page_props', [ 'pp_page' => $id ], __METHOD__ ); + $dbw->delete( 'redirect', [ 'rd_from' => $id ], __METHOD__ ); + $dbw->delete( 'page_props', [ 'pp_page' => $id ], __METHOD__ ); } // If using cleanup triggers, we can skip some manual deletes - if ( !$this->mDb->cleanupTriggers() ) { + if ( !$dbw->cleanupTriggers() ) { // Find recentchanges entries to clean up... - $rcIdsForTitle = $this->mDb->selectFieldValues( + $rcIdsForTitle = $dbw->selectFieldValues( 'recentchanges', 'rc_id', [ @@ -159,11 +164,11 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate 'rc_namespace' => $title->getNamespace(), 'rc_title' => $title->getDBkey(), 'rc_timestamp < ' . - $this->mDb->addQuotes( $this->mDb->timestamp( $this->timestamp ) ) + $dbw->addQuotes( $dbw->timestamp( $this->timestamp ) ) ], __METHOD__ ); - $rcIdsForPage = $this->mDb->selectFieldValues( + $rcIdsForPage = $dbw->selectFieldValues( 'recentchanges', 'rc_id', [ 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ], @@ -173,10 +178,10 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate // T98706: delete by PK to avoid lock contention with RC delete log insertions $rcIdBatches = array_chunk( array_merge( $rcIdsForTitle, $rcIdsForPage ), $batchSize ); foreach ( $rcIdBatches as $rcIdBatch ) { - $this->mDb->delete( 'recentchanges', [ 'rc_id' => $rcIdBatch ], __METHOD__ ); + $dbw->delete( 'recentchanges', [ 'rc_id' => $rcIdBatch ], __METHOD__ ); if ( count( $rcIdBatches ) > 1 ) { - $factory->commitAndWaitForReplication( - __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ] + $lbFactory->commitAndWaitForReplication( + __METHOD__, $this->ticket, [ 'wiki' => $dbw->getWikiID() ] ); } } @@ -187,17 +192,19 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate } private function batchDeleteByPK( $table, array $conds, array $pk, $bSize ) { - $dbw = $this->mDb; // convenience - $factory = wfGetLBFactory(); + $services = MediaWikiServices::getInstance(); + $lbFactory = $services->getDBLoadBalancerFactory(); + $dbw = $this->getDB(); // convenience + $res = $dbw->select( $table, $pk, $conds, __METHOD__ ); $pkDeleteConds = []; foreach ( $res as $row ) { - $pkDeleteConds[] = $this->mDb->makeList( (array)$row, LIST_AND ); + $pkDeleteConds[] = $dbw->makeList( (array)$row, LIST_AND ); if ( count( $pkDeleteConds ) >= $bSize ) { $dbw->delete( $table, $dbw->makeList( $pkDeleteConds, LIST_OR ), __METHOD__ ); - $factory->commitAndWaitForReplication( - __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ] + $lbFactory->commitAndWaitForReplication( + __METHOD__, $this->ticket, [ 'wiki' => $dbw->getWikiID() ] ); $pkDeleteConds = []; } @@ -208,9 +215,17 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate } } + protected function getDB() { + if ( !$this->db ) { + $this->db = wfGetDB( DB_MASTER ); + } + + return $this->db; + } + public function getAsJobSpecification() { return [ - 'wiki' => $this->mDb->getWikiID(), + 'wiki' => $this->getDB()->getWikiID(), 'job' => new JobSpecification( 'deleteLinks', [ 'pageId' => $this->pageId, 'timestamp' => $this->timestamp ], diff --git a/includes/deferred/LinksUpdate.php b/includes/deferred/LinksUpdate.php index ec7360e0d9..6124a71eac 100644 --- a/includes/deferred/LinksUpdate.php +++ b/includes/deferred/LinksUpdate.php @@ -20,6 +20,8 @@ * @file */ +use MediaWiki\MediaWikiServices; + /** * Class the manages updates of *_link tables as well as similar extension-managed tables * @@ -27,7 +29,7 @@ * * See docs/deferred.txt */ -class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { +class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate { // @todo make members protected, but make sure extensions don't break /** @var int Page ID of the article linked from */ @@ -94,6 +96,9 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { */ private $user; + /** @var IDatabase */ + private $db; + /** * Constructor * @@ -103,9 +108,6 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @throws MWException */ function __construct( Title $title, ParserOutput $parserOutput, $recursive = true ) { - // Implicit transactions are disabled as they interfere with batching - parent::__construct( false ); - $this->mTitle = $title; $this->mId = $title->getArticleID( Title::GAID_FOR_UPDATE ); @@ -160,7 +162,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { public function doUpdate() { // Make sure all links update threads see the changes of each other. // This handles the case when updates have to batched into several COMMITs. - $scopedLock = self::acquirePageLock( $this->mDb, $this->mId ); + $scopedLock = self::acquirePageLock( $this->getDB(), $this->mId ); Hooks::run( 'LinksUpdate', [ &$this ] ); $this->doIncrementalUpdate(); @@ -168,7 +170,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { // Commit and release the lock ScopedCallback::consume( $scopedLock ); // Run post-commit hooks without DBO_TRX - $this->mDb->onTransactionIdle( function() { + $this->getDB()->onTransactionIdle( function() { Hooks::run( 'LinksUpdateComplete', [ &$this ] ); } ); } @@ -315,7 +317,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @param array $cats */ function invalidateCategories( $cats ) { - PurgeJobUtils::invalidatePages( $this->mDb, NS_CATEGORY, array_keys( $cats ) ); + PurgeJobUtils::invalidatePages( $this->getDB(), NS_CATEGORY, array_keys( $cats ) ); } /** @@ -334,7 +336,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @param array $images */ function invalidateImageDescriptions( $images ) { - PurgeJobUtils::invalidatePages( $this->mDb, NS_FILE, array_keys( $images ) ); + PurgeJobUtils::invalidatePages( $this->getDB(), NS_FILE, array_keys( $images ) ); } /** @@ -345,8 +347,9 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @param array $insertions Rows to insert */ private function incrTableUpdate( $table, $prefix, $deletions, $insertions ) { - $bSize = RequestContext::getMain()->getConfig()->get( 'UpdateRowsPerQuery' ); - $factory = wfGetLBFactory(); + $services = MediaWikiServices::getInstance(); + $bSize = $services->getMainConfig()->get( 'UpdateRowsPerQuery' ); + $factory = $services->getDBLoadBalancerFactory(); if ( $table === 'page_props' ) { $fromField = 'pp_page'; @@ -378,7 +381,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { foreach ( $deletionBatches as $deletionBatch ) { $deleteWheres[] = [ $fromField => $this->mId, - $this->mDb->makeWhereFrom2d( $deletionBatch, $baseKey, "{$prefix}_title" ) + $this->getDB()->makeWhereFrom2d( $deletionBatch, $baseKey, "{$prefix}_title" ) ]; } } else { @@ -397,17 +400,17 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { } foreach ( $deleteWheres as $deleteWhere ) { - $this->mDb->delete( $table, $deleteWhere, __METHOD__ ); + $this->getDB()->delete( $table, $deleteWhere, __METHOD__ ); $factory->commitAndWaitForReplication( - __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ] + __METHOD__, $this->ticket, [ 'wiki' => $this->getDB()->getWikiID() ] ); } $insertBatches = array_chunk( $insertions, $bSize ); foreach ( $insertBatches as $insertBatch ) { - $this->mDb->insert( $table, $insertBatch, __METHOD__, 'IGNORE' ); + $this->getDB()->insert( $table, $insertBatch, __METHOD__, 'IGNORE' ); $factory->commitAndWaitForReplication( - __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ] + __METHOD__, $this->ticket, [ 'wiki' => $this->getDB()->getWikiID() ] ); } @@ -494,7 +497,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { foreach ( $diffs as $url => $dummy ) { foreach ( wfMakeUrlIndexes( $url ) as $index ) { $arr[] = [ - 'el_id' => $this->mDb->nextSequenceValue( 'externallinks_el_id_seq' ), + 'el_id' => $this->getDB()->nextSequenceValue( 'externallinks_el_id_seq' ), 'el_from' => $this->mId, 'el_to' => $url, 'el_index' => $index, @@ -540,7 +543,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { 'cl_from' => $this->mId, 'cl_to' => $name, 'cl_sortkey' => $sortkey, - 'cl_timestamp' => $this->mDb->timestamp(), + 'cl_timestamp' => $this->getDB()->timestamp(), 'cl_sortkey_prefix' => $prefix, 'cl_collation' => $wgCategoryCollation, 'cl_type' => $type, @@ -778,8 +781,8 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @return array */ private function getExistingLinks() { - $res = $this->mDb->select( 'pagelinks', [ 'pl_namespace', 'pl_title' ], - [ 'pl_from' => $this->mId ], __METHOD__, $this->mOptions ); + $res = $this->getDB()->select( 'pagelinks', [ 'pl_namespace', 'pl_title' ], + [ 'pl_from' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { if ( !isset( $arr[$row->pl_namespace] ) ) { @@ -797,8 +800,8 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @return array */ private function getExistingTemplates() { - $res = $this->mDb->select( 'templatelinks', [ 'tl_namespace', 'tl_title' ], - [ 'tl_from' => $this->mId ], __METHOD__, $this->mOptions ); + $res = $this->getDB()->select( 'templatelinks', [ 'tl_namespace', 'tl_title' ], + [ 'tl_from' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { if ( !isset( $arr[$row->tl_namespace] ) ) { @@ -816,8 +819,8 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @return array */ private function getExistingImages() { - $res = $this->mDb->select( 'imagelinks', [ 'il_to' ], - [ 'il_from' => $this->mId ], __METHOD__, $this->mOptions ); + $res = $this->getDB()->select( 'imagelinks', [ 'il_to' ], + [ 'il_from' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { $arr[$row->il_to] = 1; @@ -832,8 +835,8 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @return array */ private function getExistingExternals() { - $res = $this->mDb->select( 'externallinks', [ 'el_to' ], - [ 'el_from' => $this->mId ], __METHOD__, $this->mOptions ); + $res = $this->getDB()->select( 'externallinks', [ 'el_to' ], + [ 'el_from' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { $arr[$row->el_to] = 1; @@ -848,8 +851,8 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @return array */ private function getExistingCategories() { - $res = $this->mDb->select( 'categorylinks', [ 'cl_to', 'cl_sortkey_prefix' ], - [ 'cl_from' => $this->mId ], __METHOD__, $this->mOptions ); + $res = $this->getDB()->select( 'categorylinks', [ 'cl_to', 'cl_sortkey_prefix' ], + [ 'cl_from' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { $arr[$row->cl_to] = $row->cl_sortkey_prefix; @@ -865,8 +868,8 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @return array */ private function getExistingInterlangs() { - $res = $this->mDb->select( 'langlinks', [ 'll_lang', 'll_title' ], - [ 'll_from' => $this->mId ], __METHOD__, $this->mOptions ); + $res = $this->getDB()->select( 'langlinks', [ 'll_lang', 'll_title' ], + [ 'll_from' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { $arr[$row->ll_lang] = $row->ll_title; @@ -879,9 +882,9 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * Get an array of existing inline interwiki links, as a 2-D array * @return array (prefix => array(dbkey => 1)) */ - protected function getExistingInterwikis() { - $res = $this->mDb->select( 'iwlinks', [ 'iwl_prefix', 'iwl_title' ], - [ 'iwl_from' => $this->mId ], __METHOD__, $this->mOptions ); + private function getExistingInterwikis() { + $res = $this->getDB()->select( 'iwlinks', [ 'iwl_prefix', 'iwl_title' ], + [ 'iwl_from' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { if ( !isset( $arr[$row->iwl_prefix] ) ) { @@ -899,8 +902,8 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { * @return array Array of property names and values */ private function getExistingProperties() { - $res = $this->mDb->select( 'page_props', [ 'pp_propname', 'pp_value' ], - [ 'pp_page' => $this->mId ], __METHOD__, $this->mOptions ); + $res = $this->getDB()->select( 'page_props', [ 'pp_propname', 'pp_value' ], + [ 'pp_page' => $this->mId ], __METHOD__ ); $arr = []; foreach ( $res as $row ) { $arr[$row->pp_propname] = $row->pp_value; @@ -1050,18 +1053,29 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { /** * Update links table freshness */ - protected function updateLinksTimestamp() { + private function updateLinksTimestamp() { if ( $this->mId ) { // The link updates made here only reflect the freshness of the parser output $timestamp = $this->mParserOutput->getCacheTime(); - $this->mDb->update( 'page', - [ 'page_links_updated' => $this->mDb->timestamp( $timestamp ) ], + $this->getDB()->update( 'page', + [ 'page_links_updated' => $this->getDB()->timestamp( $timestamp ) ], [ 'page_id' => $this->mId ], __METHOD__ ); } } + /** + * @return IDatabase + */ + private function getDB() { + if ( !$this->db ) { + $this->db = wfGetDB( DB_MASTER ); + } + + return $this->db; + } + public function getAsJobSpecification() { if ( $this->user ) { $userInfo = [ @@ -1079,7 +1093,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate { } return [ - 'wiki' => $this->mDb->getWikiID(), + 'wiki' => $this->getDB()->getWikiID(), 'job' => new JobSpecification( 'refreshLinksPrioritized', [ -- 2.20.1