Commit bf4c9bf9 authored by Gábor Hojtsy's avatar Gábor Hojtsy

Issue #147000 by Berdir, Dave Reid, pwolanin, pillarsdotnet, TR, jbrauer,...

Issue #147000 by Berdir, Dave Reid, pwolanin, pillarsdotnet, TR, jbrauer, dstol: rework module_rebuild_cache() and system_theme_data() to support locking, so that concurrent requests will not corrupt the data; fixes an issue where themes got disabled occasionally
parent 8ab16cb6
<?php
/**
* @file
* A stub lock implementation to be used during the installation
* process when database access is not yet available. Because Drupal's
* install system should never be running in more than on concurrant
* request, we can bypass any need for locking.
*/
/**
* Initialize the locking system.
*/
function lock_init() {
}
/**
* Acquire (or renew) a lock, but do not block if it fails.
*
* @return
* TRUE if the lock was acquired, FALSE if it failed.
*/
function lock_acquire($name, $timeout = 30.0) {
return TRUE;
}
/**
* Check if lock acquired by a different process may be available.
*
* @return
* TRUE if there is no lock or it was removed, FALSE otherwise.
*/
function lock_may_be_available($name) {
return TRUE;
}
/**
* Wait for a lock to be available.
*
* @return
* TRUE if the lock holds, FALSE if it is available.
*/
function lock_wait($name, $delay = 30) {
return FALSE;
}
/**
* Release a lock previously acquired by lock_acquire().
*
* This will release the named lock if it is still held by the current request.
*
* @param $name
* The name of the lock.
*/
function lock_release($name) {
}
/**
* Release all previously acquired locks.
*/
function lock_release_all($lock_id = NULL) {
}
......@@ -93,6 +93,14 @@ function module_list($refresh = FALSE, $bootstrap = TRUE, $sort = FALSE, $fixed_
* The array of filesystem objects used to rebuild the cache.
*/
function module_rebuild_cache() {
$write_database = TRUE;
// If lock not acquired, return $files data without writing to database.
if (!lock_acquire('module_rebuild_cache')) {
$write_database = FALSE;
// Wait for the parallel thread to be done so we are more likely
// to get updated and consistent data.
lock_wait('module_rebuild_cache');
}
// Get current list of modules
$files = drupal_system_listing('\.module$', 'modules', 'name', 0);
......@@ -119,32 +127,39 @@ function module_rebuild_cache() {
unset($files[$filename]);
continue;
}
// Merge in defaults and save.
$files[$filename]->info = $file->info + $defaults;
// Invoke hook_system_info_alter() to give installed modules a chance to
// modify the data in the .info files if necessary.
drupal_alter('system_info', $files[$filename]->info, $files[$filename]);
// Log the critical hooks implemented by this module.
$bootstrap = 0;
foreach (bootstrap_hooks() as $hook) {
if (module_hook($file->name, $hook)) {
$bootstrap = 1;
break;
// Merge in defaults and save.
$files[$filename]->info = $file->info + $defaults;
}
// If lock not acquired, return $files data without writing to database.
if ($write_database) {
foreach ($files as $filename => $file) {
// Log the critical hooks implemented by this module.
$bootstrap = 0;
foreach (bootstrap_hooks() as $hook) {
if (module_hook($file->name, $hook)) {
$bootstrap = 1;
break;
}
}
}
// Update the contents of the system table:
if (isset($file->status) || (isset($file->old_filename) && $file->old_filename != $file->filename)) {
db_query("UPDATE {system} SET info = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s'", serialize($files[$filename]->info), $file->name, $file->filename, $bootstrap, $file->old_filename);
}
else {
// This is a new module.
$files[$filename]->status = 0;
$files[$filename]->throttle = 0;
db_query("INSERT INTO {system} (name, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0, 0, $bootstrap);
// Update the contents of the system table:
if (isset($file->status)) {
db_query("UPDATE {system} SET info = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s'", serialize($files[$filename]->info), $file->name, $file->filename, $bootstrap, $file->old_filename);
}
else {
// This is a new module.
$files[$filename]->status = 0;
$files[$filename]->throttle = 0;
db_query("INSERT INTO {system} (name, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0, 0, $bootstrap);
}
}
lock_release('module_rebuild_cache');
}
$files = _module_build_dependencies($files);
return $files;
......
......@@ -130,6 +130,12 @@ function install_main() {
if (!$verify) {
install_change_settings($profile, $install_locale);
}
// The default lock implementation uses a database table,
// so we cannot use it for install, but we still need
// the API functions available.
require_once './includes/lock-install.inc';
$conf['lock_inc'] = './includes/lock-install.inc';
lock_init();
// Install system.module.
drupal_install_system();
......
......@@ -805,22 +805,48 @@ function system_theme_default() {
* Array of all available themes and their data.
*/
function system_theme_data() {
$write_database = TRUE;
// If lock not acquired, return $files data without writing to database.
if (!lock_acquire('system_theme_data')) {
$write_database = FALSE;
// Wait for the parallel thread to be done so we are more likely
// to get updated and consistent data.
lock_wait('system_theme_data');
}
// Scan the installation theme .info files and their engines.
$themes = _system_theme_data();
foreach ($themes as $key => $theme) {
if (!isset($theme->owner)) {
$themes[$key]->owner = '';
}
}
// Extract current files from database.
system_get_files_database($themes, 'theme');
db_query("DELETE FROM {system} WHERE type = 'theme'");
// If lock not acquired, return $themes data without writing to database.
if ($write_database) {
$names = array();
foreach ($themes as $theme) {
if (!isset($theme->owner)) {
$theme->owner = '';
foreach ($themes as $theme) {
// Record the name of each theme found in the file system.
$names[] = $theme->name;
// Update the contents of the system table.
if (isset($theme->status) && !(defined('MAINTENANCE_MODE') && MAINTENANCE_MODE != 'install')) {
db_query("UPDATE {system} SET owner = '%s', info = '%s', filename = '%s' WHERE name = '%s' AND type = '%s'", $theme->owner, serialize($theme->info), $theme->filename, $theme->name, 'theme');
}
else {
$theme->status = ($theme->name == variable_get('theme_default', 'garland'));
// This is a new theme.
db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, $theme->status, 0, 0);
}
}
db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
// Delete from the system table any themes missing from the file system.
if ($names) {
db_query("DELETE FROM {system} WHERE type = 'theme' AND name NOT IN (". db_placeholders($names, 'varchar') .")", $names);
}
lock_release('system_theme_data');
}
return $themes;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment