From 9590b4684d4ff87a5986742bf00ea0a91e061b0c Mon Sep 17 00:00:00 2001 From: Sem Date: Mon, 9 Jul 2012 02:02:59 +0200 Subject: Fixes #4643. Locks the upgrade process while it is running. --- upgrade.php | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/upgrade.php b/upgrade.php index 60764ba93..38be476a4 100644 --- a/upgrade.php +++ b/upgrade.php @@ -13,6 +13,35 @@ * @subpackage Upgrade */ +function upgrade_lock() { + global $CONFIG, $DB_QUERY_CACHE; + + $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}locked'")); + + // Invalidate query cache + if ($DB_QUERY_CACHE) { + $DB_QUERY_CACHE->clear(); + elgg_log("Query cache invalidated", 'NOTICE'); + } + + if (!$is_locked) { + // lock it + insert_data("create table {$CONFIG->dbprefix}locked (id INT)"); + error_log('Upgrade continue running'); + return true; + } + + error_log('Upgrade is locked'); + return false; +} + +function upgrade_unlock() { + global $CONFIG; + delete_data("drop table {$CONFIG->dbprefix}locked"); + error_log('Upgrade unlocks itself'); +} + + // we want to know if an error occurs ini_set('display_errors', 1); @@ -20,6 +49,12 @@ define('UPGRADING', 'upgrading'); require_once(dirname(__FILE__) . "/engine/start.php"); if (get_input('upgrade') == 'upgrade') { + + // prevent someone from running the upgrade script in parallel (see #4643) + if (!upgrade_lock()) { + forward(); + } + // disable the system log for upgrades to avoid exceptions when the schema changes. elgg_unregister_event_handler('log', 'systemlog', 'system_log_default_logger'); elgg_unregister_event_handler('all', 'all', 'system_log_listener'); @@ -33,6 +68,10 @@ if (get_input('upgrade') == 'upgrade') { elgg_trigger_event('upgrade', 'system', null); elgg_invalidate_simplecache(); elgg_reset_system_cache(); + + // critical region has past + upgrade_unlock(); + } else { // if upgrading from < 1.8.0, check for the core view 'welcome' and bail if it's found. // see http://trac.elgg.org/ticket/3064 @@ -53,4 +92,4 @@ if (get_input('upgrade') == 'upgrade') { exit; } -forward(); \ No newline at end of file +forward(); -- cgit v1.2.3 From dce60b43126dcaa38e6845ae45e09db87aa7e229 Mon Sep 17 00:00:00 2001 From: Sem Date: Tue, 17 Jul 2012 02:46:53 +0200 Subject: Refs #4643. Added unlock upgrade action. --- actions/admin/site/unlock_upgrade.php | 23 ++++++++++++++++++ engine/lib/admin.php | 1 + languages/en.php | 3 +++ upgrade.php | 2 ++ views/default/widgets/control_panel/content.php | 32 ++++++++++++++++++++----- 5 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 actions/admin/site/unlock_upgrade.php diff --git a/actions/admin/site/unlock_upgrade.php b/actions/admin/site/unlock_upgrade.php new file mode 100644 index 000000000..b73cf7033 --- /dev/null +++ b/actions/admin/site/unlock_upgrade.php @@ -0,0 +1,23 @@ +dbprefix}locked'")); + +// Invalidate query cache +if ($DB_QUERY_CACHE) { + $DB_QUERY_CACHE->clear(); + elgg_log("Query cache invalidated", 'NOTICE'); +} + +if ($is_locked) { + // @todo Move to ElggUpgradeManager::unlock() when #4682 fixed. + delete_data("drop table {$CONFIG->dbprefix}locked"); + error_log('Upgrade unlocks itself'); +} +system_message(elgg_echo('upgrade:unlock:success')); +forward(REFERER); \ No newline at end of file diff --git a/engine/lib/admin.php b/engine/lib/admin.php index b65d98c95..4673805f0 100644 --- a/engine/lib/admin.php +++ b/engine/lib/admin.php @@ -233,6 +233,7 @@ function admin_init() { elgg_register_action('admin/site/update_basic', '', 'admin'); elgg_register_action('admin/site/update_advanced', '', 'admin'); elgg_register_action('admin/site/flush_cache', '', 'admin'); + elgg_register_action('admin/site/unlock_upgrade', '', 'admin'); elgg_register_action('admin/menu/save', '', 'admin'); diff --git a/languages/en.php b/languages/en.php index 18d0c88d9..159867e2f 100644 --- a/languages/en.php +++ b/languages/en.php @@ -1047,6 +1047,9 @@ Once you have logged in, we highly recommend that you change your password. 'upgrading' => 'Upgrading...', 'upgrade:db' => 'Your database was upgraded.', 'upgrade:core' => 'Your Elgg installation was upgraded.', + 'upgrade:unlock' => 'Unlock upgrade', + 'upgrade:unlock:confirm' => "Somebody is performing an upgrade. You should cancel and wait until upgrade is done. Are you sure you want to continue?", + 'upgrade:unlock:success' => "Upgrade unlocked suscessfully.", 'upgrade:unable_to_upgrade' => 'Unable to upgrade.', 'upgrade:unable_to_upgrade_info' => 'This installation cannot be upgraded because legacy views diff --git a/upgrade.php b/upgrade.php index 38be476a4..e1f3c6b9e 100644 --- a/upgrade.php +++ b/upgrade.php @@ -13,6 +13,7 @@ * @subpackage Upgrade */ +// @todo Move to ElggUpgradeManager::lock() when #4628 fixed. function upgrade_lock() { global $CONFIG, $DB_QUERY_CACHE; @@ -35,6 +36,7 @@ function upgrade_lock() { return false; } +// @todo Move to ElggUpgradeManager::unlock() when #4682 fixed. function upgrade_unlock() { global $CONFIG; delete_data("drop table {$CONFIG->dbprefix}locked"); diff --git a/views/default/widgets/control_panel/content.php b/views/default/widgets/control_panel/content.php index d2db54bc6..e6763d851 100644 --- a/views/default/widgets/control_panel/content.php +++ b/views/default/widgets/control_panel/content.php @@ -11,12 +11,32 @@ elgg_register_menu_item('admin_control_panel', array( 'link_class' => 'elgg-button elgg-button-action', )); -elgg_register_menu_item('admin_control_panel', array( - 'name' => 'upgrade', - 'text' => elgg_echo('upgrade'), - 'href' => 'upgrade.php', - 'link_class' => 'elgg-button elgg-button-action', -)); +// @todo Move in this in ElggUpgradeManager::isLocked() when #4682 fixed +global $CONFIG, $DB_QUERY_CACHE; +$is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}locked'")); +// Invalidate query cache +if ($DB_QUERY_CACHE) { + $DB_QUERY_CACHE->clear(); + elgg_log("Query cache invalidated", 'NOTICE'); +} + +if (!$is_locked) { + elgg_register_menu_item('admin_control_panel', array( + 'name' => 'upgrade', + 'text' => elgg_echo('upgrade'), + 'href' => 'upgrade.php', + 'link_class' => 'elgg-button elgg-button-action', + )); +} else { + elgg_register_menu_item('admin_control_panel', array( + 'name' => 'unlock_upgrade', + 'text' => elgg_echo('upgrade:unlock'), + 'href' => 'action/admin/site/unlock_upgrade', + 'is_action' => true, + 'link_class' => 'elgg-button elgg-button-delete', + 'confirm' => elgg_echo('upgrade:unlock:confirm'), + )); +} echo elgg_view_menu('admin_control_panel', array( 'class' => 'elgg-menu-hz', -- cgit v1.2.3 From ba0761b5a0fb7d5dd3c20179de0f49b1aa8e0a89 Mon Sep 17 00:00:00 2001 From: Sem Date: Wed, 5 Sep 2012 01:16:45 +0200 Subject: Moved upgrade lock/unlock functions to upgrade.php lib. --- actions/admin/site/unlock_upgrade.php | 19 +++---------- engine/lib/upgrade.php | 51 +++++++++++++++++++++++++++++++++++ upgrade.php | 35 ++---------------------- 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/actions/admin/site/unlock_upgrade.php b/actions/admin/site/unlock_upgrade.php index b73cf7033..b625b1d26 100644 --- a/actions/admin/site/unlock_upgrade.php +++ b/actions/admin/site/unlock_upgrade.php @@ -3,21 +3,8 @@ * Unlocks the upgrade script */ -// @todo Move this in ElggUpgradeManager::isLocked() when #4682 fixed -global $CONFIG, $DB_QUERY_CACHE; - -$is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}locked'")); - -// Invalidate query cache -if ($DB_QUERY_CACHE) { - $DB_QUERY_CACHE->clear(); - elgg_log("Query cache invalidated", 'NOTICE'); -} - -if ($is_locked) { - // @todo Move to ElggUpgradeManager::unlock() when #4682 fixed. - delete_data("drop table {$CONFIG->dbprefix}locked"); - error_log('Upgrade unlocks itself'); +if (_elgg_upgrade_is_locked()) { + _elgg_upgrade_unlock(); } system_message(elgg_echo('upgrade:unlock:success')); -forward(REFERER); \ No newline at end of file +forward(REFERER); diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php index f0874a483..7f55c4cba 100644 --- a/engine/lib/upgrade.php +++ b/engine/lib/upgrade.php @@ -311,3 +311,54 @@ function elgg_upgrade_bootstrap_17_to_18() { return elgg_set_processed_upgrades($processed_upgrades); } + +/** + * Locks a mutual execution of upgrade + * + * @return bool + * @access private + */ +function _elgg_upgrade_lock() { + global $CONFIG; + + if (!_elgg_upgrade_is_locked()) { + // lock it + insert_data("create table {$CONFIG->dbprefix}locked (id INT)"); + error_log('Upgrade continue running'); + return true; + } + + error_log('Upgrade is locked'); + return false; +} + +/** + * Unlocks upgrade for new upgrade executions + * + * @access private + */ +function _elgg_upgrade_unlock() { + global $CONFIG; + delete_data("drop table {$CONFIG->dbprefix}locked"); + error_log('Upgrade unlocks itself'); +} + +/** + * Checks if upgrade is locked + * + * @return bool + * @access private + */ +function _elgg_upgrade_is_locked() { + global $CONFIG, $DB_QUERY_CACHE; + + $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}locked'")); + + // Invalidate query cache + if ($DB_QUERY_CACHE) { + $DB_QUERY_CACHE->clear(); + elgg_log("Query cache invalidated", 'NOTICE'); + } + + return $is_locked; +} diff --git a/upgrade.php b/upgrade.php index e1f3c6b9e..a58fcdc96 100644 --- a/upgrade.php +++ b/upgrade.php @@ -13,37 +13,6 @@ * @subpackage Upgrade */ -// @todo Move to ElggUpgradeManager::lock() when #4628 fixed. -function upgrade_lock() { - global $CONFIG, $DB_QUERY_CACHE; - - $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}locked'")); - - // Invalidate query cache - if ($DB_QUERY_CACHE) { - $DB_QUERY_CACHE->clear(); - elgg_log("Query cache invalidated", 'NOTICE'); - } - - if (!$is_locked) { - // lock it - insert_data("create table {$CONFIG->dbprefix}locked (id INT)"); - error_log('Upgrade continue running'); - return true; - } - - error_log('Upgrade is locked'); - return false; -} - -// @todo Move to ElggUpgradeManager::unlock() when #4682 fixed. -function upgrade_unlock() { - global $CONFIG; - delete_data("drop table {$CONFIG->dbprefix}locked"); - error_log('Upgrade unlocks itself'); -} - - // we want to know if an error occurs ini_set('display_errors', 1); @@ -53,7 +22,7 @@ require_once(dirname(__FILE__) . "/engine/start.php"); if (get_input('upgrade') == 'upgrade') { // prevent someone from running the upgrade script in parallel (see #4643) - if (!upgrade_lock()) { + if (!_elgg_upgrade_lock()) { forward(); } @@ -72,7 +41,7 @@ if (get_input('upgrade') == 'upgrade') { elgg_reset_system_cache(); // critical region has past - upgrade_unlock(); + _elgg_upgrade_unlock(); } else { // if upgrading from < 1.8.0, check for the core view 'welcome' and bail if it's found. -- cgit v1.2.3 From 22e8d9be4582b78a500382e14046a653a14e3f43 Mon Sep 17 00:00:00 2001 From: Brett Profitt Date: Sun, 16 Dec 2012 17:26:03 -0500 Subject: Refs #4643. Cleanup for the upgrade lock. --- engine/lib/upgrade.php | 20 ++++++++++++-------- languages/en.php | 3 ++- upgrade.php | 5 +++-- views/default/widgets/control_panel/content.php | 10 ++-------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php index 7f55c4cba..f4f4b16f5 100644 --- a/engine/lib/upgrade.php +++ b/engine/lib/upgrade.php @@ -313,7 +313,9 @@ function elgg_upgrade_bootstrap_17_to_18() { } /** - * Locks a mutual execution of upgrade + * Creates a table {prefix}upgrade_lock that is used as a mutex for upgrades. + * + * @see _elgg_upgrade_lock() * * @return bool * @access private @@ -323,24 +325,26 @@ function _elgg_upgrade_lock() { if (!_elgg_upgrade_is_locked()) { // lock it - insert_data("create table {$CONFIG->dbprefix}locked (id INT)"); - error_log('Upgrade continue running'); + insert_data("create table {$CONFIG->dbprefix}upgrade_lock (id INT)"); + elgg_log('Locked for upgrade.', 'NOTICE'); return true; } - error_log('Upgrade is locked'); + elgg_log('Cannot lock for upgrade: already locked.', 'WARNING'); return false; } /** - * Unlocks upgrade for new upgrade executions + * Unlocks upgrade. + * + * @see _elgg_upgrade_lock() * * @access private */ function _elgg_upgrade_unlock() { global $CONFIG; - delete_data("drop table {$CONFIG->dbprefix}locked"); - error_log('Upgrade unlocks itself'); + delete_data("drop table {$CONFIG->dbprefix}upgrade_lock"); + elgg_log('Upgrade unlocked.', 'NOTICE'); } /** @@ -352,7 +356,7 @@ function _elgg_upgrade_unlock() { function _elgg_upgrade_is_locked() { global $CONFIG, $DB_QUERY_CACHE; - $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}locked'")); + $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}upgrade_lock'")); // Invalidate query cache if ($DB_QUERY_CACHE) { diff --git a/languages/en.php b/languages/en.php index 159867e2f..f1a1d650b 100644 --- a/languages/en.php +++ b/languages/en.php @@ -1048,7 +1048,8 @@ Once you have logged in, we highly recommend that you change your password. 'upgrade:db' => 'Your database was upgraded.', 'upgrade:core' => 'Your Elgg installation was upgraded.', 'upgrade:unlock' => 'Unlock upgrade', - 'upgrade:unlock:confirm' => "Somebody is performing an upgrade. You should cancel and wait until upgrade is done. Are you sure you want to continue?", + 'upgrade:unlock:confirm' => "The database is locked for another upgrade. Running concurrent upgrades is dangerous. You should only continue if you know there is not another upgrade running. Unlock?", + 'upgrade:locked' => "Cannot upgrade. Another upgrade is running. To clear the upgrade lock, visit the Admin section.", 'upgrade:unlock:success' => "Upgrade unlocked suscessfully.", 'upgrade:unable_to_upgrade' => 'Unable to upgrade.', 'upgrade:unable_to_upgrade_info' => diff --git a/upgrade.php b/upgrade.php index a58fcdc96..c5f158c61 100644 --- a/upgrade.php +++ b/upgrade.php @@ -9,6 +9,8 @@ * new version of the script. Deleting the script is not a requirement and * leaving it behind does not affect the security of the site. * + * Upgrades use a table {db_prefix}upgrade_lock as a mutex to prevent concurrent upgrades. + * * @package Elgg.Core * @subpackage Upgrade */ @@ -20,9 +22,9 @@ define('UPGRADING', 'upgrading'); require_once(dirname(__FILE__) . "/engine/start.php"); if (get_input('upgrade') == 'upgrade') { - // prevent someone from running the upgrade script in parallel (see #4643) if (!_elgg_upgrade_lock()) { + register_error(elgg_echo('upgrade:locked')); forward(); } @@ -40,7 +42,6 @@ if (get_input('upgrade') == 'upgrade') { elgg_invalidate_simplecache(); elgg_reset_system_cache(); - // critical region has past _elgg_upgrade_unlock(); } else { diff --git a/views/default/widgets/control_panel/content.php b/views/default/widgets/control_panel/content.php index e6763d851..a348d612f 100644 --- a/views/default/widgets/control_panel/content.php +++ b/views/default/widgets/control_panel/content.php @@ -12,13 +12,7 @@ elgg_register_menu_item('admin_control_panel', array( )); // @todo Move in this in ElggUpgradeManager::isLocked() when #4682 fixed -global $CONFIG, $DB_QUERY_CACHE; -$is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}locked'")); -// Invalidate query cache -if ($DB_QUERY_CACHE) { - $DB_QUERY_CACHE->clear(); - elgg_log("Query cache invalidated", 'NOTICE'); -} +$is_locked = _elgg_upgrade_is_locked(); if (!$is_locked) { elgg_register_menu_item('admin_control_panel', array( @@ -33,7 +27,7 @@ if (!$is_locked) { 'text' => elgg_echo('upgrade:unlock'), 'href' => 'action/admin/site/unlock_upgrade', 'is_action' => true, - 'link_class' => 'elgg-button elgg-button-delete', + 'link_class' => 'elgg-button elgg-button-action', 'confirm' => elgg_echo('upgrade:unlock:confirm'), )); } -- cgit v1.2.3