From e2088f1170b2867ca3ababe205137cc6ad010068 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Sat, 27 Oct 2018 07:34:52 -0700 Subject: [PATCH] Make UserEditCountUpdate faster by using auto-commit mode Bug: T202715 Change-Id: I92c08694cb5e1c367809439cff42e33a56ff9878 --- includes/deferred/UserEditCountUpdate.php | 78 +++++++++++------------ includes/user/User.php | 9 +-- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/includes/deferred/UserEditCountUpdate.php b/includes/deferred/UserEditCountUpdate.php index 2a1205c675..5194e4f1cc 100644 --- a/includes/deferred/UserEditCountUpdate.php +++ b/includes/deferred/UserEditCountUpdate.php @@ -66,48 +66,48 @@ class UserEditCountUpdate implements DeferrableUpdate, MergeableUpdate { * Purges the list of URLs passed to the constructor. */ public function doUpdate() { - foreach ( $this->infoByUser as $userId => $info ) { - $lb = MediaWikiServices::getInstance()->getDBLoadBalancer(); - $dbw = $lb->getConnection( DB_MASTER ); + $lb = MediaWikiServices::getInstance()->getDBLoadBalancer(); + $dbw = $lb->getConnection( DB_MASTER ); - $dbw->startAtomic( __METHOD__ ); // define minimum row lock duration - $dbw->update( - 'user', - [ 'user_editcount=user_editcount+' . (int)$info['increment'] ], - [ 'user_id' => $userId, 'user_editcount IS NOT NULL' ], - __METHOD__ - ); - /** @var User[] $affectedInstances */ - $affectedInstances = $info['instances']; - // Lazy initialization check... - if ( $dbw->affectedRows() == 0 ) { - // No rows will be "affected" if user_editcount is NULL. - // Get the generic "replica" connection to see if it actually uses the master. - $dbr = $lb->getConnection( DB_REPLICA ); - if ( $dbr !== $dbw ) { - // This method runs after the new revisions were committed. - // Wait for the replica to catch up so they will all be counted. - $dbr->flushSnapshot( __METHOD__ ); - $lb->safeWaitForMasterPos( $dbr ); + ( new AutoCommitUpdate( $dbw, __METHOD__, function () use ( $lb, $dbw ) { + foreach ( $this->infoByUser as $userId => $info ) { + $dbw->update( + 'user', + [ 'user_editcount=user_editcount+' . (int)$info['increment'] ], + [ 'user_id' => $userId, 'user_editcount IS NOT NULL' ], + __METHOD__ + ); + /** @var User[] $affectedInstances */ + $affectedInstances = $info['instances']; + // Lazy initialization check... + if ( $dbw->affectedRows() == 0 ) { + // No rows will be "affected" if user_editcount is NULL. + // Check if the generic "replica" connection is not the master. + $dbr = $lb->getConnection( DB_REPLICA ); + if ( $dbr !== $dbw ) { + // This method runs after the new revisions were committed. + // Wait for the replica to catch up so they will all be counted. + $dbr->flushSnapshot( __METHOD__ ); + $lb->safeWaitForMasterPos( $dbr ); + } + $affectedInstances[0]->initEditCountInternal(); } - $affectedInstances[0]->initEditCountInternal(); - } - $newCount = (int)$dbw->selectField( - 'user', - [ 'user_editcount' ], - [ 'user_id' => $userId ], - __METHOD__ - ); - $dbw->endAtomic( __METHOD__ ); + $newCount = (int)$dbw->selectField( + 'user', + [ 'user_editcount' ], + [ 'user_id' => $userId ], + __METHOD__ + ); - // Update the edit count in the instance caches. This is mostly useful - // for maintenance scripts, where deferred updates might run immediately - // and user instances might be reused for a long time. - foreach ( $affectedInstances as $affectedInstance ) { - $affectedInstance->setEditCountInternal( $newCount ); + // Update the edit count in the instance caches. This is mostly useful + // for maintenance scripts, where deferred updates might run immediately + // and user instances might be reused for a long time. + foreach ( $affectedInstances as $affectedInstance ) { + $affectedInstance->setEditCountInternal( $newCount ); + } + // Clear the edit count in user cache too + $affectedInstances[0]->invalidateCache(); } - // Clear the edit count in user cache too - $affectedInstances[0]->invalidateCache(); - } + } ) )->doUpdate(); } } diff --git a/includes/user/User.php b/includes/user/User.php index 9cd3ea1611..43be06e717 100644 --- a/includes/user/User.php +++ b/includes/user/User.php @@ -5350,10 +5350,9 @@ class User implements IDBAccessObject, UserIdentity { * * This method should not be called outside User/UserEditCountUpdate * - * @param int $add Edits to add to the count from the revision table * @return int Number of edits */ - public function initEditCountInternal( $add = 0 ) { + public function initEditCountInternal() { // Pull from a replica DB to be less cruel to servers // Accuracy isn't the point anyway here $dbr = wfGetDB( DB_REPLICA ); @@ -5366,13 +5365,15 @@ class User implements IDBAccessObject, UserIdentity { [], $actorWhere['joins'] ); - $count = $count + $add; $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'user', [ 'user_editcount' => $count ], - [ 'user_id' => $this->getId() ], + [ + 'user_id' => $this->getId(), + 'user_editcount IS NULL OR user_editcount < ' . (int)$count + ], __METHOD__ ); -- 2.20.1