Permalink
Browse files

Merge branch 'wip-MDL-38565-m24' of git://github.com/samhemelryk/mood…

…le into MOODLE_24_STABLE
  • Loading branch information...
2 parents 501dd08 + 6318a38 commit 0c60dae52210a74daa29a063f6ff181dab2a864c @danpoltawski danpoltawski committed Apr 19, 2013
View
@@ -18,6 +18,7 @@ A definition:
'requiremultipleidentifiers' => false, // Optional
'requirelockingread' => false, // Optional
'requirelockingwrite' => false, // Optional
+ 'requiresearchable' => false, // Optional
'maxsize' => null, // Optional
'overrideclass' => null, // Optional
'overrideclassfile' => null, // Optional
@@ -135,6 +136,7 @@ The following optional settings can also be defined:
* requiremultipleidentifiers - If set to true then only stores that support multiple identifiers will be used.
* requirelockingread - If set to true a lock will be acquired for reading. Don't use this setting unless you have a REALLY good reason to.
* requirelockingwrite - If set to true a lock will be acquired before writing to the cache. Avoid this unless necessary.
+* requiresearchable - If set to true only stores that support key searching will be used for this definition. Its not recommended to use this unless absolutely unavoidable.
* maxsize - This gives a cache an indication about the maximum items it should store. Cache stores don't have to use this, it is up to them to decide if its required.
* overrideclass - If provided this class will be used for the loader. It must extend one of the core loader classes (based upon mode).
* overrideclassfile - Included if required when using the overrideclass param.
@@ -225,4 +227,4 @@ Cache information can be invalidated in two ways.
The first method is designed to be used when you have a single known definition you want to invalidate entries within.
The second method is a lot more intensive for the system. There are defined invalidation events that definitions can "subscribe" to (through the definitions invalidationevents option).
When you invalidate by event the cache API finds all of the definitions that subscribe to the event, it then loads the stores for each of those definitions and purges the keys from each store.
-This is obviously a recursive, and therefore, intense process.
+This is obviously a recursive, and therefore, intense process.
@@ -184,6 +184,13 @@ class cache_definition {
protected $requirelockingwrite = false;
/**
+ * Gets set to true if this definition requires searchable stores.
+ * @since 2.4.4
+ * @var bool
+ */
+ protected $requiresearchable = false;
+
+ /**
* Sets the maximum number of items that can exist in the cache.
* Please note this isn't a hard limit, and doesn't need to be enforced by the caches. They can choose to do so optionally.
* @var int
@@ -307,6 +314,7 @@ public static function load($id, array $definition, $datasourceaggregate = null)
$requiremultipleidentifiers = false;
$requirelockingread = false;
$requirelockingwrite = false;
+ $requiresearchable = ($mode === cache_store::MODE_SESSION) ? true : false;
$maxsize = null;
$overrideclass = null;
$overrideclassfile = null;
@@ -342,6 +350,10 @@ public static function load($id, array $definition, $datasourceaggregate = null)
}
$requirelocking = $requirelockingwrite || $requirelockingread;
+ if (array_key_exists('requiresearchable', $definition)) {
+ $requiresearchable = (bool)$definition['requiresearchable'];
+ }
+
if (array_key_exists('maxsize', $definition)) {
$maxsize = (int)$definition['maxsize'];
}
@@ -433,6 +445,7 @@ public static function load($id, array $definition, $datasourceaggregate = null)
$cachedefinition->requirelocking = $requirelocking;
$cachedefinition->requirelockingread = $requirelockingread;
$cachedefinition->requirelockingwrite = $requirelockingwrite;
+ $cachedefinition->requiresearchable = $requiresearchable;
$cachedefinition->maxsize = $maxsize;
$cachedefinition->overrideclass = $overrideclass;
$cachedefinition->overrideclassfile = $overrideclassfile;
@@ -634,6 +647,15 @@ public function require_locking_write() {
}
/**
+ * Returns true if this definition requires a searchable cache.
+ * @since 2.4.4
+ * @return bool
+ */
+ public function require_searchable() {
+ return $this->requiresearchable;
+ }
+
+ /**
* Returns true if this definition has an associated data source.
* @return bool
*/
@@ -686,6 +708,9 @@ public function get_requirements_bin() {
if ($this->require_multiple_identifiers()) {
$requires += cache_store::SUPPORTS_MULTIPLE_IDENTIFIERS;
}
+ if ($this->require_searchable()) {
+ $requires += cache_store::IS_SEARCHABLE;
+ }
return $requires;
}
@@ -694,7 +719,7 @@ public function get_requirements_bin() {
* @return bool
*/
public function should_be_persistent() {
- return $this->persistent;
+ return $this->persistent || $this->mode === cache_store::MODE_SESSION;
}
/**
@@ -207,9 +207,7 @@ public function create_cache_from_params($mode, $component, $area, array $identi
if (array_key_exists($key, $this->cachesfromparams)) {
return $this->cachesfromparams[$key];
}
- // Get the class. Note this is a late static binding so we need to use get_called_class.
$definition = cache_definition::load_adhoc($mode, $component, $area, $options);
- $config = $this->create_config_instance();
$definition->set_identifiers($identifiers);
$cache = $this->create_cache($definition, $identifiers);
if ($definition->should_be_persistent()) {
@@ -244,10 +244,9 @@ public static function invalidate_by_event($event, array $keys) {
if ($definition->invalidates_on_event($event)) {
// OK at this point we know that the definition has information to invalidate on the event.
// There are two routes, either its an application cache in which case we can invalidate it now.
- // or it is a session cache in which case we need to set something to the "Event invalidation" definition.
- // No need to deal with request caches, we don't want to change data half way through a request.
- if ($definition->get_mode() === cache_store::MODE_APPLICATION) {
- $cache = $factory->create_cache($definition);
+ // or it is a persistent cache that also needs to be invalidated now.
+ if ($definition->get_mode() === cache_store::MODE_APPLICATION || $definition->should_be_persistent()) {
+ $cache = $factory->create_cache_from_definition($definition->get_component(), $definition->get_area());
$cache->delete_many($keys);
}
@@ -568,4 +567,64 @@ public static function get_site_version() {
global $CFG;
return (string)$CFG->version;
}
+
+ /**
+ * Runs cron routines for MUC.
+ */
+ public static function cron() {
+ self::clean_old_session_data(true);
+ }
+
+ /**
+ * Cleans old session data from cache stores used for session based definitions.
+ *
+ * @param bool $output If set to true output will be given.
+ */
+ public static function clean_old_session_data($output = false) {
+ global $CFG;
+ if ($output) {
+ mtrace('Cleaning up stale session data from cache stores.');
+ }
+ $factory = cache_factory::instance();
+ $config = $factory->create_config_instance();
+ $definitions = $config->get_definitions();
+ $purgetime = time() - $CFG->sessiontimeout;
+ foreach ($definitions as $definitionarray) {
+ // We are only interested in session caches.
+ if (!($definitionarray['mode'] & cache_store::MODE_SESSION)) {
+ continue;
+ }
+ $definition = $factory->create_definition($definitionarray['component'], $definitionarray['area']);
+ $stores = $config->get_stores_for_definition($definition);
+ // Turn them into store instances.
+ $stores = self::initialise_cachestore_instances($stores, $definition);
+ // Initialise all of the stores used for that definition.
+ foreach ($stores as $store) {
+ // If the store doesn't support searching we can skip it.
+ if (!($store instanceof cache_is_searchable)) {
+ debugging('Cache stores used for session definitions should ideally be searchable.', DEBUG_DEVELOPER);
+ continue;
+ }
+ // Get all of the keys.
+ $keys = $store->find_by_prefix(cache_session::KEY_PREFIX);
+ $todelete = array();
+ foreach ($store->get_many($keys) as $key => $value) {
+ if (strpos($key, cache_session::KEY_PREFIX) !== 0 || !is_array($value) || !isset($value['lastaccess'])) {
+ continue;
+ }
+ if ((int)$value['lastaccess'] < $purgetime || true) {
+ $todelete[] = $key;
+ }
+ }
+ if (count($todelete)) {
+ $outcome = (int)$store->delete_many($todelete);
+ if ($output) {
+ $strdef = s($definition->get_id());
+ $strstore = s($store->my_name());
+ mtrace("- Removed {$outcome} old {$strdef} sessions from the '{$strstore}' cache store.");
+ }
+ }
+ }
+ }
+ }
}
@@ -339,6 +339,30 @@ public function has_all(array $keys);
}
/**
+ * Cache store feature: keys are searchable.
+ *
+ * Cache stores can choose to implement this interface.
+ * In order for a store to be usable as a session cache it must implement this interface.
+ *
+ * @since 2.4.4
+ */
+interface cache_is_searchable {
+ /**
+ * Finds all of the keys being used by the cache store.
+ *
+ * @return array.
+ */
+ public function find_all();
+
+ /**
+ * Finds all of the keys whose keys start with the given prefix.
+ *
+ * @param string $prefix
+ */
+ public function find_by_prefix($prefix);
+}
+
+/**
* Cache store feature: configurable.
*
* This feature should be implemented by all cache stores that are configurable when adding an instance.
Oops, something went wrong.

0 comments on commit 0c60dae

Please sign in to comment.