From 7b59841f43b94a523a7bcf5c2e1bbc90e6168e7f Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Fri, 29 May 2015 12:35:16 -0700 Subject: [PATCH] Reduce page deletion lock contention Bug: T98706 Change-Id: Ib37e74c4737de9d705af28ac2eac06e716dd5f10 --- includes/page/WikiPage.php | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 5e4438ac7a..7d990d941a 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -2769,9 +2769,16 @@ class WikiPage implements Page, IDBAccessObject { $dbw->begin( __METHOD__ ); if ( $id == 0 ) { - $this->loadPageData( 'forupdate' ); + // T98706: lock the page from various other updates but avoid using + // WikiPage::READ_LOCKING as that will carry over the FOR UPDATE to + // the revisions queries (which also JOIN on user). Only lock the page + // row and CAS check on page_latest to see if the trx snapshot matches. + $latest = $this->lock(); + + $this->loadPageData( WikiPage::READ_LATEST ); $id = $this->getID(); - if ( $id == 0 ) { + if ( $id == 0 || $this->getLatest() != $latest ) { + // Page not there or trx snapshot is stale $dbw->rollback( __METHOD__ ); $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) ); return $status; @@ -2878,6 +2885,24 @@ class WikiPage implements Page, IDBAccessObject { return $status; } + /** + * Lock the page row for this title and return page_latest (or 0) + * + * @return integer + */ + protected function lock() { + return (int)wfGetDB( DB_MASTER )->selectField( + 'page', + 'page_latest', + array( + 'page_namespace' => $this->getTitle()->getNamespace(), + 'page_title' => $this->getTitle()->getDBkey() + ), + __METHOD__, + array( 'FOR UPDATE' ) + ); + } + /** * Do some database updates after deletion * -- 2.20.1