WordPress.org

Make WordPress Core

Changeset 27075


Ignore:
Timestamp:
02/02/14 22:06:42 (4 years ago)
Author:
nacin
Message:

When the MySQL server has "gone away," attempt to reconnect and retry the query.

props pento.
see #5932.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/wp-db.php

    r27074 r27075  
    157157     */ 
    158158    var $queries; 
     159 
     160    /** 
     161     * The number of times to retry reconnecting before dying. 
     162     * 
     163     * @since 3.9.0 
     164     * @access protected 
     165     * @see wpdb::check_connection() 
     166     * @var int 
     167     */ 
     168    protected $reconnect_retries = 5; 
    159169 
    160170    /** 
     
    11931203 
    11941204    /** 
    1195      * Connect to and select database 
     1205     * Connect to and select database. 
    11961206     * 
    11971207     * @since 3.0.0 
    1198      */ 
    1199     function db_connect() { 
     1208     * 
     1209     * @param bool $allow_bail Optional. Allows the function to bail, default true. If this is set 
     1210     *                         to false, you will need to handle the lack of database connection 
     1211     *                         manually. Available since 3.9.0. 
     1212     * 
     1213     * @return bool True with a successful connection, false on failure. 
     1214     */ 
     1215    function db_connect( $allow_bail = true ) { 
    12001216 
    12011217        $this->is_mysql = true; 
     
    12181234        } 
    12191235 
    1220         if ( !$this->dbh ) { 
     1236        if ( ! $this->dbh && $allow_bail ) { 
    12211237            wp_load_translations_early(); 
    12221238 
     
    12381254" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' ); 
    12391255 
    1240             return; 
    1241         } 
    1242  
    1243         $this->set_charset( $this->dbh ); 
    1244  
    1245         $this->set_sql_mode(); 
    1246  
    1247         $this->ready = true; 
    1248  
    1249         $this->select( $this->dbname, $this->dbh ); 
     1256            return false; 
     1257        } else if ( $this->dbh ) { 
     1258            $this->set_charset( $this->dbh ); 
     1259            $this->set_sql_mode(); 
     1260            $this->ready = true; 
     1261            $this->select( $this->dbname, $this->dbh ); 
     1262 
     1263            return true; 
     1264        } 
     1265 
     1266        return false; 
     1267    } 
     1268 
     1269    /** 
     1270     * Check that the connection to the database is still up. If not, try to reconnect. 
     1271     * 
     1272     * If this function is unable to reconnect, it will forcibly die. 
     1273     * 
     1274     * @since 3.9.0 
     1275     * 
     1276     * @return bool True if the connection is up. 
     1277     */ 
     1278    function check_connection() { 
     1279        if ( @mysql_ping( $this->dbh ) ) { 
     1280            return true; 
     1281        } 
     1282 
     1283        $error_reporting = false; 
     1284 
     1285        // Disable warnings, as we don't want to see a multitude of "unable to connect" messages 
     1286        if ( WP_DEBUG ) { 
     1287            $error_reporting = error_reporting(); 
     1288            error_reporting( $error_reporting & ~E_WARNING ); 
     1289        } 
     1290 
     1291        for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) { 
     1292            // On the last try, re-enable warnings. We want to see a single instance of the 
     1293            // "unable to connect" message on the bail() screen, if it appears. 
     1294            if ( $this->reconnect_retries === $tries && WP_DEBUG ) { 
     1295                error_reporting( $error_reporting ); 
     1296            } 
     1297 
     1298            if ( $this->db_connect( false ) ) { 
     1299                if ( $error_reporting ) { 
     1300                    error_reporting( $error_reporting ); 
     1301                } 
     1302 
     1303                return true; 
     1304            } 
     1305 
     1306            sleep( 1 ); 
     1307        } 
     1308 
     1309        // We weren't able to reconnect, so we better bail. 
     1310        $this->bail( sprintf( ( " 
     1311<h1>Error reconnecting to the database</h1> 
     1312<p>This means that we lost contact with the database server at <code>%s</code>. This could mean your host's database server is down.</p> 
     1313<ul> 
     1314    <li>Are you sure that the database server is running?</li> 
     1315    <li>Are you sure that the database server is not under particularly heavy load?</li> 
     1316</ul> 
     1317<p>If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href='http://wordpress.org/support/'>WordPress Support Forums</a>.</p> 
     1318" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' ); 
     1319 
     1320        // Call dead_db() if bail didn't die, because this database is no more. It has ceased to be (at least temporarily). 
     1321        dead_db(); 
    12501322    } 
    12511323 
     
    12631335        if ( ! $this->ready ) 
    12641336            return false; 
     1337 
    12651338        /** 
    12661339         * Filter the database query. 
     
    12821355        $this->last_query = $query; 
    12831356 
    1284         if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) 
    1285             $this->timer_start(); 
    1286  
    1287         $this->result = @mysql_query( $query, $this->dbh ); 
    1288         $this->num_queries++; 
    1289  
    1290         if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) 
    1291             $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() ); 
     1357        $this->_do_query( $query ); 
     1358 
     1359        // MySQL server has gone away, try to reconnect 
     1360        if ( empty( $this->dbh ) || 2006 == mysql_errno( $this->dbh ) ) { 
     1361            if ( $this->check_connection() ) { 
     1362                $this->_do_query( $query ); 
     1363            } 
     1364        } 
    12921365 
    12931366        // If there is an error then take note of it.. 
     
    13251398 
    13261399        return $return_val; 
     1400    } 
     1401 
     1402    /** 
     1403     * Internal function to perform the mysql_query call 
     1404     * 
     1405     * @since 3.9.0 
     1406     * 
     1407     * @access private 
     1408     * @see wpdb::query() 
     1409     * 
     1410     * @param string $query The query to run 
     1411     */ 
     1412    private function _do_query( $query ) { 
     1413        if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { 
     1414            $this->timer_start(); 
     1415        } 
     1416 
     1417        $this->result = @mysql_query( $query, $this->dbh ); 
     1418        $this->num_queries++; 
     1419 
     1420        if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { 
     1421            $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() ); 
     1422        } 
    13271423    } 
    13281424 
  • trunk/tests/phpunit/tests/db.php

    r27073 r27075  
    3939        $this->_queries[] = $sql; 
    4040        return $sql; 
     41    } 
     42 
     43    /** 
     44     * Test that WPDB will reconnect when the DB link dies 
     45     * @ticket 5932 
     46     */ 
     47    public function test_db_reconnect() { 
     48        global $wpdb; 
     49 
     50        $var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" ); 
     51        $this->assertGreaterThan( 0, $var ); 
     52 
     53        mysql_close( $wpdb->dbh ); 
     54        unset( $wpdb->dbh ); 
     55 
     56        $var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" ); 
     57        $this->assertGreaterThan( 0, $var ); 
    4158    } 
    4259 
Note: See TracChangeset for help on using the changeset viewer.