Made the prior user existence check in LoginForm use DB_MASTER
authorAaron Schulz <aschulz@wikimedia.org>
Fri, 10 Jul 2015 23:18:23 +0000 (16:18 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Fri, 10 Jul 2015 23:45:28 +0000 (16:45 -0700)
* 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
includes/specials/SpecialUserlogin.php

index 63c0d37..dea9750 100644 (file)
@@ -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;
        }
 
index 472fdb7..aa51415 100644 (file)
@@ -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' );
                }