From 08698e48e8cf0987b9cbc35653e6cf4352ee3767 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Fri, 10 Jul 2015 16:18:23 -0700 Subject: [PATCH] Made the prior user existence check in LoginForm use DB_MASTER * This helps if multiple account creation attempts were made in a row and the slave selected was lagged (either too much for Chronology Protector or the user did not resend the cookies to link the session). * The locking also better handles concurrent attempt to make another account, especially with CentralAuth trying to make external accounts. This assumes that the rate of concurrent account creations with close names is low enough given trx speed to avoid gap locking issues. This will need to be confirmed with low error log rates to be sure. * The User::idFromName() method now includes a $flags parameter. Bug: T104615 Change-Id: I8385526a19efc528a016ad2bbf376b377138966b --- includes/User.php | 16 +++++++++++++--- includes/specials/SpecialUserlogin.php | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/includes/User.php b/includes/User.php index 63c0d37e45..dea9750b6a 100644 --- a/includes/User.php +++ b/includes/User.php @@ -3705,19 +3705,29 @@ class User implements IDBAccessObject { /** * If only this user's username is known, and it exists, return the user ID. + * + * @param int $flags Bitfield of User:READ_* constants; useful for existence checks * @return int */ - public function idForName() { + public function idForName( $flags = 0 ) { $s = trim( $this->getName() ); if ( $s === '' ) { return 0; } - $dbr = wfGetDB( DB_SLAVE ); - $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ ); + $db = ( ( $flags & self::READ_LATEST ) == self::READ_LATEST ) + ? wfGetDB( DB_MASTER ) + : wfGetDB( DB_SLAVE ); + + $options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING ) + ? array( 'FOR UPDATE' ) + : array(); + + $id = $db->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__, $options ); if ( $id === false ) { $id = 0; } + return $id; } diff --git a/includes/specials/SpecialUserlogin.php b/includes/specials/SpecialUserlogin.php index 472fdb71dc..aa5141514e 100644 --- a/includes/specials/SpecialUserlogin.php +++ b/includes/specials/SpecialUserlogin.php @@ -529,9 +529,9 @@ class LoginForm extends SpecialPage { # Now create a dummy user ($u) and check if it is valid $u = User::newFromName( $this->mUsername, 'creatable' ); - if ( !is_object( $u ) ) { + if ( !$u ) { return Status::newFatal( 'noname' ); - } elseif ( 0 != $u->idForName() ) { + } elseif ( 0 != $u->idForName( User::READ_LOCKING ) ) { return Status::newFatal( 'userexists' ); } -- 2.20.1