WordPress.org

Make WordPress Core

Changeset 27075


Ignore:
Timestamp:
02/02/2014 10:06:42 PM (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.