When the MySQL server has "gone away," attempt to reconnect and retry the query.
props pento. see #5932. git-svn-id: https://develop.svn.wordpress.org/trunk@27075 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
e993ef0249
commit
194d6a94b7
|
@ -157,6 +157,16 @@ class wpdb {
|
|||
*/
|
||||
var $queries;
|
||||
|
||||
/**
|
||||
* The number of times to retry reconnecting before dying.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @access protected
|
||||
* @see wpdb::check_connection()
|
||||
* @var int
|
||||
*/
|
||||
protected $reconnect_retries = 5;
|
||||
|
||||
/**
|
||||
* WordPress table prefix
|
||||
*
|
||||
|
@ -1192,11 +1202,17 @@ class wpdb {
|
|||
}
|
||||
|
||||
/**
|
||||
* Connect to and select database
|
||||
* Connect to and select database.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param bool $allow_bail Optional. Allows the function to bail, default true. If this is set
|
||||
* to false, you will need to handle the lack of database connection
|
||||
* manually. Available since 3.9.0.
|
||||
*
|
||||
* @return bool True with a successful connection, false on failure.
|
||||
*/
|
||||
function db_connect() {
|
||||
function db_connect( $allow_bail = true ) {
|
||||
|
||||
$this->is_mysql = true;
|
||||
|
||||
|
@ -1217,7 +1233,7 @@ class wpdb {
|
|||
$this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
|
||||
}
|
||||
|
||||
if ( !$this->dbh ) {
|
||||
if ( ! $this->dbh && $allow_bail ) {
|
||||
wp_load_translations_early();
|
||||
|
||||
// Load custom DB error template, if present.
|
||||
|
@ -1237,16 +1253,72 @@ class wpdb {
|
|||
<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>
|
||||
" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' );
|
||||
|
||||
return;
|
||||
return false;
|
||||
} else if ( $this->dbh ) {
|
||||
$this->set_charset( $this->dbh );
|
||||
$this->set_sql_mode();
|
||||
$this->ready = true;
|
||||
$this->select( $this->dbname, $this->dbh );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->set_charset( $this->dbh );
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->set_sql_mode();
|
||||
/**
|
||||
* Check that the connection to the database is still up. If not, try to reconnect.
|
||||
*
|
||||
* If this function is unable to reconnect, it will forcibly die.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*
|
||||
* @return bool True if the connection is up.
|
||||
*/
|
||||
function check_connection() {
|
||||
if ( @mysql_ping( $this->dbh ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->ready = true;
|
||||
$error_reporting = false;
|
||||
|
||||
$this->select( $this->dbname, $this->dbh );
|
||||
// Disable warnings, as we don't want to see a multitude of "unable to connect" messages
|
||||
if ( WP_DEBUG ) {
|
||||
$error_reporting = error_reporting();
|
||||
error_reporting( $error_reporting & ~E_WARNING );
|
||||
}
|
||||
|
||||
for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) {
|
||||
// On the last try, re-enable warnings. We want to see a single instance of the
|
||||
// "unable to connect" message on the bail() screen, if it appears.
|
||||
if ( $this->reconnect_retries === $tries && WP_DEBUG ) {
|
||||
error_reporting( $error_reporting );
|
||||
}
|
||||
|
||||
if ( $this->db_connect( false ) ) {
|
||||
if ( $error_reporting ) {
|
||||
error_reporting( $error_reporting );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sleep( 1 );
|
||||
}
|
||||
|
||||
// We weren't able to reconnect, so we better bail.
|
||||
$this->bail( sprintf( ( "
|
||||
<h1>Error reconnecting to the database</h1>
|
||||
<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>
|
||||
<ul>
|
||||
<li>Are you sure that the database server is running?</li>
|
||||
<li>Are you sure that the database server is not under particularly heavy load?</li>
|
||||
</ul>
|
||||
<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>
|
||||
" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' );
|
||||
|
||||
// Call dead_db() if bail didn't die, because this database is no more. It has ceased to be (at least temporarily).
|
||||
dead_db();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1262,6 +1334,7 @@ class wpdb {
|
|||
function query( $query ) {
|
||||
if ( ! $this->ready )
|
||||
return false;
|
||||
|
||||
/**
|
||||
* Filter the database query.
|
||||
*
|
||||
|
@ -1281,14 +1354,14 @@ class wpdb {
|
|||
// Keep track of the last query for debug..
|
||||
$this->last_query = $query;
|
||||
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
|
||||
$this->timer_start();
|
||||
$this->_do_query( $query );
|
||||
|
||||
$this->result = @mysql_query( $query, $this->dbh );
|
||||
$this->num_queries++;
|
||||
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
|
||||
$this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
|
||||
// MySQL server has gone away, try to reconnect
|
||||
if ( empty( $this->dbh ) || 2006 == mysql_errno( $this->dbh ) ) {
|
||||
if ( $this->check_connection() ) {
|
||||
$this->_do_query( $query );
|
||||
}
|
||||
}
|
||||
|
||||
// If there is an error then take note of it..
|
||||
if ( $this->last_error = mysql_error( $this->dbh ) ) {
|
||||
|
@ -1326,6 +1399,29 @@ class wpdb {
|
|||
return $return_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to perform the mysql_query call
|
||||
*
|
||||
* @since 3.9.0
|
||||
*
|
||||
* @access private
|
||||
* @see wpdb::query()
|
||||
*
|
||||
* @param string $query The query to run
|
||||
*/
|
||||
private function _do_query( $query ) {
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
||||
$this->timer_start();
|
||||
}
|
||||
|
||||
$this->result = @mysql_query( $query, $this->dbh );
|
||||
$this->num_queries++;
|
||||
|
||||
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
||||
$this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a row into a table.
|
||||
*
|
||||
|
|
|
@ -40,6 +40,23 @@ class Tests_DB extends WP_UnitTestCase {
|
|||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that WPDB will reconnect when the DB link dies
|
||||
* @ticket 5932
|
||||
*/
|
||||
public function test_db_reconnect() {
|
||||
global $wpdb;
|
||||
|
||||
$var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" );
|
||||
$this->assertGreaterThan( 0, $var );
|
||||
|
||||
mysql_close( $wpdb->dbh );
|
||||
unset( $wpdb->dbh );
|
||||
|
||||
$var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" );
|
||||
$this->assertGreaterThan( 0, $var );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that floats formatted as "0,700" get sanitized properly by wpdb
|
||||
* @global mixed $wpdb
|
||||
|
|
Loading…
Reference in New Issue