From e876adef8fd6f24d79d18b62d90d56c0353ee0d1 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 6 Oct 2018 00:53:13 +0200 Subject: [PATCH 01/13] Moved the functions update_db and run_update_function to a Friendica\Core\Update class --- boot.php | 4 +- src/Core/Console/DatabaseStructure.php | 5 +- src/Core/Update.php | 123 +++++++++++++++++++++++++ src/Worker/DBUpdate.php | 5 +- 4 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 src/Core/Update.php diff --git a/boot.php b/boot.php index 3efd065f3e..5973156ecd 100644 --- a/boot.php +++ b/boot.php @@ -28,9 +28,9 @@ use Friendica\Core\L10n; use Friendica\Core\PConfig; use Friendica\Core\Protocol; use Friendica\Core\System; +use Friendica\Core\Update; use Friendica\Core\Worker; use Friendica\Database\DBA; -use Friendica\Database\DBStructure; use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Util\DateTimeFormat; @@ -454,7 +454,7 @@ function check_db($via_worker) if ($build < DB_UPDATE_VERSION) { // When we cannot execute the database update via the worker, we will do it directly if (!Worker::add(PRIORITY_CRITICAL, 'DBUpdate') && $via_worker) { - update_db(); + Update::run(); } } } diff --git a/src/Core/Console/DatabaseStructure.php b/src/Core/Console/DatabaseStructure.php index 4b607c1e6a..7b4c4c6cf1 100644 --- a/src/Core/Console/DatabaseStructure.php +++ b/src/Core/Console/DatabaseStructure.php @@ -3,6 +3,7 @@ namespace Friendica\Core\Console; use Friendica\Core; +use Friendica\Core\Update; use Friendica\Database\DBA; use Friendica\Database\DBStructure; use RuntimeException; @@ -80,7 +81,7 @@ HELP; // run the pre_update_nnnn functions in update.php for ($x = $stored; $x < $current; $x ++) { - $r = run_update_function($x, 'pre_update'); + $r = Update::runUpdateFunction($x, 'pre_update'); if (!$r) { break; } @@ -90,7 +91,7 @@ HELP; // run the update_nnnn functions in update.php for ($x = $stored; $x < $current; $x ++) { - $r = run_update_function($x, 'update'); + $r = Update::runUpdateFunction($x, 'update'); if (!$r) { break; } diff --git a/src/Core/Update.php b/src/Core/Update.php new file mode 100644 index 0000000000..350c2572e2 --- /dev/null +++ b/src/Core/Update.php @@ -0,0 +1,123 @@ + DB_UPDATE_VERSION)) { + $build = DB_UPDATE_VERSION - 1; + Config::set('system', 'build', $build); + } + + if ($build != DB_UPDATE_VERSION) { + require_once 'update.php'; + + $stored = intval($build); + $current = intval(DB_UPDATE_VERSION); + if ($stored < $current) { + Config::load('database'); + + // Compare the current structure with the defined structure + $t = Config::get('database', 'dbupdate_' . DB_UPDATE_VERSION); + if (!is_null($t)) { + return; + } + + // run the pre_update_nnnn functions in update.php + for ($x = $stored + 1; $x <= $current; $x++) { + $r = self::runUpdateFunction($x, 'pre_update'); + if (!$r) { + break; + } + } + + Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, time()); + + // update the structure in one call + $retval = DBStructure::update(false, true); + if ($retval) { + DBStructure::updateFail( + DB_UPDATE_VERSION, + $retval + ); + return; + } else { + Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, 'success'); + } + + // run the update_nnnn functions in update.php + for ($x = $stored + 1; $x <= $current; $x++) { + $r = self::runUpdateFunction($x, 'update'); + if (!$r) { + break; + } + } + } + } + } + + /** + * Executes a specific update function + * + * @param int $x the DB version number of the function + * @param string $prefix the prefix of the function (update, pre_update) + * + * @return bool true, if the update function worked + */ + public static function runUpdateFunction($x, $prefix) + { + $funcname = $prefix . '_' . $x; + + if (function_exists($funcname)) { + // There could be a lot of processes running or about to run. + // We want exactly one process to run the update command. + // So store the fact that we're taking responsibility + // after first checking to see if somebody else already has. + // If the update fails or times-out completely you may need to + // delete the config entry to try again. + + $t = Config::get('database', $funcname); + if (!is_null($t)) { + return false; + } + Config::set('database', $funcname, time()); + + // call the specific update + $retval = $funcname(); + + if ($retval) { + //send the administrator an e-mail + DBStructure::updateFail( + $x, + L10n::t('Update %s failed. See error logs.', $x) + ); + return false; + } else { + Config::set('database', $funcname, 'success'); + + if ($prefix == 'update') { + Config::set('system', 'build', $x); + } + + return true; + } + } else { + Config::set('database', $funcname, 'success'); + + if ($prefix == 'update') { + Config::set('system', 'build', $x); + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/Worker/DBUpdate.php b/src/Worker/DBUpdate.php index ed8e409e98..fcf07c0b65 100644 --- a/src/Worker/DBUpdate.php +++ b/src/Worker/DBUpdate.php @@ -6,17 +6,16 @@ namespace Friendica\Worker; use Friendica\Core\Config; +use Friendica\Core\Update; class DBUpdate { public static function execute() { - $a = \Friendica\BaseObject::getApp(); - // We are deleting the latest dbupdate entry. // This is done to avoid endless loops because the update was interupted. Config::delete('database', 'dbupdate_'.DB_UPDATE_VERSION); - update_db($a); + Update::run(); } } From f2ca3e5be44192c486e8e3af2a993e065ad40a7d Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 6 Oct 2018 20:38:35 +0200 Subject: [PATCH 02/13] Using Locks for Updating and writing last success to config --- src/Core/Update.php | 104 ++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/src/Core/Update.php b/src/Core/Update.php index 350c2572e2..8b11d8dcff 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -27,39 +27,38 @@ class Update Config::load('database'); // Compare the current structure with the defined structure - $t = Config::get('database', 'dbupdate_' . DB_UPDATE_VERSION); - if (!is_null($t)) { - return; - } + if (Lock::acquire('dbupdate')) { - // run the pre_update_nnnn functions in update.php - for ($x = $stored + 1; $x <= $current; $x++) { - $r = self::runUpdateFunction($x, 'pre_update'); - if (!$r) { - break; + // run the pre_update_nnnn functions in update.php + for ($x = $stored + 1; $x <= $current; $x++) { + $r = self::runUpdateFunction($x, 'pre_update'); + if (!$r) { + break; + } } - } - Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, time()); - - // update the structure in one call - $retval = DBStructure::update(false, true); - if ($retval) { - DBStructure::updateFail( - DB_UPDATE_VERSION, - $retval - ); - return; - } else { - Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, 'success'); - } - - // run the update_nnnn functions in update.php - for ($x = $stored + 1; $x <= $current; $x++) { - $r = self::runUpdateFunction($x, 'update'); - if (!$r) { - break; + // update the structure in one call + $retval = DBStructure::update(false, true); + if ($retval) { + DBStructure::updateFail( + DB_UPDATE_VERSION, + $retval + ); + Lock::release('dbupdate'); + return; + } else { + Config::set('database', 'last_successful_update', time()); } + + // run the update_nnnn functions in update.php + for ($x = $stored + 1; $x <= $current; $x++) { + $r = self::runUpdateFunction($x, 'update'); + if (!$r) { + break; + } + } + + Lock::release('dbupdate'); } } } @@ -85,33 +84,36 @@ class Update // If the update fails or times-out completely you may need to // delete the config entry to try again. - $t = Config::get('database', $funcname); - if (!is_null($t)) { - return false; - } - Config::set('database', $funcname, time()); + if (Lock::acquire('dbupdate_function')) { - // call the specific update - $retval = $funcname(); + // call the specific update + $retval = $funcname(); - if ($retval) { - //send the administrator an e-mail - DBStructure::updateFail( - $x, - L10n::t('Update %s failed. See error logs.', $x) - ); - return false; - } else { - Config::set('database', $funcname, 'success'); + if ($retval) { + //send the administrator an e-mail + DBStructure::updateFail( + $x, + L10n::t('Update %s failed. See error logs.', $x) + ); + Lock::release('dbupdate_function'); + return false; + } else { + Config::set('database', 'last_successful_update_function', $funcname); + Config::set('database', 'last_successful_update_function_time', time()); - if ($prefix == 'update') { - Config::set('system', 'build', $x); + if ($prefix == 'update') { + Config::set('system', 'build', $x); + } + + Lock::release('dbupdate_function'); + return true; } - - return true; } } else { - Config::set('database', $funcname, 'success'); + logger('Skipping \'' . $funcname . '\' without executing', LOGGER_DEBUG); + + Config::set('database', 'last_successful_update_function', $funcname); + Config::set('database', 'last_successful_update_function_time', time()); if ($prefix == 'update') { Config::set('system', 'build', $x); @@ -120,4 +122,4 @@ class Update return true; } } -} \ No newline at end of file +} From 26aee232544f0d83b1863433fddecbc9060afc4d Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 6 Oct 2018 22:15:08 +0200 Subject: [PATCH 03/13] Replacing dbupdate_ in admin.php and removing it from Worker\DBUpdate --- mod/admin.php | 2 +- src/Worker/DBUpdate.php | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/mod/admin.php b/mod/admin.php index d4cbafe54b..9dd907e11c 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -1595,7 +1595,7 @@ function admin_page_dbsync(App $a) $retval = DBStructure::update(false, true); if ($retval === '') { $o .= L10n::t("Database structure update %s was successfully applied.", DB_UPDATE_VERSION) . "
"; - Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, 'success'); + Config::set('database', 'last_successful_update', time()); } else { $o .= L10n::t("Executing of database structure update %s failed with error: %s", DB_UPDATE_VERSION, $retval) . "
"; } diff --git a/src/Worker/DBUpdate.php b/src/Worker/DBUpdate.php index fcf07c0b65..ae25760c87 100644 --- a/src/Worker/DBUpdate.php +++ b/src/Worker/DBUpdate.php @@ -12,10 +12,6 @@ class DBUpdate { public static function execute() { - // We are deleting the latest dbupdate entry. - // This is done to avoid endless loops because the update was interupted. - Config::delete('database', 'dbupdate_'.DB_UPDATE_VERSION); - Update::run(); } } From 4ae985e5ed31ba664a3f78e136e531774a5b352c Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sun, 7 Oct 2018 10:42:14 +0200 Subject: [PATCH 04/13] Setting update version & time on success --- mod/admin.php | 3 ++- src/Core/Update.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/admin.php b/mod/admin.php index 9dd907e11c..08c2ecbbc4 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -1595,7 +1595,8 @@ function admin_page_dbsync(App $a) $retval = DBStructure::update(false, true); if ($retval === '') { $o .= L10n::t("Database structure update %s was successfully applied.", DB_UPDATE_VERSION) . "
"; - Config::set('database', 'last_successful_update', time()); + Config::set('database', 'last_successful_update', DB_UPDATE_VERSION); + Config::set('database', 'last_successful_update_time', time()); } else { $o .= L10n::t("Executing of database structure update %s failed with error: %s", DB_UPDATE_VERSION, $retval) . "
"; } diff --git a/src/Core/Update.php b/src/Core/Update.php index 8b11d8dcff..a524830e75 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -47,7 +47,8 @@ class Update Lock::release('dbupdate'); return; } else { - Config::set('database', 'last_successful_update', time()); + Config::set('database', 'last_successful_update', $current); + Config::set('database', 'last_successful_update_time', time()); } // run the update_nnnn functions in update.php From 87f3fe24f7008dd1460cec1abd3ea7f3ae16679f Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sun, 14 Oct 2018 13:19:37 +0200 Subject: [PATCH 05/13] Moving UPDATE defines/constants out of boot --- boot.php | 19 ------------------- mod/admin.php | 9 +++++---- src/Core/Update.php | 3 +++ src/Database/DBStructure.php | 8 ++++++-- update.php | 21 +++++++++++---------- 5 files changed, 25 insertions(+), 35 deletions(-) diff --git a/boot.php b/boot.php index 5973156ecd..efff5baffa 100644 --- a/boot.php +++ b/boot.php @@ -43,13 +43,6 @@ define('FRIENDICA_VERSION', '2018.12-dev'); define('DFRN_PROTOCOL_VERSION', '2.23'); define('NEW_UPDATE_ROUTINE_VERSION', 1170); -/** - * @brief Constants for the database update check - */ -const DB_UPDATE_NOT_CHECKED = 0; // Database check wasn't executed before -const DB_UPDATE_SUCCESSFUL = 1; // Database check was successful -const DB_UPDATE_FAILED = 2; // Database check failed - /** * @brief Constant with a HTML line break. * @@ -119,18 +112,6 @@ define('REGISTER_OPEN', 2); * @} */ -/** - * @name Update - * - * DB update return values - * @{ - */ -define('UPDATE_SUCCESS', 0); -define('UPDATE_FAILED', 1); -/** - * @} - */ - /** * @name CP * diff --git a/mod/admin.php b/mod/admin.php index 08c2ecbbc4..d97bac194d 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -16,6 +16,7 @@ use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\System; use Friendica\Core\Theme; +use Friendica\Core\Update; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Database\DBStructure; @@ -864,10 +865,10 @@ function admin_page_summary(App $a) } } - if (Config::get('system', 'dbupdate', DB_UPDATE_NOT_CHECKED) == DB_UPDATE_NOT_CHECKED) { + if (Config::get('system', 'dbupdate', DBStructure::UPDATE_NOT_CHECKED) == DBStructure::UPDATE_NOT_CHECKED) { DBStructure::update(false, true); } - if (Config::get('system', 'dbupdate') == DB_UPDATE_FAILED) { + if (Config::get('system', 'dbupdate') == DBStructure::UPDATE_FAILED) { $showwarning = true; $warningtext[] = L10n::t('The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.'); } @@ -1613,9 +1614,9 @@ function admin_page_dbsync(App $a) if (function_exists($func)) { $retval = $func(); - if ($retval === UPDATE_FAILED) { + if ($retval === Update::FAILED) { $o .= L10n::t("Executing %s failed with error: %s", $func, $retval); - } elseif ($retval === UPDATE_SUCCESS) { + } elseif ($retval === Update::SUCCESS) { $o .= L10n::t('Update %s was successfully applied.', $func); Config::set('database', $func, 'success'); } else { diff --git a/src/Core/Update.php b/src/Core/Update.php index a524830e75..d4bcd04bba 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -6,6 +6,9 @@ use Friendica\Database\DBStructure; class Update { + const SUCCESS = 0; + const FAILED = 1; + /** * Automatic database updates */ diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 9a14114de1..b24c513336 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -23,6 +23,10 @@ require_once 'include/text.php'; */ class DBStructure { + const UPDATE_NOT_CHECKED = 0; // Database check wasn't executed before + const UPDATE_SUCCESSFUL = 1; // Database check was successful + const UPDATE_FAILED = 2; // Database check failed + /** * Database structure definition loaded from config/dbstructure.php * @@ -535,9 +539,9 @@ class DBStructure Config::set('system', 'maintenance_reason', ''); if ($errors) { - Config::set('system', 'dbupdate', DB_UPDATE_FAILED); + Config::set('system', 'dbupdate', self::UPDATE_FAILED); } else { - Config::set('system', 'dbupdate', DB_UPDATE_SUCCESSFUL); + Config::set('system', 'dbupdate', self::UPDATE_SUCCESSFUL); } } diff --git a/update.php b/update.php index 6a0ed1af20..439dd04bd5 100644 --- a/update.php +++ b/update.php @@ -4,6 +4,7 @@ use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\PConfig; +use Friendica\Core\Update; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Contact; @@ -65,7 +66,7 @@ function update_1179() { // Update the central item storage with uid=0 Worker::add(PRIORITY_LOW, "threadupdate"); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1181() { @@ -73,7 +74,7 @@ function update_1181() { // Fill the new fields in the term table. Worker::add(PRIORITY_LOW, "TagUpdate"); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1189() { @@ -84,7 +85,7 @@ function update_1189() { Config::delete('system','directory_submit_url'); } - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1191() { @@ -144,7 +145,7 @@ function update_1191() { Config::set('system', 'maintenance', 0); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1203() { @@ -165,19 +166,19 @@ function update_1244() { // Logged in users are forcibly logged out DBA::delete('session', ['1 = 1']); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1245() { $rino = Config::get('system', 'rino_encrypt'); if (!$rino) { - return UPDATE_SUCCESS; + return Update::SUCCESS; } Config::set('system', 'rino_encrypt', 1); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1247() { @@ -226,13 +227,13 @@ function update_1260() { SET `thread`.`author-id` = `item`.`author-id` WHERE `thread`.`author-id` = 0"); Config::set('system', 'maintenance', 0); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1261() { // This fixes the results of an issue in the develop branch of 2018-05. DBA::update('contact', ['blocked' => false, 'pending' => false], ['uid' => 0, 'blocked' => true, 'pending' => true]); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1278() { @@ -244,7 +245,7 @@ function update_1278() { Config::set('system', 'maintenance', 0); - return UPDATE_SUCCESS; + return Update::SUCCESS; } function update_1288() { From ffbad2dc81bb1a081729ebd139103035312cf608 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sun, 14 Oct 2018 13:26:53 +0200 Subject: [PATCH 06/13] moved check_db($via_worker) to Update::check($via_worker) --- bin/worker.php | 3 ++- boot.php | 27 --------------------------- src/Core/Update.php | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/bin/worker.php b/bin/worker.php index d5cd1f6b4b..9ae2f68b3e 100755 --- a/bin/worker.php +++ b/bin/worker.php @@ -7,6 +7,7 @@ use Friendica\App; use Friendica\Core\Config; use Friendica\Core\Worker; +use Friendica\Core\Update; // Get options $shortopts = 'sn'; @@ -30,7 +31,7 @@ require_once "boot.php"; $a = new App(dirname(__DIR__)); // Check the database structure and possibly fixes it -check_db(true); +Update::check(true); // Quit when in maintenance if (!$a->getMode()->has(App\Mode::MAINTENANCEDISABLED)) { diff --git a/boot.php b/boot.php index efff5baffa..0ca2fcdf8b 100644 --- a/boot.php +++ b/boot.php @@ -413,33 +413,6 @@ function defaults() { return $return; } -/** - * @brief Function to check if request was an AJAX (xmlhttprequest) request. - * - * @param boolean $via_worker boolean Is the check run via the worker? - */ -function check_db($via_worker) -{ - $build = Config::get('system', 'build'); - - if (empty($build)) { - Config::set('system', 'build', DB_UPDATE_VERSION - 1); - $build = DB_UPDATE_VERSION - 1; - } - - // We don't support upgrading from very old versions anymore - if ($build < NEW_UPDATE_ROUTINE_VERSION) { - die('You try to update from a version prior to database version 1170. The direct upgrade path is not supported. Please update to version 3.5.4 before updating to this version.'); - } - - if ($build < DB_UPDATE_VERSION) { - // When we cannot execute the database update via the worker, we will do it directly - if (!Worker::add(PRIORITY_CRITICAL, 'DBUpdate') && $via_worker) { - Update::run(); - } - } -} - /** * @brief Automatic database updates * @param object $a App diff --git a/src/Core/Update.php b/src/Core/Update.php index d4bcd04bba..e749c7233a 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -9,6 +9,33 @@ class Update const SUCCESS = 0; const FAILED = 1; + /** + * @brief Function to check if the Database structure needs an update. + * + * @param boolean $via_worker boolean Is the check run via the worker? + */ + public static function check($via_worker) + { + $build = Config::get('system', 'build'); + + if (empty($build)) { + Config::set('system', 'build', DB_UPDATE_VERSION - 1); + $build = DB_UPDATE_VERSION - 1; + } + + // We don't support upgrading from very old versions anymore + if ($build < NEW_UPDATE_ROUTINE_VERSION) { + die('You try to update from a version prior to database version 1170. The direct upgrade path is not supported. Please update to version 3.5.4 before updating to this version.'); + } + + if ($build < DB_UPDATE_VERSION) { + // When we cannot execute the database update via the worker, we will do it directly + if (!Worker::add(PRIORITY_CRITICAL, 'DBUpdate') && $via_worker) { + self::run(); + } + } + } + /** * Automatic database updates */ From f08f063a38543ce9790f4a89172f42885fb186c8 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 29 Oct 2018 09:07:36 +0100 Subject: [PATCH 07/13] Replaced check_db in App --- src/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.php b/src/App.php index 781faf1a50..598c0e66fc 100644 --- a/src/App.php +++ b/src/App.php @@ -1682,7 +1682,7 @@ class App $this->module = 'maintenance'; } else { $this->checkURL(); - check_db(false); + Core\Update::check(false); Core\Addon::loadAddons(); Core\Hook::loadHooks(); } From f2ec963b9500aba74ac2210f99bae3fda88a7411 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 29 Oct 2018 09:08:39 +0100 Subject: [PATCH 08/13] removed update db functions again --- boot.php | 110 ------------------------------------------------------- 1 file changed, 110 deletions(-) diff --git a/boot.php b/boot.php index 0ca2fcdf8b..a94b380387 100644 --- a/boot.php +++ b/boot.php @@ -413,116 +413,6 @@ function defaults() { return $return; } -/** - * @brief Automatic database updates - * @param object $a App - */ -function update_db() -{ - $build = Config::get('system', 'build'); - - if (empty($build) || ($build > DB_UPDATE_VERSION)) { - $build = DB_UPDATE_VERSION - 1; - Config::set('system', 'build', $build); - } - - if ($build != DB_UPDATE_VERSION) { - require_once 'update.php'; - - $stored = intval($build); - $current = intval(DB_UPDATE_VERSION); - if ($stored < $current) { - Config::load('database'); - - // Compare the current structure with the defined structure - $t = Config::get('database', 'dbupdate_' . DB_UPDATE_VERSION); - if (!is_null($t)) { - return; - } - - // run the pre_update_nnnn functions in update.php - for ($x = $stored + 1; $x <= $current; $x++) { - $r = run_update_function($x, 'pre_update'); - if (!$r) { - break; - } - } - - Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, time()); - - // update the structure in one call - $retval = DBStructure::update(false, true); - if ($retval) { - DBStructure::updateFail( - DB_UPDATE_VERSION, - $retval - ); - return; - } else { - Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, 'success'); - } - - // run the update_nnnn functions in update.php - for ($x = $stored + 1; $x <= $current; $x++) { - $r = run_update_function($x, 'update'); - if (!$r) { - break; - } - } - } - } - - return; -} - -function run_update_function($x, $prefix) -{ - $funcname = $prefix . '_' . $x; - - if (function_exists($funcname)) { - // There could be a lot of processes running or about to run. - // We want exactly one process to run the update command. - // So store the fact that we're taking responsibility - // after first checking to see if somebody else already has. - // If the update fails or times-out completely you may need to - // delete the config entry to try again. - - $t = Config::get('database', $funcname); - if (!is_null($t)) { - return false; - } - Config::set('database', $funcname, time()); - - // call the specific update - $retval = $funcname(); - - if ($retval) { - //send the administrator an e-mail - DBStructure::updateFail( - $x, - L10n::t('Update %s failed. See error logs.', $x) - ); - return false; - } else { - Config::set('database', $funcname, 'success'); - - if ($prefix == 'update') { - Config::set('system', 'build', $x); - } - - return true; - } - } else { - Config::set('database', $funcname, 'success'); - - if ($prefix == 'update') { - Config::set('system', 'build', $x); - } - - return true; - } -} - /** * @brief Used to end the current process, after saving session state. * @deprecated From 270e817954ea491cd7a85cca1d592e66666c1ae9 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 29 Oct 2018 10:16:07 +0100 Subject: [PATCH 09/13] Adding force to update routine - Introduced Cache::NEVER Lock (never expiring lock) - Force flag for dbstructure update - Moving the business logic to central place in Update class --- src/Core/Cache.php | 1 + src/Core/Cache/DatabaseCacheDriver.php | 20 ++-- src/Core/Cache/ICacheDriver.php | 2 +- src/Core/Cache/IMemoryCacheDriver.php | 2 +- src/Core/Console/DatabaseStructure.php | 35 +------ src/Core/Lock.php | 5 +- src/Core/Update.php | 126 +++++++++++++++++++++++-- src/Database/DBStructure.php | 52 ---------- update.php | 2 +- 9 files changed, 141 insertions(+), 104 deletions(-) diff --git a/src/Core/Cache.php b/src/Core/Cache.php index 0fb328aaee..0579ee0c8d 100644 --- a/src/Core/Cache.php +++ b/src/Core/Cache.php @@ -19,6 +19,7 @@ class Cache extends \Friendica\BaseObject const QUARTER_HOUR = 900; const FIVE_MINUTES = 300; const MINUTE = 60; + const NEVER = 0; /** * @var Cache\ICacheDriver diff --git a/src/Core/Cache/DatabaseCacheDriver.php b/src/Core/Cache/DatabaseCacheDriver.php index d90c6e4f18..f6f5b6486c 100644 --- a/src/Core/Cache/DatabaseCacheDriver.php +++ b/src/Core/Cache/DatabaseCacheDriver.php @@ -40,7 +40,7 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver */ public function get($key) { - $cache = DBA::selectFirst('cache', ['v'], ['`k` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); + $cache = DBA::selectFirst('cache', ['v'], ['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()]); if (DBA::isResult($cache)) { $cached = $cache['v']; @@ -62,11 +62,19 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver */ public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { - $fields = [ - 'v' => serialize($value), - 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'), - 'updated' => DateTimeFormat::utcNow() - ]; + if ($ttl > 0) { + $fields = [ + 'v' => serialize($value), + 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'), + 'updated' => DateTimeFormat::utcNow() + ]; + } else { + $fields = [ + 'v' => serialize($value), + 'expires' => -1, + 'updated' => DateTimeFormat::utcNow() + ]; + } return DBA::update('cache', $fields, ['k' => $key], true); } diff --git a/src/Core/Cache/ICacheDriver.php b/src/Core/Cache/ICacheDriver.php index 2c04c59925..1188e51877 100644 --- a/src/Core/Cache/ICacheDriver.php +++ b/src/Core/Cache/ICacheDriver.php @@ -34,7 +34,7 @@ interface ICacheDriver * * @param string $key The cache key * @param mixed $value The value to store - * @param integer $ttl The cache lifespan, must be one of the Cache constants + * @param integer $ttl The cache lifespan, must be one of the Cache constants * * @return bool */ diff --git a/src/Core/Cache/IMemoryCacheDriver.php b/src/Core/Cache/IMemoryCacheDriver.php index a50e2d1d48..0c5146f439 100644 --- a/src/Core/Cache/IMemoryCacheDriver.php +++ b/src/Core/Cache/IMemoryCacheDriver.php @@ -28,7 +28,7 @@ interface IMemoryCacheDriver extends ICacheDriver * @param string $key The cache key * @param mixed $oldValue The old value we know from the cache * @param mixed $newValue The new value we want to set - * @param int $ttl The cache lifespan, must be one of the Cache constants + * @param int $ttl The cache lifespan, must be one of the Cache constants * * @return bool */ diff --git a/src/Core/Console/DatabaseStructure.php b/src/Core/Console/DatabaseStructure.php index 7b4c4c6cf1..f3badc1969 100644 --- a/src/Core/Console/DatabaseStructure.php +++ b/src/Core/Console/DatabaseStructure.php @@ -25,7 +25,7 @@ class DatabaseStructure extends \Asika\SimpleConsole\Console $help = << [-h|--help|-?] [-v] + bin/console dbstructure [-h|--help|-?] |-f|--force] [-v] Commands dryrun Show database update schema queries without running them @@ -36,14 +36,13 @@ Commands Options -h|--help|-? Show help information -v Show more debug information. + -f|--force Force the command in case of "update" (Ignore failed updates/running updates) HELP; return $help; } protected function doExecute() { - $a = get_app(); - if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); $this->out('Arguments: ' . var_export($this->args, true)); @@ -70,34 +69,8 @@ HELP; $output = DBStructure::update(true, false); break; case "update": - $build = Core\Config::get('system', 'build'); - if (empty($build)) { - Core\Config::set('system', 'build', DB_UPDATE_VERSION); - $build = DB_UPDATE_VERSION; - } - - $stored = intval($build); - $current = intval(DB_UPDATE_VERSION); - - // run the pre_update_nnnn functions in update.php - for ($x = $stored; $x < $current; $x ++) { - $r = Update::runUpdateFunction($x, 'pre_update'); - if (!$r) { - break; - } - } - - $output = DBStructure::update(true, true); - - // run the update_nnnn functions in update.php - for ($x = $stored; $x < $current; $x ++) { - $r = Update::runUpdateFunction($x, 'update'); - if (!$r) { - break; - } - } - - Core\Config::set('system', 'build', DB_UPDATE_VERSION); + $force = $this->getOption(['f', 'force'], false); + $output = Update::run($force, true, false); break; case "dumpsql": ob_start(); diff --git a/src/Core/Lock.php b/src/Core/Lock.php index 4a737e3814..a5467c6442 100644 --- a/src/Core/Lock.php +++ b/src/Core/Lock.php @@ -111,12 +111,13 @@ class Lock * * @param string $key Name of the lock * @param integer $timeout Seconds until we give up + * @param integer $ttl The Lock lifespan, must be one of the Cache constants * * @return boolean Was the lock successful? */ - public static function acquire($key, $timeout = 120) + public static function acquire($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES) { - return self::getDriver()->acquireLock($key, $timeout); + return self::getDriver()->acquireLock($key, $timeout, $ttl); } /** diff --git a/src/Core/Update.php b/src/Core/Update.php index e749c7233a..4dc727b155 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -2,6 +2,7 @@ namespace Friendica\Core; +use Friendica\Database\DBA; use Friendica\Database\DBStructure; class Update @@ -38,9 +39,21 @@ class Update /** * Automatic database updates + * + * @param bool $force Force the Update-Check even if the lock is set + * @param bool $verbose Run the Update-Check verbose + * @param bool $sendMail Sends a Mail to the administrator in case of success/failure + * + * @return string Empty string if the update is successful, error messages otherwise */ - public static function run() + public static function run($force = false, $verbose = false, $sendMail = true) { + // In force mode, we release the dbupdate lock first + // Necessary in case of an stuck update + if ($force) { + Lock::release('dbupdate'); + } + $build = Config::get('system', 'build'); if (empty($build) || ($build > DB_UPDATE_VERSION)) { @@ -57,7 +70,8 @@ class Update Config::load('database'); // Compare the current structure with the defined structure - if (Lock::acquire('dbupdate')) { + // If the Lock is acquired, never release it automatically to avoid double updates + if (Lock::acquire('dbupdate', 120, Cache::NEVER)) { // run the pre_update_nnnn functions in update.php for ($x = $stored + 1; $x <= $current; $x++) { @@ -68,14 +82,17 @@ class Update } // update the structure in one call - $retval = DBStructure::update(false, true); + $retval = DBStructure::update($verbose, true); if ($retval) { - DBStructure::updateFail( - DB_UPDATE_VERSION, - $retval - ); + if ($sendMail) { + self::updateFailed( + DB_UPDATE_VERSION, + $retval + ); + } + Lock::release('dbcheck'); Lock::release('dbupdate'); - return; + return $retval; } else { Config::set('database', 'last_successful_update', $current); Config::set('database', 'last_successful_update_time', time()); @@ -89,10 +106,16 @@ class Update } } + if ($sendMail) { + self::updateSuccessfull($stored, $current); + } + Lock::release('dbupdate'); } } } + + return ''; } /** @@ -115,14 +138,14 @@ class Update // If the update fails or times-out completely you may need to // delete the config entry to try again. - if (Lock::acquire('dbupdate_function')) { + if (Lock::acquire('dbupdate_function', 120,Cache::NEVER)) { // call the specific update $retval = $funcname(); if ($retval) { //send the administrator an e-mail - DBStructure::updateFail( + self::updateFailed( $x, L10n::t('Update %s failed. See error logs.', $x) ); @@ -153,4 +176,87 @@ class Update return true; } } + + /** + * send the email and do what is needed to do on update fails + * + * @param int $update_id number of failed update + * @param string $error_message error message + */ + private static function updateFailed($update_id, $error_message) { + //send the administrators an e-mail + $admin_mail_list = "'".implode("','", array_map(['Friendica\Database\DBA', 'escape'], explode(",", str_replace(" ", "", Config::get('config', 'admin_email')))))."'"; + $adminlist = q("SELECT uid, language, email FROM user WHERE email IN (%s)", + $admin_mail_list + ); + + // No valid result? + if (!DBA::isResult($adminlist)) { + logger(sprintf('Cannot notify administrators about update_id=%d, error_message=%s', $update_id, $error_message), LOGGER_INFO); + + // Don't continue + return; + } + + // every admin could had different language + foreach ($adminlist as $admin) { + $lang = (($admin['language'])?$admin['language']:'en'); + L10n::pushLang($lang); + + $preamble = deindent(L10n::t(" + The friendica developers released update %s recently, + but when I tried to install it, something went terribly wrong. + This needs to be fixed soon and I can't do it alone. Please contact a + friendica developer if you can not help me on your own. My database might be invalid.", + $update_id)); + $body = L10n::t("The error message is\n[pre]%s[/pre]", $error_message); + + notification([ + 'uid' => $admin['uid'], + 'type' => SYSTEM_EMAIL, + 'to_email' => $admin['email'], + 'preamble' => $preamble, + 'body' => $body, + 'language' => $lang] + ); + L10n::popLang(); + } + + //try the logger + logger("CRITICAL: Database structure update failed: ".$error_message); + } + + private static function updateSuccessfull($from_build, $to_build) + { + //send the administrators an e-mail + $admin_mail_list = "'".implode("','", array_map(['Friendica\Database\DBA', 'escape'], explode(",", str_replace(" ", "", Config::get('config', 'admin_email')))))."'"; + $adminlist = q("SELECT uid, language, email FROM user WHERE email IN (%s)", + $admin_mail_list + ); + + if (DBA::isResult($adminlist)) { + // every admin could had different language + foreach ($adminlist as $admin) { + $lang = (($admin['language']) ? $admin['language'] : 'en'); + L10n::pushLang($lang); + + $preamble = deindent(L10n::t(" + The friendica database was successfully update from %s to %s.", + $from_build, $to_build)); + + notification([ + 'uid' => $admin['uid'], + 'type' => SYSTEM_EMAIL, + 'to_email' => $admin['email'], + 'preamble' => $preamble, + 'body' => $preamble, + 'language' => $lang] + ); + L10n::popLang(); + } + } + + //try the logger + logger("CRITICAL: Database structure update successful.", LOGGER_TRACE); + } } diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index b24c513336..4a9bc69f61 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -57,58 +57,6 @@ class DBStructure } } - /* - * send the email and do what is needed to do on update fails - * - * @param update_id (int) number of failed update - * @param error_message (str) error message - */ - public static function updateFail($update_id, $error_message) { - $a = get_app(); - - //send the administrators an e-mail - $admin_mail_list = "'".implode("','", array_map(['Friendica\Database\DBA', 'escape'], explode(",", str_replace(" ", "", Config::get('config', 'admin_email')))))."'"; - $adminlist = q("SELECT uid, language, email FROM user WHERE email IN (%s)", - $admin_mail_list - ); - - // No valid result? - if (!DBA::isResult($adminlist)) { - Logger::log(sprintf('Cannot notify administrators about update_id=%d, error_message=%s', $update_id, $error_message), Logger::INFO); - - // Don't continue - return; - } - - // every admin could had different language - foreach ($adminlist as $admin) { - $lang = (($admin['language'])?$admin['language']:'en'); - L10n::pushLang($lang); - - $preamble = deindent(L10n::t(" - The friendica developers released update %s recently, - but when I tried to install it, something went terribly wrong. - This needs to be fixed soon and I can't do it alone. Please contact a - friendica developer if you can not help me on your own. My database might be invalid.", - $update_id)); - $body = L10n::t("The error message is\n[pre]%s[/pre]", $error_message); - - notification([ - 'uid' => $admin['uid'], - 'type' => SYSTEM_EMAIL, - 'to_email' => $admin['email'], - 'preamble' => $preamble, - 'body' => $body, - 'language' => $lang] - ); - L10n::popLang(); - } - - //try the logger - Logger::log("CRITICAL: Database structure update failed: ".$error_message); - } - - private static function tableStructure($table) { $structures = q("DESCRIBE `%s`", $table); diff --git a/update.php b/update.php index 439dd04bd5..115f817d79 100644 --- a/update.php +++ b/update.php @@ -254,5 +254,5 @@ function update_1288() { DBA::e("UPDATE `item-activity` INNER JOIN `item` ON `item`.`iaid` = `item-activity`.`id` SET `item-activity`.`uri-id` = `item`.`uri-id` WHERE `item-activity`.`uri-id` IS NULL OR `item-activity`.`uri-id` = 0"); DBA::e("UPDATE `item-content` INNER JOIN `item` ON `item`.`icid` = `item-content`.`id` SET `item-content`.`uri-id` = `item`.`uri-id` WHERE `item-content`.`uri-id` IS NULL OR `item-content`.`uri-id` = 0"); - return UPDATE_SUCCESS; + return Update::SUCCESS; } From 9690dfc54e53973fe48924ad505791d41c858645 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 29 Oct 2018 10:21:10 +0100 Subject: [PATCH 10/13] Renamed Cache flag --- src/Core/Cache.php | 2 +- src/Core/Update.php | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Core/Cache.php b/src/Core/Cache.php index 0579ee0c8d..e7277fd702 100644 --- a/src/Core/Cache.php +++ b/src/Core/Cache.php @@ -19,7 +19,7 @@ class Cache extends \Friendica\BaseObject const QUARTER_HOUR = 900; const FIVE_MINUTES = 300; const MINUTE = 60; - const NEVER = 0; + const INFINITE = 0; /** * @var Cache\ICacheDriver diff --git a/src/Core/Update.php b/src/Core/Update.php index 4dc727b155..557d854c8c 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -71,7 +71,7 @@ class Update // Compare the current structure with the defined structure // If the Lock is acquired, never release it automatically to avoid double updates - if (Lock::acquire('dbupdate', 120, Cache::NEVER)) { + if (Lock::acquire('dbupdate', 120, Cache::INFINITE)) { // run the pre_update_nnnn functions in update.php for ($x = $stored + 1; $x <= $current; $x++) { @@ -90,7 +90,6 @@ class Update $retval ); } - Lock::release('dbcheck'); Lock::release('dbupdate'); return $retval; } else { @@ -138,7 +137,7 @@ class Update // If the update fails or times-out completely you may need to // delete the config entry to try again. - if (Lock::acquire('dbupdate_function', 120,Cache::NEVER)) { + if (Lock::acquire('dbupdate_function', 120,Cache::INFINITE)) { // call the specific update $retval = $funcname(); @@ -241,7 +240,7 @@ class Update L10n::pushLang($lang); $preamble = deindent(L10n::t(" - The friendica database was successfully update from %s to %s.", + The friendica database was successfully updated from %s to %s.", $from_build, $to_build)); notification([ From e5530dfa63931df73318a9211d52a2c719fdae13 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 29 Oct 2018 11:33:27 +0100 Subject: [PATCH 11/13] refactoring query --- src/Core/Update.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Core/Update.php b/src/Core/Update.php index 557d854c8c..2c070f67e9 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -185,9 +185,7 @@ class Update private static function updateFailed($update_id, $error_message) { //send the administrators an e-mail $admin_mail_list = "'".implode("','", array_map(['Friendica\Database\DBA', 'escape'], explode(",", str_replace(" ", "", Config::get('config', 'admin_email')))))."'"; - $adminlist = q("SELECT uid, language, email FROM user WHERE email IN (%s)", - $admin_mail_list - ); + $adminlist = DBA::select('user', ['uid', 'language', 'email'], ['`email` IN (%s)', $admin_mail_list]); // No valid result? if (!DBA::isResult($adminlist)) { @@ -229,9 +227,7 @@ class Update { //send the administrators an e-mail $admin_mail_list = "'".implode("','", array_map(['Friendica\Database\DBA', 'escape'], explode(",", str_replace(" ", "", Config::get('config', 'admin_email')))))."'"; - $adminlist = q("SELECT uid, language, email FROM user WHERE email IN (%s)", - $admin_mail_list - ); + $adminlist = DBA::select('user', ['uid', 'language', 'email'], ['`email` IN (%s)', $admin_mail_list]); if (DBA::isResult($adminlist)) { // every admin could had different language @@ -256,6 +252,6 @@ class Update } //try the logger - logger("CRITICAL: Database structure update successful.", LOGGER_TRACE); + logger("Database structure update successful.", LOGGER_TRACE); } } From 3f813d853b8e9ac2f57b403aaafd94809306578f Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 31 Oct 2018 14:48:19 +0100 Subject: [PATCH 12/13] introducing Logger::log --- src/Core/Update.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Core/Update.php b/src/Core/Update.php index 2c070f67e9..b9f3f3d1c9 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -163,7 +163,7 @@ class Update } } } else { - logger('Skipping \'' . $funcname . '\' without executing', LOGGER_DEBUG); + Logger::log('Skipping \'' . $funcname . '\' without executing', Logger::DEBUG); Config::set('database', 'last_successful_update_function', $funcname); Config::set('database', 'last_successful_update_function_time', time()); @@ -189,7 +189,7 @@ class Update // No valid result? if (!DBA::isResult($adminlist)) { - logger(sprintf('Cannot notify administrators about update_id=%d, error_message=%s', $update_id, $error_message), LOGGER_INFO); + Logger::log(sprintf('Cannot notify administrators about update_id=%d, error_message=%s', $update_id, $error_message), Logger::INFO); // Don't continue return; @@ -220,7 +220,7 @@ class Update } //try the logger - logger("CRITICAL: Database structure update failed: ".$error_message); + Logger::log("CRITICAL: Database structure update failed: " . $error_message); } private static function updateSuccessfull($from_build, $to_build) @@ -252,6 +252,6 @@ class Update } //try the logger - logger("Database structure update successful.", LOGGER_TRACE); + Logger::log("Database structure update successful.", Logger::TRACE); } } From bf878d2ebb6156b27efa9c81a6f0d10fd632922f Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 31 Oct 2018 15:22:44 +0100 Subject: [PATCH 13/13] Adding more Logger entries in case of update process --- src/Core/Update.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Core/Update.php b/src/Core/Update.php index b9f3f3d1c9..1396883357 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -69,6 +69,8 @@ class Update if ($stored < $current) { Config::load('database'); + Logger::log('Update from \'' . $stored . '\' to \'' . $current . '\' - starting', Logger::DEBUG); + // Compare the current structure with the defined structure // If the Lock is acquired, never release it automatically to avoid double updates if (Lock::acquire('dbupdate', 120, Cache::INFINITE)) { @@ -90,11 +92,13 @@ class Update $retval ); } + Logger::log('ERROR: Update from \'' . $stored . '\' to \'' . $current . '\' - failed: ' - $retval, Logger::ALL); Lock::release('dbupdate'); return $retval; } else { Config::set('database', 'last_successful_update', $current); Config::set('database', 'last_successful_update_time', time()); + Logger::log('Update from \'' . $stored . '\' to \'' . $current . '\' - finished', Logger::DEBUG); } // run the update_nnnn functions in update.php @@ -105,6 +109,7 @@ class Update } } + Logger::log('Update from \'' . $stored . '\' to \'' . $current . '\' - successful', Logger::DEBUG); if ($sendMail) { self::updateSuccessfull($stored, $current); } @@ -129,6 +134,8 @@ class Update { $funcname = $prefix . '_' . $x; + Logger::log('Update function \'' . $funcname . '\' - start', Logger::DEBUG); + if (function_exists($funcname)) { // There could be a lot of processes running or about to run. // We want exactly one process to run the update command. @@ -148,6 +155,7 @@ class Update $x, L10n::t('Update %s failed. See error logs.', $x) ); + Logger::log('ERROR: Update function \'' . $funcname . '\' - failed: ' . $retval, Logger::ALL); Lock::release('dbupdate_function'); return false; } else { @@ -159,6 +167,7 @@ class Update } Lock::release('dbupdate_function'); + Logger::log('Update function \'' . $funcname . '\' - finished', Logger::DEBUG); return true; } }