From 167ad91e8658d394a204f3f16d1b075b58349677 Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Tue, 18 Sep 2012 13:34:56 +1200 Subject: [PATCH] MDL-25290 cache: Added UI to view the cache lock setups and tidied up a couple of things --- cache/admin.php | 14 ++++++ cache/classes/config.php | 11 ++--- cache/forms.php | 9 ++++ cache/locallib.php | 99 +++++++++++++++++++++++++++----------- cache/renderer.php | 45 +++++++++++++++++ cache/tests/cache_test.php | 6 --- lang/en/cache.php | 10 +++- lib/db/caches.php | 31 ++++++++++-- 8 files changed, 176 insertions(+), 49 deletions(-) diff --git a/cache/admin.php b/cache/admin.php index 96d086d718909..81e5400b3053c 100644 --- a/cache/admin.php +++ b/cache/admin.php @@ -39,6 +39,7 @@ $plugins = cache_administration_helper::get_plugin_summaries(); $definitions = cache_administration_helper::get_definition_summaries(); $defaultmodestores = cache_administration_helper::get_default_mode_stores(); +$locks = cache_administration_helper::get_lock_summaries(); $title = new lang_string('cacheadmin', 'cache'); $mform = null; @@ -60,6 +61,12 @@ } else if ($data = $mform->get_data()) { $config = cache_administration_helper::get_store_configuration_from_data($data); $writer = cache_config_writer::instance(); + unset($config['lock']); + foreach ($writer->get_locks() as $lock => $lockconfig) { + if ($lock == $data->lock) { + $config['lock'] = $data->lock; + } + } $writer->add_plugin_instance($data->name, $data->plugin, $config); redirect($PAGE->url, get_string('addstoresuccess', 'cache', $plugins[$plugin]['name']), 5); } @@ -74,6 +81,12 @@ } else if ($data = $mform->get_data()) { $config = cache_administration_helper::get_store_configuration_from_data($data); $writer = cache_config_writer::instance(); + unset($config['lock']); + foreach ($writer->get_locks() as $lock => $lockconfig) { + if ($lock == $data->lock) { + $config['lock'] = $data->lock; + } + } $writer->edit_plugin_instance($data->name, $data->plugin, $config); redirect($PAGE->url, get_string('editstoresuccess', 'cache', $plugins[$plugin]['name']), 5); } @@ -172,6 +185,7 @@ echo $renderer->plugin_summaries($plugins); echo $renderer->store_summariers($stores, $plugins); echo $renderer->definition_summaries($definitions, cache_administration_helper::get_definition_actions($context)); + echo $renderer->lock_summaries($locks); $applicationstore = join(', ', $defaultmodestores[cache_store::MODE_APPLICATION]); $sessionstore = join(', ', $defaultmodestores[cache_store::MODE_SESSION]); diff --git a/cache/classes/config.php b/cache/classes/config.php index d45b84e5bbbc3..5f2b189a96d83 100644 --- a/cache/classes/config.php +++ b/cache/classes/config.php @@ -141,7 +141,8 @@ public function load() { debugging('Duplicate cache lock detected. This should never happen.', DEBUG_DEVELOPER); continue; } - if ($defaultlock === null || !empty($this->configlocks['default'])) { + $conf['default'] = (!empty($conf['default'])); + if ($defaultlock === null || $conf['default']) { $defaultlock = $name; } $this->configlocks[$name] = $conf; @@ -175,13 +176,9 @@ public function load() { if (!array_key_exists('configuration', $store) || !is_array($store['configuration'])) { $store['configuration'] = array(); } - if (!empty($store['useforlocking'])) { - // The site has a specified cache for locking. - unset($this->configstores['default_locking']); - } $store['class'] = $class; $store['default'] = !empty($store['default']); - if (!array_key_exists('lock', $store) || !array_key_exists($this->configlocks, $store['lock'])) { + if (!array_key_exists('lock', $store) || !array_key_exists($store['lock'], $this->configlocks)) { $store['lock'] = $defaultlock; } @@ -434,7 +431,7 @@ public function get_definition_mappings() { /** * Returns an array of the configured locks. - * @return array + * @return array Array of name => config */ public function get_locks() { return $this->configlocks; diff --git a/cache/forms.php b/cache/forms.php index b6c014f472df8..da6db918ce794 100644 --- a/cache/forms.php +++ b/cache/forms.php @@ -46,6 +46,7 @@ protected final function definition() { $form = $this->_form; $store = $this->_customdata['store']; $plugin = $this->_customdata['plugin']; + $locks = $this->_customdata['locks']; $form->addElement('hidden', 'plugin', $plugin); $form->addElement('hidden', 'editing', !empty($this->_customdata['store'])); @@ -60,6 +61,14 @@ protected final function definition() { $form->addElement('static', 'name-value', get_string('storename', 'cache'), $store); } + if (is_array($locks)) { + $form->addElement('select', 'lock', get_string('lockmethod', 'cache'), $locks); + $form->addHelpButton('lock', 'lockmethod', 'cache'); + $form->setType('lock', PARAM_TEXT); + } else { + $form->addElement('hidden', 'lock', ''); + $form->addElement('static', 'lock-value', get_string('lockmethod', 'cache'), ''.get_string('nativelocking', 'cache').''); + } if (method_exists($this, 'configuration_definition')) { $form->addElement('header', 'storeconfiguration', get_string('storeconfiguration', 'cache')); diff --git a/cache/locallib.php b/cache/locallib.php index add82cd90e24a..aa212526aaddf 100644 --- a/cache/locallib.php +++ b/cache/locallib.php @@ -137,10 +137,12 @@ public function add_plugin_instance($name, $plugin, array $configuration = array 'configuration' => $configuration, 'features' => $class::get_supported_features($configuration), 'modes' => $class::get_supported_modes($configuration), - 'mappingsonly' => !empty($configuration['mappingsonly']), - 'useforlocking' => !empty($configuration['useforlocking']) - + 'mappingsonly' => !empty($configuration['mappingsonly']) ); + if (array_key_exists('lock', $configuration)) { + $this->configstores[$name]['lock'] = $configuration['lock']; + unset($this->configstores[$name]['configuration']['lock']); + } $this->config_save(); return true; } @@ -228,9 +230,12 @@ public function edit_plugin_instance($name, $plugin, $configuration) { 'configuration' => $configuration, 'features' => $class::get_supported_features($configuration), 'modes' => $class::get_supported_modes($configuration), - 'mappingsonly' => !empty($configuration['mappingsonly']), - 'useforlocking' => !empty($configuration['useforlocking']) + 'mappingsonly' => !empty($configuration['mappingsonly']) ); + if (array_key_exists('lock', $configuration)) { + $this->configstores[$name]['lock'] = $configuration['lock']; + unset($this->configstores[$name]['configuration']['lock']); + } $this->config_save(); return true; } @@ -285,17 +290,6 @@ public static function create_default_configuration() { $writer = new self; $writer->configstores = array( - 'default_locking' => array( - 'name' => 'default_locking', - 'plugin' => 'file', - 'configuration' => array(), - 'features' => cachestore_file::get_supported_features(), - 'modes' => cache_store::MODE_APPLICATION, - 'useforlocking' => true, - 'mappingsonly' => true, - 'default' => true, - //'class' => 'cachestore_file' - ), 'default_application' => array( 'name' => 'default_application', 'plugin' => 'file', @@ -342,18 +336,12 @@ public static function create_default_configuration() { 'sort' => -1 ) ); - $writer->configdefinitionmappings = array( - array( - 'store' => 'default_locking', - 'definition' => 'core/locking', - 'sort' => -1 - ) - ); $writer->configlocks = array( 'default_file_lock' => array( - 'name' => 'default_file_lock', + 'name' => 'cachelock_file_default', 'type' => 'cachelock_file', - 'dir' => 'filelocks' + 'dir' => 'filelocks', + 'default' => true ) ); $writer->config_save(); @@ -740,8 +728,33 @@ public static function get_add_store_form($plugin) { } } + $supportsnativelocking = false; + if (file_exists($plugindir.'/lib.php')) { + require_once($plugindir.'/lib.php'); + $pluginclass = 'cachestore_'.$plugin; + if (class_exists($pluginclass)) { + $supportsnativelocking = array_key_exists('cache_is_lockable', class_implements($pluginclass)); + } + } + + if (!$supportsnativelocking) { + $config = cache_config::instance(); + $locks = array(); + foreach ($config->get_locks() as $lock => $conf) { + debug($conf); + if (!empty($conf['default'])) { + $name = get_string($lock, 'cache'); + } else { + $name = $lock; + } + $locks[$lock] = $name; + } + } else { + $locks = false; + } + $url = new moodle_url('/cache/admin.php', array('action' => 'addstore')); - return new $class($url, array('plugin' => $plugin, 'store' => null)); + return new $class($url, array('plugin' => $plugin, 'store' => null, 'locks' => $locks)); } /** @@ -821,9 +834,7 @@ public static function get_definition_store_options($component, $area) { } } foreach ($possiblestores as $key => $store) { - if ($key === 'default_locking') { - unset($possiblestores[$key]); - } else if ($store['default']) { + if ($store['default']) { unset($possiblestores[$key]); $possiblestores[$key] = $store; } @@ -863,4 +874,34 @@ public static function get_default_mode_stores() { } return $modemappings; } + + /** + * Returns an array summarising the locks available in the system + */ + public static function get_lock_summaries() { + $locks = array(); + $instance = cache_config::instance(); + $stores = $instance->get_all_stores(); + foreach ($instance->get_locks() as $lock) { + $default = !empty($lock['default']); + if ($default) { + $name = new lang_string($lock['name'], 'cache'); + } else { + $name = $lock['name']; + } + $uses = 0; + foreach ($stores as $store) { + if (!empty($store['lock']) && $store['lock'] === $lock['name']) { + $uses++; + } + } + $lockdata = array( + 'name' => $name, + 'default' => $default, + 'uses' => $uses + ); + $locks[] = $lockdata; + } + return $locks; + } } \ No newline at end of file diff --git a/cache/renderer.php b/cache/renderer.php index 95f999b00400c..3022e8fb3306b 100644 --- a/cache/renderer.php +++ b/cache/renderer.php @@ -282,4 +282,49 @@ public function mode_mappings($applicationstore, $sessionstore, $requeststore, m $html .= html_writer::end_tag('div'); return $html; } + + /** + * Display basic information about lock instances. + * + * @todo Add some actions so that people can configure lock instances. + * + * @param array $locks + * @return string + */ + public function lock_summaries(array $locks) { + $table = new html_table(); + $table->colclasses = array( + 'name', + 'default', + 'uses', + // 'actions' + ); + $table->rowclasses = array( + 'lock_name', + 'lock_default', + 'lock_uses', + // 'lock_actions', + ); + $table->head = array( + get_string('lockname', 'cache'), + get_string('lockdefault', 'cache'), + get_string('lockuses', 'cache'), + // get_string('actions', 'cache') + ); + $table->data = array(); + $tick = $this->output->pix_icon('i/tick_green_big', ''); + foreach ($locks as $lock) { + $table->data[] = new html_table_row(array( + new html_table_cell($lock['name']), + new html_table_cell($lock['default'] ? $tick : ''), + new html_table_cell($lock['uses']), + )); + } + + $html = html_writer::start_tag('div', array('id' => 'core-cache-lock-summary')); + $html .= $this->output->heading(get_string('locksummary', 'cache'), 3); + $html .= html_writer::table($table); + $html .= html_writer::end_tag('div'); + return $html; + } } \ No newline at end of file diff --git a/cache/tests/cache_test.php b/cache/tests/cache_test.php index 9035230c51af5..9b38be8ce8050 100644 --- a/cache/tests/cache_test.php +++ b/cache/tests/cache_test.php @@ -102,21 +102,15 @@ public function test_cache_config() { } $definitions = $instance->get_definitions(); - // The default locking definition is required for the cache API and must be there. - $this->assertArrayHasKey('core/locking', $definitions); // The event invalidation definition is required for the cache API and must be there. $this->assertArrayHasKey('core/eventinvalidation', $definitions); $definitionmappings = $instance->get_definition_mappings(); - // There should be a mapping for default locking to default_locking $found = false; foreach ($definitionmappings as $mapping) { // Required attributes = definition + store $this->assertArrayHasKey('definition', $mapping); $this->assertArrayHasKey('store', $mapping); - if ($mapping['store'] == 'default_locking' && $mapping['definition'] == 'core/locking') { - $found = true; - } } $this->assertTrue($found, 'The expected mapping for default locking definition to the default locking store was not found.'); } diff --git a/lang/en/cache.php b/lang/en/cache.php index 7ffc7423b0f29..acd1b2ae72ca4 100644 --- a/lang/en/cache.php +++ b/lang/en/cache.php @@ -13,6 +13,7 @@ $string['cachedef_eventinvalidation'] = 'Event invalidation'; $string['cachedef_locking'] = 'Locking'; $string['cachedef_string'] = 'Language string cache'; +$string['cachelock_file_default'] = 'Default file locking'; $string['cachestores'] = 'Cache stores'; $string['component'] = 'Component'; $string['confirmstoredeletion'] = 'Confirm store deletion'; @@ -20,7 +21,6 @@ $string['defaultmappings_help'] = 'These are the default stores that will be used if you don\'t map one or more stores to the cache definition.'; $string['defaultstoreactions'] = 'Default stores cannot be modified'; $string['default_application'] = 'Default application store'; -$string['default_locking'] = 'Default store for locking'; $string['default_request'] = 'Default request store'; $string['default_session'] = 'Default session store'; $string['definition'] = 'Definition'; @@ -41,6 +41,12 @@ $string['getmiss'] = 'Get - Miss'; $string['invalidplugin'] = 'Invalid plugin'; $string['invalidstore'] = 'Invalid cache store provided'; +$string['lockdefault'] = 'Default'; +$string['lockmethod'] = 'Lock method'; +$string['lockmethod_help'] = 'This is the method used for locking when required of this store.'; +$string['lockname'] = 'Name'; +$string['locksummary'] = 'Summary of cache lock instances.'; +$string['lockuses'] = 'Uses'; $string['mappings'] = 'Store mappings'; $string['mappingdefault'] = '(default)'; $string['mappingprimary'] = 'Primary store'; @@ -50,6 +56,7 @@ $string['mode_1'] = 'Application'; $string['mode_2'] = 'Session'; $string['mode_4'] = 'Request'; +$string['nativelocking'] = 'This plugin handles its own locking.'; $string['none'] = 'None'; $string['plugin'] = 'Plugin'; $string['pluginsummaries'] = 'Plugin summaries'; @@ -70,7 +77,6 @@ $string['storeresults_session'] = 'Store requests when used as a session cache.'; $string['stores'] = 'Stores'; $string['store_default_application'] = 'Default file store for application caches'; -$string['store_default_locking'] = 'Default file store for locking'; $string['store_default_request'] = 'Default static store for request caches'; $string['store_default_session'] = 'Default session store for session caches'; $string['storesummaries'] = 'Store summaries'; diff --git a/lib/db/caches.php b/lib/db/caches.php index a3a32f23b8d71..7e2a0769a5b42 100644 --- a/lib/db/caches.php +++ b/lib/db/caches.php @@ -1,11 +1,32 @@ . + +/** + * Core cache definitions. + * + * This file is part of Moodle's cache API, affectionately called MUC. + * It contains the components that are requried in order to use caching. + * + * @package core + * @category cache + * @copyright 2012 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ $definitions = array( - // Default cache for locking - 'locking' => array( - 'mode' => cache_store::MODE_APPLICATION, - 'mappingsonly' => true, - ), 'string' => array( 'mode' => cache_store::MODE_APPLICATION, 'component' => 'core',