From 325faeea8385e65f395709622da79ade1ed68ff7 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Thu, 26 Nov 2015 15:17:26 -0800 Subject: [PATCH] Defer the redirect table update in WikiPage::insertRedirect() This avoids contention slams and synchronous master DB writes on HTTP GET requests. Bug: T119742 Bug: T92357 Change-Id: I7b3ebac0d6a11542c47ddf3219911be54380c537 --- includes/page/WikiPage.php | 50 +++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 98bca0525b..1e59d95a58 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -881,7 +881,8 @@ class WikiPage implements Page, IDBAccessObject { if ( $row && !is_null( $row->rd_fragment ) && !is_null( $row->rd_interwiki ) ) { $this->mRedirectTarget = Title::makeTitle( $row->rd_namespace, $row->rd_title, - $row->rd_fragment, $row->rd_interwiki ); + $row->rd_fragment, $row->rd_interwiki + ); return $this->mRedirectTarget; } @@ -891,39 +892,54 @@ class WikiPage implements Page, IDBAccessObject { } /** - * Insert an entry for this page into the redirect table. + * Insert an entry for this page into the redirect table if the content is a redirect + * + * The database update will be deferred via DeferredUpdates * * Don't call this function directly unless you know what you're doing. * @return Title|null Title object or null if not a redirect */ public function insertRedirect() { - // recurse through to only get the final target $content = $this->getContent(); $retval = $content ? $content->getUltimateRedirectTarget() : null; if ( !$retval ) { return null; } - $this->insertRedirectEntry( $retval ); + + // Update the DB post-send if the page has not cached since now + $that = $this; + $latest = $this->getLatest(); + DeferredUpdates::addCallableUpdate( function() use ( $that, $retval, $latest ) { + $that->insertRedirectEntry( $retval, $latest ); + } ); + return $retval; } /** - * Insert or update the redirect table entry for this page to indicate - * it redirects to $rt . + * Insert or update the redirect table entry for this page to indicate it redirects to $rt * @param Title $rt Redirect target + * @param int|null $oldLatest Prior page_latest for check and set */ - public function insertRedirectEntry( $rt ) { + public function insertRedirectEntry( Title $rt, $oldLatest = null ) { $dbw = wfGetDB( DB_MASTER ); - $dbw->replace( 'redirect', array( 'rd_from' ), - array( - 'rd_from' => $this->getId(), - 'rd_namespace' => $rt->getNamespace(), - 'rd_title' => $rt->getDBkey(), - 'rd_fragment' => $rt->getFragment(), - 'rd_interwiki' => $rt->getInterwiki(), - ), - __METHOD__ - ); + $dbw->startAtomic( __METHOD__ ); + + if ( !$oldLatest || $oldLatest == $this->lockAndGetLatest() ) { + $dbw->replace( 'redirect', + array( 'rd_from' ), + array( + 'rd_from' => $this->getId(), + 'rd_namespace' => $rt->getNamespace(), + 'rd_title' => $rt->getDBkey(), + 'rd_fragment' => $rt->getFragment(), + 'rd_interwiki' => $rt->getInterwiki(), + ), + __METHOD__ + ); + } + + $dbw->endAtomic( __METHOD__ ); } /** -- 2.20.1