Skip to content

Commit

Permalink
MDL-38565 cache: session caches now function as expected
Browse files Browse the repository at this point in the history
This change is a large change to the way sessions are handled
within MUC after it was discovered that session did not function
as expected when any store other than the default session store
was being used.
As part of this change the session loader has been largely
customised in order to consolidate session data for the loader.
The unit tests have also being greatly increased to provide
better coverage for sessions.
  • Loading branch information
Sam Hemelryk committed Apr 18, 2013
1 parent 3a8c438 commit dbd2ea4
Show file tree
Hide file tree
Showing 14 changed files with 1,014 additions and 29 deletions.
4 changes: 3 additions & 1 deletion cache/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -236,4 +238,4 @@ The following snippet illustates how to configure the three core cache stores th

define('TEST_CACHESTORE_MEMCACHE_TESTSERVERS', '127.0.0.1:11211');
define('TEST_CACHESTORE_MEMCACHED_TESTSERVERS', '127.0.0.1:11211');
define('TEST_CACHESTORE_MONGODB_TESTSERVER', 'mongodb://localhost:27017');
define('TEST_CACHESTORE_MONGODB_TESTSERVER', 'mongodb://localhost:27017');
27 changes: 26 additions & 1 deletion cache/classes/definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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'];
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -633,6 +646,15 @@ public function require_locking_write() {
return $this->requirelockingwrite;
}

/**
* 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
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

/**
Expand Down
2 changes: 0 additions & 2 deletions cache/classes/factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
7 changes: 3 additions & 4 deletions cache/classes/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
24 changes: 24 additions & 0 deletions cache/classes/interfaces.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,30 @@ public function has_any(array $keys);
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.
*
Expand Down
Loading

0 comments on commit dbd2ea4

Please sign in to comment.