From 20f78684b8db0f5d8de7093f5c0b9412d8498935 Mon Sep 17 00:00:00 2001 From: Erik Bernhardson Date: Fri, 15 Aug 2014 14:04:10 -0700 Subject: [PATCH] Use batch inserts for watchlist Inserting a watchlist item was using two queries where only one was necessary. This adjusts to use a single query and adds the ability to watchlist multiple titles simultaneously. Change-Id: I331238524598f1ee87c28104ab02edf4b2afaaf2 --- includes/WatchedItem.php | 68 +++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/includes/WatchedItem.php b/includes/WatchedItem.php index f69fe6334f..93d6c0b136 100644 --- a/includes/WatchedItem.php +++ b/includes/WatchedItem.php @@ -270,45 +270,61 @@ class WatchedItem { } /** - * Given a title and user (assumes the object is setup), add the watch to the database. + * @param WatchedItem[] $items * @return bool */ - public function addWatch() { - wfProfileIn( __METHOD__ ); + static public function batchAddWatch( array $items ) { + $section = new ProfileSection( __METHOD__ ); - // Only loggedin user can have a watchlist - if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) { - wfProfileOut( __METHOD__ ); + if ( wfReadOnly() ) { return false; } - // Use INSERT IGNORE to avoid overwriting the notification timestamp - // if there's already an entry for this page - $dbw = wfGetDB( DB_MASTER ); - $dbw->insert( 'watchlist', - array( - 'wl_user' => $this->getUserId(), - 'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ), - 'wl_title' => $this->getTitleDBkey(), + $rows = array(); + foreach ( $items as $item ) { + // Only loggedin user can have a watchlist + if ( $item->mUser->isAnon() || !$item->isAllowed( 'editmywatchlist' ) ) { + continue; + } + $rows[] = array( + 'wl_user' => $item->getUserId(), + 'wl_namespace' => MWNamespace::getSubject( $item->getTitleNs() ), + 'wl_title' => $item->getTitleDBkey(), + 'wl_notificationtimestamp' => null, + ); + // Every single watched page needs now to be listed in watchlist; + // namespace:page and namespace_talk:page need separate entries: + $rows[] = array( + 'wl_user' => $item->getUserId(), + 'wl_namespace' => MWNamespace::getTalk( $item->getTitleNs() ), + 'wl_title' => $item->getTitleDBkey(), 'wl_notificationtimestamp' => null - ), __METHOD__, 'IGNORE' ); + ); + $item->watched = true; + } - // Every single watched page needs now to be listed in watchlist; - // namespace:page and namespace_talk:page need separate entries: - $dbw->insert( 'watchlist', - array( - 'wl_user' => $this->getUserId(), - 'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ), - 'wl_title' => $this->getTitleDBkey(), - 'wl_notificationtimestamp' => null - ), __METHOD__, 'IGNORE' ); + if ( !$rows ) { + return false; + } - $this->watched = true; + $dbw = wfGetDB( DB_MASTER ); + foreach( array_chunk( $rows, 100 ) as $toInsert ) { + // Use INSERT IGNORE to avoid overwriting the notification timestamp + // if there's already an entry for this page + $dbw->insert( 'watchlist', $toInsert, __METHOD__, 'IGNORE' ); + } - wfProfileOut( __METHOD__ ); return true; } + /** + * Given a title and user (assumes the object is setup), add the watch to the database. + * @return bool + */ + public function addWatch() { + return self::batchAddWatch( array( $this ) ); + } + /** * Same as addWatch, only the opposite. * @return bool -- 2.20.1