From: Chuck Scott Date: Fri, 21 Dec 2018 21:12:14 +0000 (-0500) Subject: Added locking for add-on database updates and new option to glmMembersConfigArraySetu... X-Git-Tag: v2.11.0^2~27 X-Git-Url: http://cvs2.gaslightmedia.com/gitweb/?a=commitdiff_plain;h=2b3dbbc67d45ce2a2a751b1aa185a83d4d849b11;p=WP-Plugins%2Fglm-member-db.git Added locking for add-on database updates and new option to glmMembersConfigArraySetup() in glmPluginSupport. --- diff --git a/classes/glmPluginSupport.php b/classes/glmPluginSupport.php index 3db61967..8c40d803 100755 --- a/classes/glmPluginSupport.php +++ b/classes/glmPluginSupport.php @@ -332,7 +332,7 @@ return; // Off for now ** Need to make this switchable in management * ) * ) */ -function glmMembersConfigArraySetup( $configTable, $configNumbTable = false, $configSelectedArray = false) +function glmMembersConfigArraySetup( $configTable, $configNumbTable = false, $configSelectedArray = false, $useNameForKey = false) { // Check if config table array exits @@ -369,6 +369,16 @@ function glmMembersConfigArraySetup( $configTable, $configNumbTable = false, $co } } + if ($useNameForKey) { + + $nameArray = array(); + foreach($conf as $c) { + $nameArray[$c['name']] = $c; + } + return $nameArray; + + } + return $conf; } diff --git a/controllers/admin.php b/controllers/admin.php index 46100ca0..8411a500 100755 --- a/controllers/admin.php +++ b/controllers/admin.php @@ -133,12 +133,6 @@ class glmMembersAdmin extends GlmPluginSupport // Save plugin configuration object $this->config = $config; - // Check the database - allow installation of tables for a new add-on -/* if (!$this->checkDatabase('install')) { - die('Database check failure'); - } -*/ - /* * Check if there's a request to bypass the WordPress Dashboard and * display directly to the browser using a specified diff --git a/defines.php b/defines.php index 3b6ed84c..4f70ca25 100644 --- a/defines.php +++ b/defines.php @@ -91,6 +91,9 @@ define('GLM_MEMBERS_WORDPRESS_FILE_LIBRARY_URL', GLM_MEMBERS_PLUGIN_MEDIA_URL.'/ global $wpdb; define('GLM_MEMBERS_PLUGIN_DB_PREFIX', $wpdb->prefix.'glm_members_'); define('GLM_MEMBERS_PLUGIN_ACTIVE_DB_OPTION', 'glmMembersDatabaseDbVersion'); +// These two are used to ensure only one instance is doing a database update. +define('GLM_MEMBERS_PLUGIN_DB_LOCK', 'glmMembersDbLock'); +define('GLM_MEMBERS_PLUGIN_DB_LOCK_TIMEOUT', 30); // Current Theme Information $glmCurrentTheme = wp_get_theme(); diff --git a/index.php b/index.php index 64253a9c..8ecd0c33 100755 --- a/index.php +++ b/index.php @@ -483,7 +483,7 @@ if ($startupNotices != '') { * @return boolean False if some failure * @access private */ -function glmCheckDatabase () +function glmCheckDatabase() { global $startupNotices, $config, $wpdb; @@ -617,80 +617,140 @@ function glmCheckDatabase () // Otherwise, check if we need to update the database } elseif ($dbVersion != $a['database']['dbCurrentVersion']) { - // Include an admin message that we're updating the database - $startupNotices .= '

The '.$a['name'].' database tables require updating...

'; + /* + * This part of the code checks to see if another instance is doing the database update. + * If there is, then it won't be done by this instance and this instance will instead + * wait till the database update is done before continuing. + * + * If there's no other instance doing the update, this instance will try to set and + * verify that it is going to do it by setting and verifying a WordPress option. + */ - // Traverse version list to find any required updates - $curVerFound = false; - $db_setup_status = true; - foreach($a['database']['dbVersions'] as $version) { + $myId = rand(); - $ver = $version['version']; + // Try to get any current DB Lock + $lockName = GLM_MEMBERS_PLUGIN_DB_LOCK."_".$a['slug']; + $lock = get_option($lockName); - // Find the current version of the database - if ($ver == $dbVersion) { - // $startupNotices .= '

