From 70ed89ad436f9a5c9090e9927c40a701db6cf93f Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Tue, 17 Jul 2018 21:22:59 +0100 Subject: [PATCH] Reduce the rate of calls to Category::refreshCounts Bug: T199762 Change-Id: I23e2e1ebf187d21ea4bd22304aa622199a8b9c5b --- includes/Category.php | 41 +++++++++++++++++++++++ includes/deferred/LinksDeletionUpdate.php | 32 ++---------------- includes/page/WikiPage.php | 21 +++--------- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/includes/Category.php b/includes/Category.php index f8ac8aeb59..3352c2c2b0 100644 --- a/includes/Category.php +++ b/includes/Category.php @@ -420,4 +420,45 @@ class Category { return true; } + + /** + * Call refreshCounts() if there are no entries in the categorylinks table + * or if the category table has a row that states that there are no entries + * + * Due to lock errors or other failures, the precomputed counts can get out of sync, + * making it hard to know when to delete the category row without checking the + * categorylinks table. + * + * @return bool Whether links were refreshed + * @since 1.32 + */ + public function refreshCountsIfEmpty() { + $dbw = wfGetDB( DB_MASTER ); + + $hasLink = $dbw->selectField( + 'categorylinks', + '1', + [ 'cl_to' => $this->getName() ], + __METHOD__ + ); + if ( !$hasLink ) { + $this->refreshCounts(); // delete any category table entry + + return true; + } + + $hasBadRow = $dbw->selectField( + 'category', + '1', + [ 'cat_title' => $this->getName(), 'cat_pages <= 0' ], + __METHOD__ + ); + if ( $hasBadRow ) { + $this->refreshCounts(); // clean up this row + + return true; + } + + return false; + } } diff --git a/includes/deferred/LinksDeletionUpdate.php b/includes/deferred/LinksDeletionUpdate.php index 9f6257c810..f370e43ffd 100644 --- a/includes/deferred/LinksDeletionUpdate.php +++ b/includes/deferred/LinksDeletionUpdate.php @@ -101,7 +101,8 @@ class LinksDeletionUpdate extends DataUpdate implements EnqueueableDataUpdate { if ( $title->getNamespace() === NS_CATEGORY ) { // T166757: do the update after the main job DB commit DeferredUpdates::addCallableUpdate( function () use ( $title ) { - $this->refreshCategoryIfEmpty( $title ); + $cat = Category::newFromName( $title->getDBkey() ); + $cat->refreshCountsIfEmpty(); } ); } @@ -187,35 +188,6 @@ class LinksDeletionUpdate extends DataUpdate implements EnqueueableDataUpdate { ScopedCallback::consume( $scopedLock ); } - /** - * @param Title $title - */ - private function refreshCategoryIfEmpty( Title $title ) { - $dbw = $this->getDB(); - - $row = $dbw->selectRow( - 'category', - [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ], - [ 'cat_title' => $title->getDBkey(), 'cat_pages <= 100' ], - __METHOD__ - ); - - if ( !$row ) { - return; // nothing to delete - } - - $cat = Category::newFromRow( $row, $title ); - $hasLink = $dbw->selectField( - 'categorylinks', - '1', - [ 'cl_to' => $title->getDBkey() ], - __METHOD__ - ); - if ( !$hasLink ) { - $cat->refreshCounts(); // delete the category table entry - } - } - private function batchDeleteByPK( $table, array $conds, array $pk, $bSize ) { $services = MediaWikiServices::getInstance(); $lbFactory = $services->getDBLoadBalancerFactory(); diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 7cc25bd3fc..0a80892eb1 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -3343,23 +3343,10 @@ class WikiPage implements Page, IDBAccessObject { foreach ( $deleted as $catName ) { $cat = Category::newFromName( $catName ); Hooks::run( 'CategoryAfterPageRemoved', [ $cat, $this, $id ] ); - } - - // Refresh counts on categories that should be empty now - if ( count( $deleted ) ) { - $rows = $dbw->select( - 'category', - [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ], - [ 'cat_title' => $deleted, 'cat_pages <= 100' ], - __METHOD__ - ); - foreach ( $rows as $row ) { - $cat = Category::newFromRow( $row ); - // T166757: do the update after this DB commit - DeferredUpdates::addCallableUpdate( function () use ( $cat ) { - $cat->refreshCounts(); - } ); - } + // Refresh counts on categories that should be empty now (after commit, T166757) + DeferredUpdates::addCallableUpdate( function () use ( $cat ) { + $cat->refreshCountsIfEmpty(); + } ); } } -- 2.20.1