Differences Between: [Versions 310 and 403] [Versions 311 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Cache administration helper. 19 * 20 * This file is part of Moodle's cache API, affectionately called MUC. 21 * It contains the components that are requried in order to use caching. 22 * 23 * @package core 24 * @category cache 25 * @author Peter Burnett <peterburnett@catalyst-au.net> 26 * @copyright 2020 Catalyst IT 27 * @copyright 2012 Sam Hemelryk 28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 29 */ 30 31 namespace core_cache; 32 33 defined('MOODLE_INTERNAL') || die(); 34 use cache_helper, cache_store, cache_config, cache_factory, cache_definition; 35 36 /** 37 * Administration helper base class. 38 * 39 * Defines abstract methods for a subclass to define the admin page. 40 * 41 * @package core 42 * @category cache 43 * @author Peter Burnett <peterburnett@catalyst-au.net> 44 * @copyright 2020 Catalyst IT 45 * @copyright 2012 Sam Hemelryk 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 47 */ 48 abstract class administration_helper extends cache_helper { 49 50 /** 51 * Returns an array containing all of the information about stores a renderer needs. 52 * @return array 53 */ 54 public static function get_store_instance_summaries(): array { 55 $return = array(); 56 $default = array(); 57 $instance = \cache_config::instance(); 58 $stores = $instance->get_all_stores(); 59 $locks = $instance->get_locks(); 60 foreach ($stores as $name => $details) { 61 $class = $details['class']; 62 $store = false; 63 if ($class::are_requirements_met()) { 64 $store = new $class($details['name'], $details['configuration']); 65 } 66 $lock = (isset($details['lock'])) ? $locks[$details['lock']] : $instance->get_default_lock(); 67 $record = array( 68 'name' => $name, 69 'plugin' => $details['plugin'], 70 'default' => $details['default'], 71 'isready' => $store ? $store->is_ready() : false, 72 'requirementsmet' => $class::are_requirements_met(), 73 'mappings' => 0, 74 'lock' => $lock, 75 'modes' => array( 76 cache_store::MODE_APPLICATION => 77 ($class::get_supported_modes($return) & cache_store::MODE_APPLICATION) == cache_store::MODE_APPLICATION, 78 cache_store::MODE_SESSION => 79 ($class::get_supported_modes($return) & cache_store::MODE_SESSION) == cache_store::MODE_SESSION, 80 cache_store::MODE_REQUEST => 81 ($class::get_supported_modes($return) & cache_store::MODE_REQUEST) == cache_store::MODE_REQUEST, 82 ), 83 'supports' => array( 84 'multipleidentifiers' => $store ? $store->supports_multiple_identifiers() : false, 85 'dataguarantee' => $store ? $store->supports_data_guarantee() : false, 86 'nativettl' => $store ? $store->supports_native_ttl() : false, 87 'nativelocking' => ($store instanceof \cache_is_lockable), 88 'keyawareness' => ($store instanceof \cache_is_key_aware), 89 'searchable' => ($store instanceof \cache_is_searchable) 90 ), 91 'warnings' => $store ? $store->get_warnings() : array() 92 ); 93 if (empty($details['default'])) { 94 $return[$name] = $record; 95 } else { 96 $default[$name] = $record; 97 } 98 } 99 100 ksort($return); 101 ksort($default); 102 $return = $return + $default; 103 104 $mappings = $instance->get_definition_mappings(); 105 foreach ($mappings as $mapping) { 106 if (!array_key_exists($mapping['store'], $return)) { 107 continue; 108 } 109 $return[$mapping['store']]['mappings']++; 110 } 111 112 // Now get all definitions, and if not mapped, increment the defaults for the mode. 113 $modemappings = $instance->get_mode_mappings(); 114 foreach ($instance->get_definitions() as $definition) { 115 // Construct the definition name to search for. 116 $defname = $definition['component'] . '/' . $definition['area']; 117 // Skip if definition is already mapped. 118 if (array_search($defname, array_column($mappings, 'definition')) !== false) { 119 continue; 120 } 121 122 $mode = $definition['mode']; 123 // Get the store name of the default mapping from the mode. 124 $index = array_search($mode, array_column($modemappings, 'mode')); 125 $store = $modemappings[$index]['store']; 126 $return[$store]['mappings']++; 127 } 128 129 return $return; 130 } 131 132 /** 133 * Returns an array of information about plugins, everything a renderer needs. 134 * 135 * @return array for each store, an array containing various information about each store. 136 * See the code below for details 137 */ 138 public static function get_store_plugin_summaries(): array { 139 $return = array(); 140 $plugins = \core_component::get_plugin_list_with_file('cachestore', 'lib.php', true); 141 foreach ($plugins as $plugin => $path) { 142 $class = 'cachestore_'.$plugin; 143 $return[$plugin] = array( 144 'name' => get_string('pluginname', 'cachestore_'.$plugin), 145 'requirementsmet' => $class::are_requirements_met(), 146 'instances' => 0, 147 'modes' => array( 148 cache_store::MODE_APPLICATION => ($class::get_supported_modes() & cache_store::MODE_APPLICATION), 149 cache_store::MODE_SESSION => ($class::get_supported_modes() & cache_store::MODE_SESSION), 150 cache_store::MODE_REQUEST => ($class::get_supported_modes() & cache_store::MODE_REQUEST), 151 ), 152 'supports' => array( 153 'multipleidentifiers' => ($class::get_supported_features() & cache_store::SUPPORTS_MULTIPLE_IDENTIFIERS), 154 'dataguarantee' => ($class::get_supported_features() & cache_store::SUPPORTS_DATA_GUARANTEE), 155 'nativettl' => ($class::get_supported_features() & cache_store::SUPPORTS_NATIVE_TTL), 156 'nativelocking' => (in_array('cache_is_lockable', class_implements($class))), 157 'keyawareness' => (array_key_exists('cache_is_key_aware', class_implements($class))), 158 ), 159 'canaddinstance' => ($class::can_add_instance() && $class::are_requirements_met()) 160 ); 161 } 162 163 $instance = cache_config::instance(); 164 $stores = $instance->get_all_stores(); 165 foreach ($stores as $store) { 166 $plugin = $store['plugin']; 167 if (array_key_exists($plugin, $return)) { 168 $return[$plugin]['instances']++; 169 } 170 } 171 172 return $return; 173 } 174 175 /** 176 * Returns an array about the definitions. All the information a renderer needs. 177 * 178 * @return array for each store, an array containing various information about each store. 179 * See the code below for details 180 */ 181 public static function get_definition_summaries(): array { 182 $factory = cache_factory::instance(); 183 $config = $factory->create_config_instance(); 184 $storenames = array(); 185 foreach ($config->get_all_stores() as $key => $store) { 186 if (!empty($store['default'])) { 187 $storenames[$key] = new \lang_string('store_'.$key, 'cache'); 188 } else { 189 $storenames[$store['name']] = $store['name']; 190 } 191 } 192 /* @var cache_definition[] $definitions */ 193 $definitions = []; 194 $return = []; 195 foreach ($config->get_definitions() as $key => $definition) { 196 $definitions[$key] = cache_definition::load($definition['component'].'/'.$definition['area'], $definition); 197 } 198 foreach ($definitions as $id => $definition) { 199 $mappings = array(); 200 foreach (cache_helper::get_stores_suitable_for_definition($definition) as $store) { 201 $mappings[] = $storenames[$store->my_name()]; 202 } 203 $return[$id] = array( 204 'id' => $id, 205 'name' => $definition->get_name(), 206 'mode' => $definition->get_mode(), 207 'component' => $definition->get_component(), 208 'area' => $definition->get_area(), 209 'mappings' => $mappings, 210 'canuselocalstore' => $definition->can_use_localstore(), 211 'sharingoptions' => self::get_definition_sharing_options($definition->get_sharing_options(), false), 212 'selectedsharingoption' => self::get_definition_sharing_options($definition->get_selected_sharing_option(), true), 213 'userinputsharingkey' => $definition->get_user_input_sharing_key() 214 ); 215 } 216 return $return; 217 } 218 219 /** 220 * Get the default stores for all modes. 221 * 222 * @return array An array containing sub-arrays, one for each mode. 223 */ 224 public static function get_default_mode_stores(): array { 225 global $OUTPUT; 226 $instance = cache_config::instance(); 227 $adequatestores = cache_helper::get_stores_suitable_for_mode_default(); 228 $icon = new \pix_icon('i/warning', new \lang_string('inadequatestoreformapping', 'cache')); 229 $storenames = array(); 230 foreach ($instance->get_all_stores() as $key => $store) { 231 if (!empty($store['default'])) { 232 $storenames[$key] = new \lang_string('store_'.$key, 'cache'); 233 } 234 } 235 $modemappings = array( 236 cache_store::MODE_APPLICATION => array(), 237 cache_store::MODE_SESSION => array(), 238 cache_store::MODE_REQUEST => array(), 239 ); 240 foreach ($instance->get_mode_mappings() as $mapping) { 241 $mode = $mapping['mode']; 242 if (!array_key_exists($mode, $modemappings)) { 243 debugging('Unknown mode in cache store mode mappings', DEBUG_DEVELOPER); 244 continue; 245 } 246 if (array_key_exists($mapping['store'], $storenames)) { 247 $modemappings[$mode][$mapping['store']] = $storenames[$mapping['store']]; 248 } else { 249 $modemappings[$mode][$mapping['store']] = $mapping['store']; 250 } 251 if (!array_key_exists($mapping['store'], $adequatestores)) { 252 $modemappings[$mode][$mapping['store']] = $modemappings[$mode][$mapping['store']].' '.$OUTPUT->render($icon); 253 } 254 } 255 return $modemappings; 256 } 257 258 /** 259 * Returns an array summarising the locks available in the system. 260 * 261 * @return array array of lock summaries. 262 */ 263 public static function get_lock_summaries(): array { 264 $locks = array(); 265 $instance = cache_config::instance(); 266 $stores = $instance->get_all_stores(); 267 foreach ($instance->get_locks() as $lock) { 268 $default = !empty($lock['default']); 269 if ($default) { 270 $name = new \lang_string($lock['name'], 'cache'); 271 } else { 272 $name = $lock['name']; 273 } 274 $uses = 0; 275 foreach ($stores as $store) { 276 if (!empty($store['lock']) && $store['lock'] === $lock['name']) { 277 $uses++; 278 } 279 } 280 $lockdata = array( 281 'name' => $name, 282 'default' => $default, 283 'uses' => $uses, 284 'type' => get_string('pluginname', $lock['type']) 285 ); 286 $locks[$lock['name']] = $lockdata; 287 } 288 return $locks; 289 } 290 291 /** 292 * Given a sharing option hash this function returns an array of strings that can be used to describe it. 293 * 294 * @param int $sharingoption The sharing option hash to get strings for. 295 * @param bool $isselectedoptions Set to true if the strings will be used to view the selected options. 296 * @return array An array of lang_string's. 297 */ 298 public static function get_definition_sharing_options(int $sharingoption, bool $isselectedoptions = true): array { 299 $options = array(); 300 $prefix = ($isselectedoptions) ? 'sharingselected' : 'sharing'; 301 if ($sharingoption & cache_definition::SHARING_ALL) { 302 $options[cache_definition::SHARING_ALL] = new \lang_string($prefix.'_all', 'cache'); 303 } 304 if ($sharingoption & cache_definition::SHARING_SITEID) { 305 $options[cache_definition::SHARING_SITEID] = new \lang_string($prefix.'_siteid', 'cache'); 306 } 307 if ($sharingoption & cache_definition::SHARING_VERSION) { 308 $options[cache_definition::SHARING_VERSION] = new \lang_string($prefix.'_version', 'cache'); 309 } 310 if ($sharingoption & cache_definition::SHARING_INPUT) { 311 $options[cache_definition::SHARING_INPUT] = new \lang_string($prefix.'_input', 'cache'); 312 } 313 return $options; 314 } 315 316 /** 317 * Get an array of stores that are suitable to be used for a given definition. 318 * 319 * @param string $component 320 * @param string $area 321 * @return array Array containing 3 elements 322 * 1. An array of currently used stores 323 * 2. An array of suitable stores 324 * 3. An array of default stores 325 */ 326 public static function get_definition_store_options(string $component, string $area): array { 327 $factory = cache_factory::instance(); 328 $definition = $factory->create_definition($component, $area); 329 $config = cache_config::instance(); 330 $currentstores = $config->get_stores_for_definition($definition); 331 $possiblestores = $config->get_stores($definition->get_mode(), $definition->get_requirements_bin()); 332 333 $defaults = array(); 334 foreach ($currentstores as $key => $store) { 335 if (!empty($store['default'])) { 336 $defaults[] = $key; 337 unset($currentstores[$key]); 338 } 339 } 340 foreach ($possiblestores as $key => $store) { 341 if ($store['default']) { 342 unset($possiblestores[$key]); 343 $possiblestores[$key] = $store; 344 } 345 } 346 return array($currentstores, $possiblestores, $defaults); 347 } 348 349 /** 350 * This function must be implemented to display options for store plugins. 351 * 352 * @param string $name the name of the store plugin. 353 * @param array $plugindetails array of store plugin details. 354 * @return array array of actions. 355 */ 356 public function get_store_plugin_actions(string $name, array $plugindetails): array { 357 return array(); 358 } 359 360 /** 361 * This function must be implemented to display options for store instances. 362 * 363 * @param string $name the store instance name. 364 * @param array $storedetails array of store instance details. 365 * @return array array of actions. 366 */ 367 public function get_store_instance_actions(string $name, array $storedetails): array { 368 return array(); 369 } 370 371 /** 372 * This function must be implemented to display options for definition mappings. 373 * 374 * @param context $context the context for the definition. 375 * @param array $definitionsummary the definition summary. 376 * @return array array of actions. 377 */ 378 public function get_definition_actions(\context $context, array $definitionsummary): array { 379 return array(); 380 } 381 382 /** 383 * This function must be implemented to get addable locks. 384 * 385 * @return array array of locks that are addable. 386 */ 387 public function get_addable_lock_options(): array { 388 return array(); 389 } 390 391 /** 392 * This function must be implemented to perform any page actions by a child class. 393 * 394 * @param string $action the action to perform. 395 * @param array $forminfo empty array to be set by actions. 396 * @return array array of form info. 397 */ 398 public abstract function perform_cache_actions(string $action, array $forminfo): array; 399 400 /** 401 * This function must be implemented to display the cache admin page. 402 * 403 * @param \core_cache\output\renderer $renderer the renderer used to generate the page. 404 * @return string the HTML for the page. 405 */ 406 abstract public function generate_admin_page(\core_cache\output\renderer $renderer): string; 407 408 /** 409 * Gets usage information about the whole cache system. 410 * 411 * This is a slow function and should only be used on an admin information page. 412 * 413 * The returned array lists all cache definitions with fields 'cacheid' and 'stores'. For 414 * each store, the following fields are available: 415 * 416 * - name (store name) 417 * - class (e.g. cachestore_redis) 418 * - supported (true if we have any information) 419 * - items (number of items stored) 420 * - mean (mean size of item) 421 * - sd (standard deviation for item sizes) 422 * - margin (margin of error for mean at 95% confidence) 423 * - storetotal (total usage for store if known, otherwise null) 424 * 425 * The storetotal field will be the same for every cache that uses the same store. 426 * 427 * @param int $samplekeys Number of keys to sample when checking size of large caches 428 * @return array Details of cache usage 429 */ 430 abstract public function get_usage(int $samplekeys): array; 431 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body