The database version installed for the '.GLM_MEMBERS_PLUGIN_NAME - // .' plugin is current and does not require updating.

'; - $db_setup_status = true; - $curVerFound = true; + // If another instance is doing a database update + // (If we got something back that's a 2 el array that doesn't have my ID and hasn't expired) + if ($lock && is_array($lock) && count($lock) == 2 && $lock[0] != $myId && $lock[1] > microtime(true)) { - // Otherwise if it's already been found and $ver is not the new target version - } elseif ($curVerFound && $dbVersion != $a['database']['dbCurrentVersion']) { + trigger_error("glmCheckDatabase() - Lock Name: $lockName - Instance: $myId - Another instance is updating the database for: ".$a['short_name']."",E_USER_NOTICE); - // Read in Database creation script - $sqlFile = $a['database']['dbScriptPath'].'/update_database_V'.$ver.'.sql'; - $sql = file_get_contents($sqlFile); + // Unfortunately things get mucked up for other instances, even if we hold them for a bit, so they go here instead. + $output = file_get_contents(GLM_MEMBERS_PLUGIN_PATH.'/views/front/error/databaseUpdateInProgress.html'); + wp_die($output); - // Replace {prefix} with table name prefix - $sql = str_replace('{prefix}', $a['database']['dbPrefix'], $sql); + } else { - // Split script into separate queries by looking for lines with only "---" - $queries = preg_split('/^----$/m', $sql); + trigger_error("glmCheckDatabase() - Lock Name: $lockName - Instance: $myId - This instance trying to secure database update lock for: ".$a['short_name'],E_USER_NOTICE); - // Try executing all queries to update database - do { - $q = current($queries); - $wpdb->query($q); - $queryError = $wpdb->last_error; - } while ($queryError == '' && next($queries)); + // Add our ID and timeout then wait a second + add_option($lockName, array($myId, (microtime(true)+GLM_MEMBERS_PLUGIN_DB_LOCK_TIMEOUT))); + sleep(1); - // Check for PHP script to update database - $phpScript = $a['database']['dbScriptPath'].'/update_database_V'.$ver.'.php'; - if (is_file($phpScript)) { - require_once $phpScript; - } + // Make sure this instance has the lock + $lock = get_option($lockName); + if ($lock && is_array($lock) && count($lock) == 2 && $lock[0] == $myId && $lock[1] > microtime(true)) { - // If there were no errors - if ($queryError == '') { - $startupNotices .= '

The database for the '.$a['name'].' plugin has been updated ' - .'from V'.$dbVersion.' to V'.$ver.'.

'; - } else { - $startupNotices .= '

Failure updating the database tables for the '.$a['name'].' plugin ' - .'from V'.$dbVersion.' to V'.$ver.'.

'; - $db_setup_status = false; - $startupNotices .= '

Database Update Error: '.$queryError.'

'; - } + /* + * At this point this instance should have a verified lock on doing the database + * update and all other instances should be waiting for this to complete. + */ - $dbVersion = $ver; - $db_setup_status = true; + trigger_error("glmCheckDatabase() - Lock Name: $lockName - Instance: $myId - This instance has a verified database update lock for: ".$a['short_name'],E_USER_NOTICE); - } + // Include an admin message that we're updating the database + $startupNotices .= '

The '.$a['name'].' database tables require updating...

'; - // Save the new version. If we've had a problem updating the database, then stop here. - if ($db_setup_status) { + // Traverse version list to find any required updates + $curVerFound = false; + $db_setup_status = true; + foreach($a['database']['dbVersions'] as $version) { + + $ver = $version['version']; + + // Find the current version of the database + if ($ver == $dbVersion) { + + $db_setup_status = true; + $curVerFound = true; + + // Otherwise if it's already been found and $ver is not the new target version + } elseif ($curVerFound && $dbVersion != $a['database']['dbCurrentVersion']) { + + // Read in Database creation script + $sqlFile = $a['database']['dbScriptPath'].'/update_database_V'.$ver.'.sql'; + $sql = file_get_contents($sqlFile); + + // Replace {prefix} with table name prefix + $sql = str_replace('{prefix}', $a['database']['dbPrefix'], $sql); + + // Split script into separate queries by looking for lines with only "---" + $queries = preg_split('/^----$/m', $sql); + + // Try executing all queries to update database + do { + $q = current($queries); + $wpdb->query($q); + $queryError = $wpdb->last_error; + } while ($queryError == '' && next($queries)); + + // Check for PHP script to update database + $phpScript = $a['database']['dbScriptPath'].'/update_database_V'.$ver.'.php'; + if (is_file($phpScript)) { + require_once $phpScript; + } + + // If there were no errors + if ($queryError == '') { + $startupNotices .= '

The database for the '.$a['name'].' plugin has been updated ' + .'from V'.$dbVersion.' to V'.$ver.'.

'; + } else { + $startupNotices .= '

Failure updating the database tables for the '.$a['name'].' plugin ' + .'from V'.$dbVersion.' to V'.$ver.'.

'; + $db_setup_status = false; + $startupNotices .= '

Database Update Error: '.$queryError.'

'; + } + + $dbVersion = $ver; + $db_setup_status = true; + + } + + // Save the new version. + if ($db_setup_status) { + update_option($a['database']['dbActiveVersionOption'], $dbVersion); + } else { + // There was a problem updating the database, so don't do any more. + break; + } - // Save the version of the installed database - update_option($a['database']['dbActiveVersionOption'], $dbVersion); + } - } else { - break; - } + if ($db_setup_status) { + trigger_error("glmCheckDatabase() - Lock Name: $lockName - Instance: $myId - This instance has updated the database for: ".$a['short_name'],E_USER_NOTICE); + $startupNotices .= '

Database tables updated.

'; + } else { + trigger_error("glmCheckDatabase() - Lock Name: $lockName - Instance: $myId - This instance had a problem updating the database for: ".$a['short_name'],E_USER_NOTICE); + } - } + /* + * This instance has completed the database update (or failed) and will remove + * the WordPress option that's locking out the other instances so they can + * continue. + * + * If there was a failure doing the update, this plugin will be deactivated + * at the bottom of this function. + */ + + // Remove our lock + delete_option($lockName); - if ($db_setup_status) { + trigger_error("glmCheckDatabase() - Lock Name: $lockName - Instance: $myId - This instance has removed database update lock for: ".$a['short_name'],E_USER_NOTICE); - $startupNotices .= '

Database tables updated.

'; + } } } else { @@ -713,7 +773,7 @@ function glmCheckDatabase () // Deactivate this add-on include_once ABSPATH . 'wp-admin/includes/plugin.php'; deactivate_plugins($a['slug'].'/index.php'); - $startupNotices .= '

Plugin '.$a['name'].' Deactivated.

'; + $startupNotices .= '

Plugin '.$a['name'].' Deactivated due to serious database update problem.

'; } } // For each plugin diff --git a/readme.txt b/readme.txt index aa3e09f3..c5587d84 100755 --- a/readme.txt +++ b/readme.txt @@ -66,6 +66,10 @@ There is of course much more to this. (none) == Changelog == += PENDING = +* Now locking out other processes from database update on an Add-On when one process is doing the update. +* Added parameter to glmMembersConfigArraySetup() in glmPluginSupport.php to use names for resulting array if needed. + = 2.10.46 = * Moved session startup from adminHooks.php to index.php to ensure there's always a session started. * Fixed member listings not using selected sort order setting past first page. diff --git a/views/front/error/databaseUpdateInProgress.html b/views/front/error/databaseUpdateInProgress.html new file mode 100644 index 00000000..63918af1 --- /dev/null +++ b/views/front/error/databaseUpdateInProgress.html @@ -0,0 +1,24 @@ + + + + +
+

Aw shucks!

+

We're sorry about this, but we had to do a quick database update.

+
+

+ Unfortunately you came in here just as we started doing that and if we let you continue + it might really muck up the works here. Fortunately these things are usually + really quick and rarely does anyone get caught like this. That makes you special, so + enjoy our database update page for a minute. +

+

+ If you'd like to get back to our Website, you can probably do that now by clicking + the link below. If that doesn't work it means we really messed things up and it + might be a good time for a snack. +

+

Try Again

+
+
+ + \ No newline at end of file