Core Upgrader: Add a locking mechanism to avoid two concurrent updates of WordPress occuring.
Fixes #34878 Built from https://develop.svn.wordpress.org/trunk@36349 git-svn-id: http://core.svn.wordpress.org/trunk@36316 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
60a9f41315
commit
006ae74d4c
|
@ -751,6 +751,64 @@ class WP_Upgrader {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Lock using WordPress options.
|
||||
*
|
||||
* @since 4.5.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $lock_name The name of this unique lock.
|
||||
* @param int $release_timeout The duration in seconds to respect an existing lock. Default: 1 hour.
|
||||
* @return bool
|
||||
*/
|
||||
public function create_lock( $lock_name, $release_timeout = null ) {
|
||||
global $wpdb;
|
||||
if ( ! $release_timeout ) {
|
||||
$release_timeout = HOUR_IN_SECONDS;
|
||||
}
|
||||
$lock_option = $lock_name . '.lock';
|
||||
|
||||
// Try to lock
|
||||
$lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_option, time() ) );
|
||||
|
||||
if ( ! $lock_result ) {
|
||||
$lock_result = get_option( $lock_option );
|
||||
|
||||
// If we couldn't create a lock, and there isn't a lock, bail
|
||||
if ( ! $lock_result ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if the lock is still valid
|
||||
if ( $lock_result > ( time() - $release_timeout ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There must exist an expired lock, clear it and re-gain it.
|
||||
$this->release_lock( $lock_name );
|
||||
|
||||
return $this->create_lock( $lock_name, $release_timeout );
|
||||
}
|
||||
|
||||
// Update the lock, as by this point we've definitely got a lock, just need to fire the actions
|
||||
update_option( $lock_option, time() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a lock created by `WP_Upgrader::create_lock()`.
|
||||
*
|
||||
* @since 4.5.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $lock_name The name of this unique lock.
|
||||
* @return bool
|
||||
*/
|
||||
public function release_lock( $lock_name ) {
|
||||
return delete_option( $lock_name . '.lock' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2168,6 +2226,7 @@ class Core_Upgrader extends WP_Upgrader {
|
|||
*/
|
||||
public function upgrade_strings() {
|
||||
$this->strings['up_to_date'] = __('WordPress is at the latest version.');
|
||||
$this->strings['locked'] = __('Another update is currently in progress.');
|
||||
$this->strings['no_package'] = __('Update package not available.');
|
||||
$this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…');
|
||||
$this->strings['unpack_package'] = __('Unpacking the update…');
|
||||
|
@ -2252,25 +2311,38 @@ class Core_Upgrader extends WP_Upgrader {
|
|||
else
|
||||
$to_download = 'full';
|
||||
|
||||
// Lock to prevent multiple Core Updates occuring
|
||||
$lock = $this->create_lock( 'core_updater', 15 * MINUTE_IN_SECONDS );
|
||||
if ( ! $lock ) {
|
||||
return new WP_Error( 'locked', $this->strings['locked'] );
|
||||
}
|
||||
|
||||
$download = $this->download_package( $current->packages->$to_download );
|
||||
if ( is_wp_error($download) )
|
||||
if ( is_wp_error( $download ) ) {
|
||||
$this->release_lock( 'core_updater' );
|
||||
return $download;
|
||||
}
|
||||
|
||||
$working_dir = $this->unpack_package( $download );
|
||||
if ( is_wp_error($working_dir) )
|
||||
if ( is_wp_error( $working_dir ) ) {
|
||||
$this->release_lock( 'core_updater' );
|
||||
return $working_dir;
|
||||
}
|
||||
|
||||
// Copy update-core.php from the new version into place.
|
||||
if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) {
|
||||
$wp_filesystem->delete($working_dir, true);
|
||||
$this->release_lock( 'core_updater' );
|
||||
return new WP_Error( 'copy_failed_for_update_core_file', __( 'The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.' ), 'wp-admin/includes/update-core.php' );
|
||||
}
|
||||
$wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE);
|
||||
|
||||
require_once( ABSPATH . 'wp-admin/includes/update-core.php' );
|
||||
|
||||
if ( ! function_exists( 'update_core' ) )
|
||||
if ( ! function_exists( 'update_core' ) ) {
|
||||
$this->release_lock( 'core_updater' );
|
||||
return new WP_Error( 'copy_failed_space', $this->strings['copy_failed_space'] );
|
||||
}
|
||||
|
||||
$result = update_core( $working_dir, $wp_dir );
|
||||
|
||||
|
@ -2345,6 +2417,8 @@ class Core_Upgrader extends WP_Upgrader {
|
|||
wp_version_check( $stats );
|
||||
}
|
||||
|
||||
$this->release_lock( 'core_updater' );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -2938,8 +3012,13 @@ class WP_Automatic_Updater {
|
|||
$upgrade_result = new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) );
|
||||
}
|
||||
|
||||
// Core doesn't output this, so let's append it so we don't get confused.
|
||||
if ( 'core' == $type ) {
|
||||
if ( is_wp_error( $upgrade_result ) && ( 'up_to_date' == $upgrade_result->get_error_code() || 'locked' == $upgrade_result->get_error_code() ) ) {
|
||||
// These aren't actual errors, treat it as a skipped-update instead to avoid triggering the post-core update failure routines.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Core doesn't output this, so let's append it so we don't get confused.
|
||||
if ( is_wp_error( $upgrade_result ) ) {
|
||||
$skin->error( __( 'Installation Failed' ), $upgrade_result );
|
||||
} else {
|
||||
|
@ -2975,26 +3054,9 @@ class WP_Automatic_Updater {
|
|||
if ( ! is_main_network() || ! is_main_site() )
|
||||
return;
|
||||
|
||||
$lock_name = 'auto_updater.lock';
|
||||
|
||||
// Try to lock
|
||||
$lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) );
|
||||
|
||||
if ( ! $lock_result ) {
|
||||
$lock_result = get_option( $lock_name );
|
||||
|
||||
// If we couldn't create a lock, and there isn't a lock, bail
|
||||
if ( ! $lock_result )
|
||||
if ( ! $this->create_lock( 'auto_updater' ) )
|
||||
return;
|
||||
|
||||
// Check to see if the lock is still valid
|
||||
if ( $lock_result > ( time() - HOUR_IN_SECONDS ) )
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the lock, as by this point we've definitely got a lock, just need to fire the actions
|
||||
update_option( $lock_name, time() );
|
||||
|
||||
// Don't automatically run these thins, as we'll handle it ourselves
|
||||
remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
|
||||
remove_action( 'upgrader_process_complete', 'wp_version_check' );
|
||||
|
@ -3092,8 +3154,7 @@ class WP_Automatic_Updater {
|
|||
do_action( 'automatic_updates_complete', $this->update_results );
|
||||
}
|
||||
|
||||
// Clear the lock
|
||||
delete_option( $lock_name );
|
||||
$this->release_lock( 'auto_updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3163,7 +3224,7 @@ class WP_Automatic_Updater {
|
|||
* the issue could actually be on WordPress.org's side.) If that one fails, then email.
|
||||
*/
|
||||
$send = true;
|
||||
$transient_failures = array( 'incompatible_archive', 'download_failed', 'insane_distro' );
|
||||
$transient_failures = array( 'incompatible_archive', 'download_failed', 'insane_distro', 'locked' );
|
||||
if ( in_array( $error_code, $transient_failures ) && ! get_site_option( 'auto_core_update_failed' ) ) {
|
||||
wp_schedule_single_event( time() + HOUR_IN_SECONDS, 'wp_maybe_auto_update' );
|
||||
$send = false;
|
||||
|
|
|
@ -484,7 +484,7 @@ function do_core_upgrade( $reinstall = false ) {
|
|||
|
||||
if ( is_wp_error($result) ) {
|
||||
show_message($result);
|
||||
if ('up_to_date' != $result->get_error_code() )
|
||||
if ( 'up_to_date' != $result->get_error_code() && 'locked' != $result->get_error_code() )
|
||||
show_message( __('Installation Failed') );
|
||||
echo '</div>';
|
||||
return;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '4.5-alpha-1453176612026';
|
||||
$wp_version = '4.5-alpha-1453180032918';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue