Merge "Make server index validity checks in LoadBalancer actually work"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 11 Oct 2016 20:02:04 +0000 (20:02 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 11 Oct 2016 20:02:04 +0000 (20:02 +0000)
1  2 
includes/libs/rdbms/loadbalancer/LoadBalancer.php

@@@ -105,9 -105,10 +105,9 @@@ class LoadBalancer implements ILoadBala
  
        /** @var integer Warn when this many connection are held */
        const CONN_HELD_WARN_THRESHOLD = 10;
 +
        /** @var integer Default 'max lag' when unspecified */
        const MAX_LAG_DEFAULT = 10;
 -      /** @var integer Max time to wait for a replica DB to catch up (e.g. ChronologyProtector) */
 -      const POS_WAIT_TIMEOUT = 10;
        /** @var integer Seconds to cache master server read-only status */
        const TTL_CACHE_READONLY = 5;
  
                        $this->localDomainIdAlias = $this->localDomain->getDatabase();
                }
  
 -              $this->mWaitTimeout = isset( $params['waitTimeout'] )
 -                      ? $params['waitTimeout']
 -                      : self::POS_WAIT_TIMEOUT;
 +              $this->mWaitTimeout = isset( $params['waitTimeout'] ) ? $params['waitTimeout'] : 10;
  
                $this->mReadIndex = -1;
                $this->mConns = [
                }
  
                # Scale the configured load ratios according to the dynamic load if supported
 -              $this->getLoadMonitor()->scaleLoads( $nonErrorLoads, $group, $domain );
 +              $this->getLoadMonitor()->scaleLoads( $nonErrorLoads, $domain );
  
                $laggedReplicaMode = false;
  
  
                                return false;
                        } else {
 -                              $conn = $this->openConnection( $index, '' );
 +                              $conn = $this->openConnection( $index, self::DOMAIN_ANY );
                                if ( !$conn ) {
                                        $this->replLogger->warning( __METHOD__ . ": failed to connect to $server" );
  
                        return;
                }
  
 +              if ( $this->disabled ) {
 +                      return; // DBConnRef handle probably survived longer than the LoadBalancer
 +              }
 +
                $domain = $conn->getDomainID();
 -              if ( $this->mConns['foreignUsed'][$serverIndex][$domain] !== $conn ) {
 +              if ( !isset( $this->mConns['foreignUsed'][$serverIndex][$domain] ) ) {
 +                      throw new InvalidArgumentException( __METHOD__ .
 +                              ": connection $serverIndex/$domain not found; it may have already been freed." );
 +              } elseif ( $this->mConns['foreignUsed'][$serverIndex][$domain] !== $conn ) {
                        throw new InvalidArgumentException( __METHOD__ .
 -                              ": connection not found, has the connection been freed already?" );
 +                              ": connection $serverIndex/$domain mismatched; it may have already been freed." );
                }
                $conn->setLBInfo( 'foreignPoolRefCount', --$refCount );
                if ( $refCount <= 0 ) {
                } elseif ( isset( $this->mConns['local'][$i][0] ) ) {
                        $conn = $this->mConns['local'][$i][0];
                } else {
+                       if ( !isset( $this->mServers[$i] ) || !is_array( $this->mServers[$i] ) ) {
+                               throw new InvalidArgumentException( "No server with index '$i'." );
+                       }
+                       // Open a new connection
                        $server = $this->mServers[$i];
                        $server['serverIndex'] = $i;
                        $conn = $this->reallyOpenConnection( $server, false );
                                        ": reusing free connection from $oldDomain for $domain" );
                        }
                } else {
+                       if ( !isset( $this->mServers[$i] ) || !is_array( $this->mServers[$i] ) ) {
+                               throw new InvalidArgumentException( "No server with index '$i'." );
+                       }
                        // Open a new connection
                        $server = $this->mServers[$i];
                        $server['serverIndex'] = $i;
         * @throws DBAccessError
         * @throws InvalidArgumentException
         */
-       protected function reallyOpenConnection( $server, $dbNameOverride = false ) {
+       protected function reallyOpenConnection( array $server, $dbNameOverride = false ) {
                if ( $this->disabled ) {
                        throw new DBAccessError();
                }
  
-               if ( !is_array( $server ) ) {
-                       throw new InvalidArgumentException(
-                               'You must update your load-balancing configuration. ' .
-                               'See DefaultSettings.php entry for $wgDBservers.' );
-               }
                if ( $dbNameOverride !== false ) {
                        $server['dbname'] = $dbNameOverride;
                }
                }
  
                if ( !$pos ) {
 -                      // Get the current master position
 -                      $dbw = $this->getConnection( self::DB_MASTER );
 -                      $pos = $dbw->getMasterPos();
 -                      $this->reuseConnection( $dbw );
 +                      // Get the current master position, opening a connection if needed
 +                      $masterConn = $this->getAnyOpenConnection( $this->getWriterIndex() );
 +                      if ( $masterConn ) {
 +                              $pos = $masterConn->getMasterPos();
 +                      } else {
 +                              $masterConn = $this->openConnection( $this->getWriterIndex(), self::DOMAIN_ANY );
 +                              $pos = $masterConn->getMasterPos();
 +                              $this->closeConnection( $masterConn );
 +                      }
                }
  
                if ( $pos instanceof DBMasterPos ) {
                return $ok;
        }
  
 -      public function clearLagTimeCache() {
 -              $this->getLoadMonitor()->clearCaches();
 -      }
 -
        public function setTransactionListener( $name, callable $callback = null ) {
                if ( $callback ) {
                        $this->trxRecurringCallbacks[$name] = $callback;
  
        function __destruct() {
                // Avoid connection leaks for sanity
 -              $this->closeAll();
 +              $this->disable();
        }
  }