mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-82158 core_cache: Move interfaces
This commit is contained in:
parent
6cd55074c7
commit
4038c52928
330
cache/classes/application_cache.php
vendored
Normal file
330
cache/classes/application_cache.php
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* An application cache.
|
||||
*
|
||||
* This class is used for application caches returned by the cache::make methods.
|
||||
* On top of the standard functionality it also allows locking to be required and or manually operated.
|
||||
*
|
||||
* This cache class should never be interacted with directly. Instead you should always use the cache::make methods.
|
||||
* It is technically possible to call those methods through this class however there is no guarantee that you will get an
|
||||
* instance of this class back again.
|
||||
*
|
||||
* @internal don't use me directly.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_application extends cache implements cache_loader_with_locking {
|
||||
|
||||
/**
|
||||
* Lock identifier.
|
||||
* This is used to ensure the lock belongs to the cache instance + definition + user.
|
||||
* @var string
|
||||
*/
|
||||
protected $lockidentifier;
|
||||
|
||||
/**
|
||||
* Gets set to true if the cache's primary store natively supports locking.
|
||||
* If it does then we use that, otherwise we need to instantiate a second store to use for locking.
|
||||
* @var cache_store
|
||||
*/
|
||||
protected $nativelocking = null;
|
||||
|
||||
/**
|
||||
* Gets set to true if the cache is going to be using locking.
|
||||
* This isn't a requirement, it doesn't need to use locking (most won't) and this bool is used to quickly check things.
|
||||
* If required then locking will be forced for the get|set|delete operation.
|
||||
* @var bool
|
||||
*/
|
||||
protected $requirelocking = false;
|
||||
|
||||
/**
|
||||
* Gets set to true if the cache writes (set|delete) must have a manual lock created first
|
||||
* @var bool
|
||||
*/
|
||||
protected $requirelockingbeforewrite = false;
|
||||
|
||||
/**
|
||||
* Gets set to a cache_store to use for locking if the caches primary store doesn't support locking natively.
|
||||
* @var cache_lock_interface
|
||||
*/
|
||||
protected $cachelockinstance;
|
||||
|
||||
/**
|
||||
* Store a list of locks acquired by this process.
|
||||
* @var array
|
||||
*/
|
||||
protected $locks;
|
||||
|
||||
/**
|
||||
* Overrides the cache construct method.
|
||||
*
|
||||
* You should not call this method from your code, instead you should use the cache::make methods.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @param cache_store $store
|
||||
* @param cache_loader|cache_data_source $loader
|
||||
*/
|
||||
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
|
||||
parent::__construct($definition, $store, $loader);
|
||||
$this->nativelocking = $this->store_supports_native_locking();
|
||||
if ($definition->require_locking()) {
|
||||
$this->requirelocking = true;
|
||||
$this->requirelockingbeforewrite = $definition->require_locking_before_write();
|
||||
}
|
||||
|
||||
$this->handle_invalidation_events();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier to use
|
||||
*
|
||||
* @staticvar int $instances Counts the number of instances. Used as part of the lock identifier.
|
||||
* @return string
|
||||
*/
|
||||
public function get_identifier() {
|
||||
static $instances = 0;
|
||||
if ($this->lockidentifier === null) {
|
||||
$this->lockidentifier = md5(
|
||||
$this->get_definition()->generate_definition_hash() .
|
||||
sesskey() .
|
||||
$instances++ .
|
||||
'cache_application'
|
||||
);
|
||||
}
|
||||
return $this->lockidentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes the instance up after a clone.
|
||||
*/
|
||||
public function __clone() {
|
||||
// Force a new idenfitier.
|
||||
$this->lockidentifier = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires a lock on the given key.
|
||||
*
|
||||
* This is done automatically if the definition requires it.
|
||||
* It is recommended to use a definition if you want to have locking although it is possible to do locking without having
|
||||
* it required by the definition.
|
||||
* The problem with such an approach is that you cannot ensure that code will consistently use locking. You will need to
|
||||
* rely on the integrators review skills.
|
||||
*
|
||||
* @param string|int $key The key as given to get|set|delete
|
||||
* @return bool Always returns true
|
||||
* @throws moodle_exception If the lock cannot be obtained
|
||||
*/
|
||||
public function acquire_lock($key) {
|
||||
$releaseparent = false;
|
||||
try {
|
||||
if ($this->get_loader() !== false) {
|
||||
$this->get_loader()->acquire_lock($key);
|
||||
// We need to release this lock later if the lock is not successful.
|
||||
$releaseparent = true;
|
||||
}
|
||||
$hashedkey = cache_helper::hash_key($key, $this->get_definition());
|
||||
$before = microtime(true);
|
||||
if ($this->nativelocking) {
|
||||
$lock = $this->get_store()->acquire_lock($hashedkey, $this->get_identifier());
|
||||
} else {
|
||||
$this->ensure_cachelock_available();
|
||||
$lock = $this->cachelockinstance->lock($hashedkey, $this->get_identifier());
|
||||
}
|
||||
$after = microtime(true);
|
||||
if ($lock) {
|
||||
$this->locks[$hashedkey] = $lock;
|
||||
if (MDL_PERF || $this->perfdebug) {
|
||||
\core\lock\timing_wrapper_lock_factory::record_lock_data($after, $before,
|
||||
$this->get_definition()->get_id(), $hashedkey, $lock, $this->get_identifier() . $hashedkey);
|
||||
}
|
||||
$releaseparent = false;
|
||||
return true;
|
||||
} else {
|
||||
throw new moodle_exception('ex_unabletolock', 'cache', '', null,
|
||||
'store: ' . get_class($this->get_store()) . ', lock: ' . $hashedkey);
|
||||
}
|
||||
} finally {
|
||||
// Release the parent lock if we acquired it, then threw an exception.
|
||||
if ($releaseparent) {
|
||||
$this->get_loader()->release_lock($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this cache has a lock on the given key.
|
||||
*
|
||||
* @param string|int $key The key as given to get|set|delete
|
||||
* @return bool|null Returns true if there is a lock and this cache has it, null if no one has a lock on that key, false if
|
||||
* someone else has the lock.
|
||||
*/
|
||||
public function check_lock_state($key) {
|
||||
$key = cache_helper::hash_key($key, $this->get_definition());
|
||||
if (!empty($this->locks[$key])) {
|
||||
return true; // Shortcut to save having to make a call to the cache store if the lock is held by this process.
|
||||
}
|
||||
if ($this->nativelocking) {
|
||||
return $this->get_store()->check_lock_state($key, $this->get_identifier());
|
||||
} else {
|
||||
$this->ensure_cachelock_available();
|
||||
return $this->cachelockinstance->check_state($key, $this->get_identifier());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the lock this cache has on the given key
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the operation succeeded, false otherwise.
|
||||
*/
|
||||
public function release_lock($key) {
|
||||
$loaderkey = $key;
|
||||
$key = cache_helper::hash_key($key, $this->get_definition());
|
||||
if ($this->nativelocking) {
|
||||
$released = $this->get_store()->release_lock($key, $this->get_identifier());
|
||||
} else {
|
||||
$this->ensure_cachelock_available();
|
||||
$released = $this->cachelockinstance->unlock($key, $this->get_identifier());
|
||||
}
|
||||
if ($released && array_key_exists($key, $this->locks)) {
|
||||
unset($this->locks[$key]);
|
||||
if (MDL_PERF || $this->perfdebug) {
|
||||
\core\lock\timing_wrapper_lock_factory::record_lock_released_data($this->get_identifier() . $key);
|
||||
}
|
||||
}
|
||||
if ($this->get_loader() !== false) {
|
||||
$this->get_loader()->release_lock($loaderkey);
|
||||
}
|
||||
return $released;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the dedicated lock store is ready to go.
|
||||
*
|
||||
* This should only happen if the cache store doesn't natively support it.
|
||||
*/
|
||||
protected function ensure_cachelock_available() {
|
||||
if ($this->cachelockinstance === null) {
|
||||
$this->cachelockinstance = cache_helper::get_cachelock_for_store($this->get_store());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a key => value pair to the cache.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set('main', 'http://moodle.org');
|
||||
* $cache->set('docs', 'http://docs.moodle.org');
|
||||
* $cache->set('tracker', 'http://tracker.moodle.org');
|
||||
* $cache->set('qa', 'http://qa.moodle.net');
|
||||
* </code>
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param int $version Version number
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @param bool $setparents If true, sets all parent loaders, otherwise only this one
|
||||
* @return bool True on success, false otherwise.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
protected function set_implementation($key, int $version, $data, bool $setparents = true): bool {
|
||||
if ($this->requirelockingbeforewrite && !$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to set cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
return parent::set_implementation($key, $version, $data, $setparents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends several key => value pairs to the cache.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set_many(array(
|
||||
* 'main' => 'http://moodle.org',
|
||||
* 'docs' => 'http://docs.moodle.org',
|
||||
* 'tracker' => 'http://tracker.moodle.org',
|
||||
* 'qa' => ''http://qa.moodle.net'
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
* @param array $keyvaluearray An array of key => value pairs to send to the cache.
|
||||
* @return int The number of items successfully set. It is up to the developer to check this matches the number of items.
|
||||
* ... if they care that is.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
if ($this->requirelockingbeforewrite) {
|
||||
foreach ($keyvaluearray as $key => $value) {
|
||||
if (!$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to set cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::set_many($keyvaluearray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return bool True of success, false otherwise.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
public function delete($key, $recurse = true) {
|
||||
if ($this->requirelockingbeforewrite && !$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to delete cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
return parent::delete($key, $recurse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all of the given keys from the cache.
|
||||
*
|
||||
* @param array $keys The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return int The number of items successfully deleted.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
public function delete_many(array $keys, $recurse = true) {
|
||||
if ($this->requirelockingbeforewrite) {
|
||||
foreach ($keys as $key) {
|
||||
if (!$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to delete cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::delete_many($keys, $recurse);
|
||||
}
|
||||
}
|
910
cache/classes/loaders.php → cache/classes/cache.php
vendored
910
cache/classes/loaders.php → cache/classes/cache.php
vendored
@ -14,20 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache loaders
|
||||
*
|
||||
* This file is part of Moodle's cache API, affectionately called MUC.
|
||||
* It contains the components that are required 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
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The main cache class.
|
||||
*
|
||||
@ -1563,899 +1549,3 @@ class cache implements cache_loader {
|
||||
public function purge_current_user() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An application cache.
|
||||
*
|
||||
* This class is used for application caches returned by the cache::make methods.
|
||||
* On top of the standard functionality it also allows locking to be required and or manually operated.
|
||||
*
|
||||
* This cache class should never be interacted with directly. Instead you should always use the cache::make methods.
|
||||
* It is technically possible to call those methods through this class however there is no guarantee that you will get an
|
||||
* instance of this class back again.
|
||||
*
|
||||
* @internal don't use me directly.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_application extends cache implements cache_loader_with_locking {
|
||||
|
||||
/**
|
||||
* Lock identifier.
|
||||
* This is used to ensure the lock belongs to the cache instance + definition + user.
|
||||
* @var string
|
||||
*/
|
||||
protected $lockidentifier;
|
||||
|
||||
/**
|
||||
* Gets set to true if the cache's primary store natively supports locking.
|
||||
* If it does then we use that, otherwise we need to instantiate a second store to use for locking.
|
||||
* @var cache_store
|
||||
*/
|
||||
protected $nativelocking = null;
|
||||
|
||||
/**
|
||||
* Gets set to true if the cache is going to be using locking.
|
||||
* This isn't a requirement, it doesn't need to use locking (most won't) and this bool is used to quickly check things.
|
||||
* If required then locking will be forced for the get|set|delete operation.
|
||||
* @var bool
|
||||
*/
|
||||
protected $requirelocking = false;
|
||||
|
||||
/**
|
||||
* Gets set to true if the cache writes (set|delete) must have a manual lock created first
|
||||
* @var bool
|
||||
*/
|
||||
protected $requirelockingbeforewrite = false;
|
||||
|
||||
/**
|
||||
* Gets set to a cache_store to use for locking if the caches primary store doesn't support locking natively.
|
||||
* @var cache_lock_interface
|
||||
*/
|
||||
protected $cachelockinstance;
|
||||
|
||||
/**
|
||||
* Store a list of locks acquired by this process.
|
||||
* @var array
|
||||
*/
|
||||
protected $locks;
|
||||
|
||||
/**
|
||||
* Overrides the cache construct method.
|
||||
*
|
||||
* You should not call this method from your code, instead you should use the cache::make methods.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @param cache_store $store
|
||||
* @param cache_loader|cache_data_source $loader
|
||||
*/
|
||||
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
|
||||
parent::__construct($definition, $store, $loader);
|
||||
$this->nativelocking = $this->store_supports_native_locking();
|
||||
if ($definition->require_locking()) {
|
||||
$this->requirelocking = true;
|
||||
$this->requirelockingbeforewrite = $definition->require_locking_before_write();
|
||||
}
|
||||
|
||||
$this->handle_invalidation_events();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier to use
|
||||
*
|
||||
* @staticvar int $instances Counts the number of instances. Used as part of the lock identifier.
|
||||
* @return string
|
||||
*/
|
||||
public function get_identifier() {
|
||||
static $instances = 0;
|
||||
if ($this->lockidentifier === null) {
|
||||
$this->lockidentifier = md5(
|
||||
$this->get_definition()->generate_definition_hash() .
|
||||
sesskey() .
|
||||
$instances++ .
|
||||
'cache_application'
|
||||
);
|
||||
}
|
||||
return $this->lockidentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes the instance up after a clone.
|
||||
*/
|
||||
public function __clone() {
|
||||
// Force a new idenfitier.
|
||||
$this->lockidentifier = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires a lock on the given key.
|
||||
*
|
||||
* This is done automatically if the definition requires it.
|
||||
* It is recommended to use a definition if you want to have locking although it is possible to do locking without having
|
||||
* it required by the definition.
|
||||
* The problem with such an approach is that you cannot ensure that code will consistently use locking. You will need to
|
||||
* rely on the integrators review skills.
|
||||
*
|
||||
* @param string|int $key The key as given to get|set|delete
|
||||
* @return bool Always returns true
|
||||
* @throws moodle_exception If the lock cannot be obtained
|
||||
*/
|
||||
public function acquire_lock($key) {
|
||||
$releaseparent = false;
|
||||
try {
|
||||
if ($this->get_loader() !== false) {
|
||||
$this->get_loader()->acquire_lock($key);
|
||||
// We need to release this lock later if the lock is not successful.
|
||||
$releaseparent = true;
|
||||
}
|
||||
$hashedkey = cache_helper::hash_key($key, $this->get_definition());
|
||||
$before = microtime(true);
|
||||
if ($this->nativelocking) {
|
||||
$lock = $this->get_store()->acquire_lock($hashedkey, $this->get_identifier());
|
||||
} else {
|
||||
$this->ensure_cachelock_available();
|
||||
$lock = $this->cachelockinstance->lock($hashedkey, $this->get_identifier());
|
||||
}
|
||||
$after = microtime(true);
|
||||
if ($lock) {
|
||||
$this->locks[$hashedkey] = $lock;
|
||||
if (MDL_PERF || $this->perfdebug) {
|
||||
\core\lock\timing_wrapper_lock_factory::record_lock_data($after, $before,
|
||||
$this->get_definition()->get_id(), $hashedkey, $lock, $this->get_identifier() . $hashedkey);
|
||||
}
|
||||
$releaseparent = false;
|
||||
return true;
|
||||
} else {
|
||||
throw new moodle_exception('ex_unabletolock', 'cache', '', null,
|
||||
'store: ' . get_class($this->get_store()) . ', lock: ' . $hashedkey);
|
||||
}
|
||||
} finally {
|
||||
// Release the parent lock if we acquired it, then threw an exception.
|
||||
if ($releaseparent) {
|
||||
$this->get_loader()->release_lock($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this cache has a lock on the given key.
|
||||
*
|
||||
* @param string|int $key The key as given to get|set|delete
|
||||
* @return bool|null Returns true if there is a lock and this cache has it, null if no one has a lock on that key, false if
|
||||
* someone else has the lock.
|
||||
*/
|
||||
public function check_lock_state($key) {
|
||||
$key = cache_helper::hash_key($key, $this->get_definition());
|
||||
if (!empty($this->locks[$key])) {
|
||||
return true; // Shortcut to save having to make a call to the cache store if the lock is held by this process.
|
||||
}
|
||||
if ($this->nativelocking) {
|
||||
return $this->get_store()->check_lock_state($key, $this->get_identifier());
|
||||
} else {
|
||||
$this->ensure_cachelock_available();
|
||||
return $this->cachelockinstance->check_state($key, $this->get_identifier());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the lock this cache has on the given key
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the operation succeeded, false otherwise.
|
||||
*/
|
||||
public function release_lock($key) {
|
||||
$loaderkey = $key;
|
||||
$key = cache_helper::hash_key($key, $this->get_definition());
|
||||
if ($this->nativelocking) {
|
||||
$released = $this->get_store()->release_lock($key, $this->get_identifier());
|
||||
} else {
|
||||
$this->ensure_cachelock_available();
|
||||
$released = $this->cachelockinstance->unlock($key, $this->get_identifier());
|
||||
}
|
||||
if ($released && array_key_exists($key, $this->locks)) {
|
||||
unset($this->locks[$key]);
|
||||
if (MDL_PERF || $this->perfdebug) {
|
||||
\core\lock\timing_wrapper_lock_factory::record_lock_released_data($this->get_identifier() . $key);
|
||||
}
|
||||
}
|
||||
if ($this->get_loader() !== false) {
|
||||
$this->get_loader()->release_lock($loaderkey);
|
||||
}
|
||||
return $released;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the dedicated lock store is ready to go.
|
||||
*
|
||||
* This should only happen if the cache store doesn't natively support it.
|
||||
*/
|
||||
protected function ensure_cachelock_available() {
|
||||
if ($this->cachelockinstance === null) {
|
||||
$this->cachelockinstance = cache_helper::get_cachelock_for_store($this->get_store());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a key => value pair to the cache.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set('main', 'http://moodle.org');
|
||||
* $cache->set('docs', 'http://docs.moodle.org');
|
||||
* $cache->set('tracker', 'http://tracker.moodle.org');
|
||||
* $cache->set('qa', 'http://qa.moodle.net');
|
||||
* </code>
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param int $version Version number
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @param bool $setparents If true, sets all parent loaders, otherwise only this one
|
||||
* @return bool True on success, false otherwise.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
protected function set_implementation($key, int $version, $data, bool $setparents = true): bool {
|
||||
if ($this->requirelockingbeforewrite && !$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to set cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
return parent::set_implementation($key, $version, $data, $setparents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends several key => value pairs to the cache.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set_many(array(
|
||||
* 'main' => 'http://moodle.org',
|
||||
* 'docs' => 'http://docs.moodle.org',
|
||||
* 'tracker' => 'http://tracker.moodle.org',
|
||||
* 'qa' => ''http://qa.moodle.net'
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
* @param array $keyvaluearray An array of key => value pairs to send to the cache.
|
||||
* @return int The number of items successfully set. It is up to the developer to check this matches the number of items.
|
||||
* ... if they care that is.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
if ($this->requirelockingbeforewrite) {
|
||||
foreach ($keyvaluearray as $key => $value) {
|
||||
if (!$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to set cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::set_many($keyvaluearray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return bool True of success, false otherwise.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
public function delete($key, $recurse = true) {
|
||||
if ($this->requirelockingbeforewrite && !$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to delete cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
return parent::delete($key, $recurse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all of the given keys from the cache.
|
||||
*
|
||||
* @param array $keys The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return int The number of items successfully deleted.
|
||||
* @throws coding_exception If a required lock has not beeen acquired
|
||||
*/
|
||||
public function delete_many(array $keys, $recurse = true) {
|
||||
if ($this->requirelockingbeforewrite) {
|
||||
foreach ($keys as $key) {
|
||||
if (!$this->check_lock_state($key)) {
|
||||
throw new coding_exception('Attempted to delete cache key "' . $key . '" without a lock. '
|
||||
. 'Locking before writes is required for ' . $this->get_definition()->get_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::delete_many($keys, $recurse);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A session cache.
|
||||
*
|
||||
* This class is used for session caches returned by the cache::make methods.
|
||||
*
|
||||
* It differs from the application loader in a couple of noteable ways:
|
||||
* 1. Sessions are always expected to exist.
|
||||
* Because of this we don't ever use the static acceleration array.
|
||||
* 2. Session data for a loader instance (store + definition) is consolidate into a
|
||||
* single array for storage within the store.
|
||||
* Along with this we embed a lastaccessed time with the data. This way we can
|
||||
* check sessions for a last access time.
|
||||
* 3. Session stores are required to support key searching and must
|
||||
* implement cache_is_searchable. This ensures stores used for the cache can be
|
||||
* targetted for garbage collection of session data.
|
||||
*
|
||||
* This cache class should never be interacted with directly. Instead you should always use the cache::make methods.
|
||||
* It is technically possible to call those methods through this class however there is no guarantee that you will get an
|
||||
* instance of this class back again.
|
||||
*
|
||||
* @todo we should support locking in the session as well. Should be pretty simple to set up.
|
||||
*
|
||||
* @internal don't use me directly.
|
||||
* @method cache_store|cache_is_searchable get_store() Returns the cache store which must implement both cache_is_searchable.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_session extends cache {
|
||||
/**
|
||||
* The user the session has been established for.
|
||||
* @var int
|
||||
*/
|
||||
protected static $loadeduserid = null;
|
||||
|
||||
/**
|
||||
* The userid this cache is currently using.
|
||||
* @var int
|
||||
*/
|
||||
protected $currentuserid = null;
|
||||
|
||||
/**
|
||||
* The session id we are currently using.
|
||||
* @var array
|
||||
*/
|
||||
protected $sessionid = null;
|
||||
|
||||
/**
|
||||
* The session data for the above session id.
|
||||
* @var array
|
||||
*/
|
||||
protected $session = null;
|
||||
|
||||
/**
|
||||
* Constant used to prefix keys.
|
||||
*/
|
||||
const KEY_PREFIX = 'sess_';
|
||||
|
||||
/**
|
||||
* This is the key used to track last access.
|
||||
*/
|
||||
const LASTACCESS = '__lastaccess__';
|
||||
|
||||
/**
|
||||
* Override the cache::construct method.
|
||||
*
|
||||
* This function gets overriden so that we can process any invalidation events if need be.
|
||||
* If the definition doesn't have any invalidation events then this occurs exactly as it would for the cache class.
|
||||
* Otherwise we look at the last invalidation time and then check the invalidation data for events that have occured
|
||||
* between then now.
|
||||
*
|
||||
* You should not call this method from your code, instead you should use the cache::make methods.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @param cache_store $store
|
||||
* @param cache_loader|cache_data_source $loader
|
||||
*/
|
||||
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
|
||||
// First up copy the loadeduserid to the current user id.
|
||||
$this->currentuserid = self::$loadeduserid;
|
||||
$this->set_session_id();
|
||||
parent::__construct($definition, $store, $loader);
|
||||
|
||||
// This will trigger check tracked user. If this gets removed a call to that will need to be added here in its place.
|
||||
$this->set(self::LASTACCESS, cache::now());
|
||||
|
||||
$this->handle_invalidation_events();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session id for the loader.
|
||||
*/
|
||||
protected function set_session_id() {
|
||||
$this->sessionid = preg_replace('#[^a-zA-Z0-9_]#', '_', session_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix used for all keys.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_key_prefix() {
|
||||
return 'u'.$this->currentuserid.'_'.$this->sessionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the key turning it into a string (or array is required) suitable to be passed to the cache store.
|
||||
*
|
||||
* This function is called for every operation that uses keys. For this reason we use this function to also check
|
||||
* that the current user is the same as the user who last used this cache.
|
||||
*
|
||||
* On top of that if prepends the string 'sess_' to the start of all keys. The _ ensures things are easily identifiable.
|
||||
*
|
||||
* @param string|int $key As passed to get|set|delete etc.
|
||||
* @return string|array String unless the store supports multi-identifiers in which case an array if returned.
|
||||
*/
|
||||
protected function parse_key($key) {
|
||||
$prefix = $this->get_key_prefix();
|
||||
if ($key === self::LASTACCESS) {
|
||||
return $key.$prefix;
|
||||
}
|
||||
return $prefix.'_'.parent::parse_key($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that this cache instance is tracking the current user.
|
||||
*/
|
||||
protected function check_tracked_user() {
|
||||
if (isset($_SESSION['USER']->id) && $_SESSION['USER']->id !== null) {
|
||||
// Get the id of the current user.
|
||||
$new = $_SESSION['USER']->id;
|
||||
} else {
|
||||
// No user set up yet.
|
||||
$new = 0;
|
||||
}
|
||||
if ($new !== self::$loadeduserid) {
|
||||
// The current user doesn't match the tracked userid for this request.
|
||||
if (!is_null(self::$loadeduserid)) {
|
||||
// Purge the data we have for the old user.
|
||||
// This way we don't bloat the session.
|
||||
$this->purge();
|
||||
}
|
||||
self::$loadeduserid = $new;
|
||||
$this->currentuserid = $new;
|
||||
} else if ($new !== $this->currentuserid) {
|
||||
// The current user matches the loaded user but not the user last used by this cache.
|
||||
$this->purge_current_user();
|
||||
$this->currentuserid = $new;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the session cache of all data belonging to the current user.
|
||||
*/
|
||||
public function purge_current_user() {
|
||||
$keys = $this->get_store()->find_by_prefix($this->get_key_prefix());
|
||||
$this->get_store()->delete_many($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value for the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* It can be any structure although using a scalar string or int is recommended in the interests of performance.
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param int $requiredversion Minimum required version of the data or cache::VERSION_NONE
|
||||
* @param int $strictness One of IGNORE_MISSING | MUST_EXIST
|
||||
* @param mixed &$actualversion If specified, will be set to the actual version number retrieved
|
||||
* @return mixed|false The data from the cache or false if the key did not exist within the cache.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
protected function get_implementation($key, int $requiredversion, int $strictness, &$actualversion = null) {
|
||||
// Check the tracked user.
|
||||
$this->check_tracked_user();
|
||||
|
||||
// Use parent code.
|
||||
return parent::get_implementation($key, $requiredversion, $strictness, $actualversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a key => value pair to the cache.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set('main', 'http://moodle.org');
|
||||
* $cache->set('docs', 'http://docs.moodle.org');
|
||||
* $cache->set('tracker', 'http://tracker.moodle.org');
|
||||
* $cache->set('qa', 'http://qa.moodle.net');
|
||||
* </code>
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* It can be any structure although using a scalar string or int is recommended in the interests of performance.
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @return bool True on success, false otherwise.
|
||||
*/
|
||||
public function set($key, $data) {
|
||||
$this->check_tracked_user();
|
||||
$loader = $this->get_loader();
|
||||
if ($loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$loader->set($key, $data);
|
||||
}
|
||||
if (is_object($data) && $data instanceof cacheable_object) {
|
||||
$data = new cache_cached_object($data);
|
||||
} else if (!$this->get_store()->supports_dereferencing_objects() && !is_scalar($data)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$data = $this->unref($data);
|
||||
}
|
||||
// We dont' support native TTL here as we consolidate data for sessions.
|
||||
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
|
||||
$data = new cache_ttl_wrapper($data, $this->get_definition()->get_ttl());
|
||||
}
|
||||
$success = $this->get_store()->set($this->parse_key($key), $data);
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_set($this->get_store(), $this->get_definition(), 1,
|
||||
$this->get_store()->get_last_io_bytes());
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return bool True of success, false otherwise.
|
||||
*/
|
||||
public function delete($key, $recurse = true) {
|
||||
$parsedkey = $this->parse_key($key);
|
||||
if ($recurse && $this->get_loader() !== false) {
|
||||
// Delete from the bottom of the stack first.
|
||||
$this->get_loader()->delete($key, $recurse);
|
||||
}
|
||||
return $this->get_store()->delete($parsedkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array of values for an array of keys.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* @param array $keys The keys of the data being requested.
|
||||
* Each key can be any structure although using a scalar string or int is recommended in the interests of performance.
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @return array An array of key value pairs for the items that could be retrieved from the cache.
|
||||
* If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
|
||||
* Otherwise any key that did not exist will have a data value of false within the results.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get_many(array $keys, $strictness = IGNORE_MISSING) {
|
||||
$this->check_tracked_user();
|
||||
$parsedkeys = array();
|
||||
$keymap = array();
|
||||
foreach ($keys as $key) {
|
||||
$parsedkey = $this->parse_key($key);
|
||||
$parsedkeys[$key] = $parsedkey;
|
||||
$keymap[$parsedkey] = $key;
|
||||
}
|
||||
$result = $this->get_store()->get_many($parsedkeys);
|
||||
if ($this->perfdebug) {
|
||||
$readbytes = $this->get_store()->get_last_io_bytes();
|
||||
}
|
||||
$return = array();
|
||||
$missingkeys = array();
|
||||
$hasmissingkeys = false;
|
||||
foreach ($result as $parsedkey => $value) {
|
||||
$key = $keymap[$parsedkey];
|
||||
if ($value instanceof cache_ttl_wrapper) {
|
||||
/* @var cache_ttl_wrapper $value */
|
||||
if ($value->has_expired()) {
|
||||
$this->delete($keymap[$parsedkey]);
|
||||
$value = false;
|
||||
} else {
|
||||
$value = $value->data;
|
||||
}
|
||||
}
|
||||
if ($value instanceof cache_cached_object) {
|
||||
/* @var cache_cached_object $value */
|
||||
$value = $value->restore_object();
|
||||
} else if (!$this->get_store()->supports_dereferencing_objects() && !is_scalar($value)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$value = $this->unref($value);
|
||||
}
|
||||
$return[$key] = $value;
|
||||
if ($value === false) {
|
||||
$hasmissingkeys = true;
|
||||
$missingkeys[$parsedkey] = $key;
|
||||
}
|
||||
}
|
||||
if ($hasmissingkeys) {
|
||||
// We've got missing keys - we've got to check any loaders or data sources.
|
||||
$loader = $this->get_loader();
|
||||
$datasource = $this->get_datasource();
|
||||
if ($loader !== false) {
|
||||
foreach ($loader->get_many($missingkeys) as $key => $value) {
|
||||
if ($value !== false) {
|
||||
$return[$key] = $value;
|
||||
unset($missingkeys[$parsedkeys[$key]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$hasmissingkeys = count($missingkeys) > 0;
|
||||
if ($datasource !== false && $hasmissingkeys) {
|
||||
// We're still missing keys but we've got a datasource.
|
||||
foreach ($datasource->load_many_for_cache($missingkeys) as $key => $value) {
|
||||
if ($value !== false) {
|
||||
$return[$key] = $value;
|
||||
unset($missingkeys[$parsedkeys[$key]]);
|
||||
}
|
||||
}
|
||||
$hasmissingkeys = count($missingkeys) > 0;
|
||||
}
|
||||
}
|
||||
if ($hasmissingkeys && $strictness === MUST_EXIST) {
|
||||
throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
}
|
||||
if ($this->perfdebug) {
|
||||
$hits = 0;
|
||||
$misses = 0;
|
||||
foreach ($return as $value) {
|
||||
if ($value === false) {
|
||||
$misses++;
|
||||
} else {
|
||||
$hits++;
|
||||
}
|
||||
}
|
||||
cache_helper::record_cache_hit($this->get_store(), $this->get_definition(), $hits, $readbytes);
|
||||
cache_helper::record_cache_miss($this->get_store(), $this->get_definition(), $misses);
|
||||
}
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all of the given keys from the cache.
|
||||
*
|
||||
* @param array $keys The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
public function delete_many(array $keys, $recurse = true) {
|
||||
$parsedkeys = array_map(array($this, 'parse_key'), $keys);
|
||||
if ($recurse && $this->get_loader() !== false) {
|
||||
// Delete from the bottom of the stack first.
|
||||
$this->get_loader()->delete_many($keys, $recurse);
|
||||
}
|
||||
return $this->get_store()->delete_many($parsedkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends several key => value pairs to the cache.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set_many(array(
|
||||
* 'main' => 'http://moodle.org',
|
||||
* 'docs' => 'http://docs.moodle.org',
|
||||
* 'tracker' => 'http://tracker.moodle.org',
|
||||
* 'qa' => ''http://qa.moodle.net'
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
* @param array $keyvaluearray An array of key => value pairs to send to the cache.
|
||||
* @return int The number of items successfully set. It is up to the developer to check this matches the number of items.
|
||||
* ... if they care that is.
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
$this->check_tracked_user();
|
||||
$loader = $this->get_loader();
|
||||
if ($loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$loader->set_many($keyvaluearray);
|
||||
}
|
||||
$data = array();
|
||||
$definitionid = $this->get_definition()->get_ttl();
|
||||
$simulatettl = $this->has_a_ttl() && !$this->store_supports_native_ttl();
|
||||
foreach ($keyvaluearray as $key => $value) {
|
||||
if (is_object($value) && $value instanceof cacheable_object) {
|
||||
$value = new cache_cached_object($value);
|
||||
} else if (!$this->get_store()->supports_dereferencing_objects() && !is_scalar($value)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$value = $this->unref($value);
|
||||
}
|
||||
if ($simulatettl) {
|
||||
$value = new cache_ttl_wrapper($value, $definitionid);
|
||||
}
|
||||
$data[$key] = array(
|
||||
'key' => $this->parse_key($key),
|
||||
'value' => $value
|
||||
);
|
||||
}
|
||||
$successfullyset = $this->get_store()->set_many($data);
|
||||
if ($this->perfdebug && $successfullyset) {
|
||||
cache_helper::record_cache_set($this->get_store(), $this->get_definition(), $successfullyset,
|
||||
$this->get_store()->get_last_io_bytes());
|
||||
}
|
||||
return $successfullyset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the cache store, and loader if there is one.
|
||||
*
|
||||
* @return bool True on success, false otherwise
|
||||
*/
|
||||
public function purge() {
|
||||
$this->get_store()->purge();
|
||||
if ($this->get_loader()) {
|
||||
$this->get_loader()->purge();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test is a cache has a key.
|
||||
*
|
||||
* The use of the has methods is strongly discouraged. In a high load environment the cache may well change between the
|
||||
* test and any subsequent action (get, set, delete etc).
|
||||
* Instead it is recommended to write your code in such a way they it performs the following steps:
|
||||
* <ol>
|
||||
* <li>Attempt to retrieve the information.</li>
|
||||
* <li>Generate the information.</li>
|
||||
* <li>Attempt to set the information</li>
|
||||
* </ol>
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @param bool $tryloadifpossible If set to true, the cache doesn't contain the key, and there is another cache loader or
|
||||
* data source then the code will try load the key value from the next item in the chain.
|
||||
* @return bool True if the cache has the requested key, false otherwise.
|
||||
*/
|
||||
public function has($key, $tryloadifpossible = false) {
|
||||
$this->check_tracked_user();
|
||||
$parsedkey = $this->parse_key($key);
|
||||
$store = $this->get_store();
|
||||
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
|
||||
// The data has a TTL and the store doesn't support it natively.
|
||||
// We must fetch the data and expect a ttl wrapper.
|
||||
$data = $store->get($parsedkey);
|
||||
$has = ($data instanceof cache_ttl_wrapper && !$data->has_expired());
|
||||
} else if (!$this->store_supports_key_awareness()) {
|
||||
// The store doesn't support key awareness, get the data and check it manually... puke.
|
||||
// Either no TTL is set of the store supports its handling natively.
|
||||
$data = $store->get($parsedkey);
|
||||
$has = ($data !== false);
|
||||
} else {
|
||||
// The store supports key awareness, this is easy!
|
||||
// Either no TTL is set of the store supports its handling natively.
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$has = $store->has($parsedkey);
|
||||
}
|
||||
if (!$has && $tryloadifpossible) {
|
||||
$result = null;
|
||||
if ($this->get_loader() !== false) {
|
||||
$result = $this->get_loader()->get($parsedkey);
|
||||
} else if ($this->get_datasource() !== null) {
|
||||
$result = $this->get_datasource()->load_for_cache($key);
|
||||
}
|
||||
$has = ($result !== null);
|
||||
if ($has) {
|
||||
$this->set($key, $result);
|
||||
}
|
||||
}
|
||||
return $has;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test is a cache has all of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has all of the given keys, false otherwise.
|
||||
*/
|
||||
public function has_all(array $keys) {
|
||||
$this->check_tracked_user();
|
||||
if (($this->has_a_ttl() && !$this->store_supports_native_ttl()) || !$this->store_supports_key_awareness()) {
|
||||
foreach ($keys as $key) {
|
||||
if (!$this->has($key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// The cache must be key aware and if support native ttl if it a ttl is set.
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$store = $this->get_store();
|
||||
return $store->has_all(array_map(array($this, 'parse_key'), $keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a cache has at least one of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has at least one of the given keys
|
||||
*/
|
||||
public function has_any(array $keys) {
|
||||
if (($this->has_a_ttl() && !$this->store_supports_native_ttl()) || !$this->store_supports_key_awareness()) {
|
||||
foreach ($keys as $key) {
|
||||
if ($this->has($key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$store = $this->get_store();
|
||||
return $store->has_any(array_map(array($this, 'parse_key'), $keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* The session loader never uses static acceleration.
|
||||
* Instead it stores things in the static $session variable. Shared between all session loaders.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function use_static_acceleration() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An request cache.
|
||||
*
|
||||
* This class is used for request caches returned by the cache::make methods.
|
||||
*
|
||||
* This cache class should never be interacted with directly. Instead you should always use the cache::make methods.
|
||||
* It is technically possible to call those methods through this class however there is no guarantee that you will get an
|
||||
* instance of this class back again.
|
||||
*
|
||||
* @internal don't use me directly.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_request extends cache {
|
||||
// This comment appeases code pre-checker ;) !
|
||||
}
|
74
cache/classes/cache_lock_interface.php
vendored
Normal file
74
cache/classes/cache_lock_interface.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache lock interface
|
||||
*
|
||||
* This interface needs to be inherited by all cache lock plugins.
|
||||
*/
|
||||
interface cache_lock_interface {
|
||||
/**
|
||||
* Constructs an instance of the cache lock given its name and its configuration data
|
||||
*
|
||||
* @param string $name The unique name of the lock instance
|
||||
* @param array $configuration
|
||||
*/
|
||||
public function __construct($name, array $configuration = array());
|
||||
|
||||
/**
|
||||
* Acquires a lock on a given key.
|
||||
*
|
||||
* @param string $key The key to acquire a lock for.
|
||||
* @param string $ownerid An unique identifier for the owner of this lock. It is entirely optional for the cache lock plugin
|
||||
* to use this. Each implementation can decide for themselves.
|
||||
* @param bool $block If set to true the application will wait until a lock can be acquired
|
||||
* @return bool True if the lock can be acquired false otherwise.
|
||||
*/
|
||||
public function lock($key, $ownerid, $block = false);
|
||||
|
||||
/**
|
||||
* Releases the lock held on a certain key.
|
||||
*
|
||||
* @param string $key The key to release the lock for.
|
||||
* @param string $ownerid An unique identifier for the owner of this lock. It is entirely optional for the cache lock plugin
|
||||
* to use this. Each implementation can decide for themselves.
|
||||
* @param bool $forceunlock If set to true the lock will be removed if it exists regardless of whether or not we own it.
|
||||
*/
|
||||
public function unlock($key, $ownerid, $forceunlock = false);
|
||||
|
||||
/**
|
||||
* Checks the state of the given key.
|
||||
*
|
||||
* Returns true if the key is locked and belongs to the ownerid.
|
||||
* Returns false if the key is locked but does not belong to the ownerid.
|
||||
* Returns null if there is no lock
|
||||
*
|
||||
* @param string $key The key we are checking for.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* @return bool True if this code has the lock, false if there is a lock but this code doesn't have it, null if there
|
||||
* is no lock.
|
||||
*/
|
||||
public function check_state($key, $ownerid);
|
||||
|
||||
/**
|
||||
* Cleans up any left over locks.
|
||||
*
|
||||
* This function MUST clean up any locks that have been acquired and not released during processing.
|
||||
* Although the situation of acquiring a lock and not releasing it should be insanely rare we need to deal with it.
|
||||
* Things such as unfortunate timeouts etc could cause this situation.
|
||||
*/
|
||||
public function __destruct();
|
||||
}
|
92
cache/classes/cacheable_object_array.php
vendored
Normal file
92
cache/classes/cacheable_object_array.php
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* An array of cacheable objects.
|
||||
*
|
||||
* This class allows a developer to create an array of cacheable objects and store that.
|
||||
* The cache API doesn't check items within an array to see whether they are cacheable. Such a check would be very costly to both
|
||||
* arrays using cacheable object and those that don't.
|
||||
* Instead the developer must explicitly use a cacheable_object_array instance.
|
||||
*
|
||||
* The following is one example of how this class can be used.
|
||||
* <code>
|
||||
* $data = array();
|
||||
* $data[] = new cacheable_object('one');
|
||||
* $data[] = new cacheable_object('two');
|
||||
* $data[] = new cacheable_object('three');
|
||||
* $cache->set(new cacheable_object_array($data));
|
||||
* </code>
|
||||
* Another example would be
|
||||
* <code>
|
||||
* $data = new cacheable_object_array();
|
||||
* $data[] = new cacheable_object('one');
|
||||
* $data[] = new cacheable_object('two');
|
||||
* $data[] = new cacheable_object('three');
|
||||
* $cache->set($data);
|
||||
* </code>
|
||||
*
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cacheable_object_array extends ArrayObject implements cacheable_object {
|
||||
|
||||
/**
|
||||
* Constructs a new array object instance.
|
||||
* @param array $items
|
||||
*/
|
||||
final public function __construct(array $items = array()) {
|
||||
parent::__construct($items, ArrayObject::STD_PROP_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data to cache for this object.
|
||||
*
|
||||
* @return array An array of cache_cached_object instances.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
final public function prepare_to_cache() {
|
||||
$result = array();
|
||||
foreach ($this as $key => $value) {
|
||||
if ($value instanceof cacheable_object) {
|
||||
$value = new cache_cached_object($value);
|
||||
} else {
|
||||
throw new coding_exception('Only cacheable_object instances can be added to a cacheable_array');
|
||||
}
|
||||
$result[$key] = $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cacheable_object_array that was originally sent to the cache.
|
||||
*
|
||||
* @param array $data
|
||||
* @return cacheable_object_array
|
||||
* @throws coding_exception
|
||||
*/
|
||||
final public static function wake_from_cache($data) {
|
||||
if (!is_array($data)) {
|
||||
throw new coding_exception('Invalid data type when reviving cacheable_array data');
|
||||
}
|
||||
$result = array();
|
||||
foreach ($data as $key => $value) {
|
||||
$result[$key] = $value->restore_object();
|
||||
}
|
||||
$class = __CLASS__;
|
||||
return new $class($result);
|
||||
}
|
||||
}
|
43
cache/classes/cacheable_object_interface.php
vendored
Normal file
43
cache/classes/cacheable_object_interface.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cacheable object.
|
||||
*
|
||||
* This interface can be implemented by any class that is going to be passed into a cache and allows it to take control of the
|
||||
* structure and the information about to be cached, as well as how to deal with it when it is retrieved from a cache.
|
||||
* Think of it like serialisation and the __sleep and __wakeup methods.
|
||||
* This is used because cache stores are responsible for how they interact with data and what they do when storing it. This
|
||||
* interface ensures there is always a guaranteed action.
|
||||
*/
|
||||
interface cacheable_object {
|
||||
|
||||
/**
|
||||
* Prepares the object for caching. Works like the __sleep method.
|
||||
*
|
||||
* @return mixed The data to cache, can be anything except a class that implements the cacheable_object... that would
|
||||
* be dumb.
|
||||
*/
|
||||
public function prepare_to_cache();
|
||||
|
||||
/**
|
||||
* Takes the data provided by prepare_to_cache and reinitialises an instance of the associated from it.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return object The instance for the given data.
|
||||
*/
|
||||
public static function wake_from_cache($data);
|
||||
}
|
58
cache/classes/cached_object.php
vendored
Normal file
58
cache/classes/cached_object.php
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A cached object wrapper.
|
||||
*
|
||||
* This class gets used when the data is an object that has implemented the cacheable_object interface.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_cached_object {
|
||||
|
||||
/**
|
||||
* The class of the cacheable object
|
||||
* @var string
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* The data returned by the cacheable_object prepare_to_cache method.
|
||||
* @var mixed
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Constructs a cached object wrapper.
|
||||
* @param cacheable_object $obj
|
||||
*/
|
||||
public function __construct(cacheable_object $obj) {
|
||||
$this->class = get_class($obj);
|
||||
$this->data = $obj->prepare_to_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the data as an instance of the cacheable_object class.
|
||||
* @return object
|
||||
*/
|
||||
public function restore_object() {
|
||||
$class = $this->class;
|
||||
return $class::wake_from_cache($this->data);
|
||||
}
|
||||
}
|
20
cache/classes/config.php
vendored
20
cache/classes/config.php
vendored
@ -14,20 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache configuration reader
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Cache configuration reader.
|
||||
*
|
||||
@ -478,10 +464,10 @@ class cache_config {
|
||||
/**
|
||||
* Gets all of the stores that are to be used for the given definition.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return array
|
||||
* @param definition $definition
|
||||
* @return array<store>
|
||||
*/
|
||||
public function get_stores_for_definition(cache_definition $definition) {
|
||||
public function get_stores_for_definition(definition $definition) {
|
||||
// Check if MUC has been disabled.
|
||||
$factory = cache_factory::instance();
|
||||
if ($factory->stores_disabled()) {
|
||||
|
44
cache/classes/configurable_cache_interface.php
vendored
Normal file
44
cache/classes/configurable_cache_interface.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache store feature: configurable.
|
||||
*
|
||||
* This feature should be implemented by all cache stores that are configurable when adding an instance.
|
||||
* It requires the implementation of methods required to convert form data into the a configuration array for the
|
||||
* store instance, and then the reverse converting configuration data into an array that can be used to set the
|
||||
* data for the edit form.
|
||||
*
|
||||
* Can be implemented by classes already implementing cache_store.
|
||||
*/
|
||||
interface cache_is_configurable {
|
||||
|
||||
/**
|
||||
* Given the data from the add instance form this function creates a configuration array.
|
||||
*
|
||||
* @param stdClass $data
|
||||
* @return array
|
||||
*/
|
||||
public static function config_get_configuration_array($data);
|
||||
|
||||
/**
|
||||
* Allows the cache store to set its data against the edit form before it is shown to the user.
|
||||
*
|
||||
* @param moodleform $editform
|
||||
* @param array $config
|
||||
*/
|
||||
public static function config_set_edit_form_data(moodleform $editform, array $config);
|
||||
}
|
60
cache/classes/data_source_interface.php
vendored
Normal file
60
cache/classes/data_source_interface.php
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache Data Source.
|
||||
*
|
||||
* The cache data source interface can be implemented by any class within Moodle.
|
||||
* If implemented then the class can be reference in a cache definition and will be used to load information that cannot be
|
||||
* retrieved from the cache. As part of its retrieval that information will also be loaded into the cache.
|
||||
*
|
||||
* This allows developers to created a complete cache solution that can be used through code ensuring consistent cache
|
||||
* interaction and loading. Allowing them in turn to centralise code and help keeps things more easily maintainable.
|
||||
*
|
||||
* Can be implemented by any class.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface cache_data_source {
|
||||
|
||||
/**
|
||||
* Returns an instance of the data source class that the cache can use for loading data using the other methods
|
||||
* specified by this interface.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return object
|
||||
*/
|
||||
public static function get_instance_for_cache(cache_definition $definition);
|
||||
|
||||
/**
|
||||
* Loads the data for the key provided ready formatted for caching.
|
||||
*
|
||||
* @param string|int $key The key to load.
|
||||
* @return mixed What ever data should be returned, or false if it can't be loaded.
|
||||
*/
|
||||
public function load_for_cache($key);
|
||||
|
||||
/**
|
||||
* Loads several keys for the cache.
|
||||
*
|
||||
* @param array $keys An array of keys each of which will be string|int.
|
||||
* @return array An array of matching data items.
|
||||
*/
|
||||
public function load_many_for_cache(array $keys);
|
||||
}
|
39
cache/classes/exception/cache_exception.php
vendored
Normal file
39
cache/classes/exception/cache_exception.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A cache exception class. Just allows people to catch cache exceptions.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_exception extends moodle_exception {
|
||||
/**
|
||||
* Constructs a new exception
|
||||
*
|
||||
* @param string $errorcode
|
||||
* @param string $module
|
||||
* @param string $link
|
||||
* @param mixed $a
|
||||
* @param mixed $debuginfo
|
||||
*/
|
||||
public function __construct($errorcode, $module = 'cache', $link = '', $a = null, $debuginfo = null) {
|
||||
// This may appear like a useless override but you will notice that we have set a MUCH more useful default for $module.
|
||||
parent::__construct($errorcode, $module, $link, $a, $debuginfo);
|
||||
}
|
||||
}
|
14
cache/classes/factory.php
vendored
14
cache/classes/factory.php
vendored
@ -14,20 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file contains the cache factory class.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The cache factory class.
|
||||
*
|
||||
|
14
cache/classes/helper.php
vendored
14
cache/classes/helper.php
vendored
@ -14,20 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache helper class
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The cache helper class.
|
||||
*
|
||||
|
605
cache/classes/interfaces.php
vendored
605
cache/classes/interfaces.php
vendored
@ -1,605 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache API interfaces
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Cache Loader.
|
||||
*
|
||||
* This cache loader interface provides the required structure for classes that wish to be interacted with as a
|
||||
* means of accessing and interacting with a cache.
|
||||
*
|
||||
* Can be implemented by any class wishing to be a cache loader.
|
||||
*/
|
||||
interface cache_loader {
|
||||
|
||||
/**
|
||||
* Retrieves the value for the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @return mixed The data retrieved from the cache, or false if the key did not exist within the cache.
|
||||
* If MUST_EXIST was used then an exception will be thrown if the key does not exist within the cache.
|
||||
*/
|
||||
public function get($key, $strictness = IGNORE_MISSING);
|
||||
|
||||
/**
|
||||
* Retrieves the value and actual version for the given key, with at least the required version.
|
||||
*
|
||||
* If there is no value for the key, or there is a value but it doesn't have the required
|
||||
* version, then this function will return false (or throw an exception if you set strictness
|
||||
* to MUST_EXIST).
|
||||
*
|
||||
* This function can be used to make it easier to support localisable caches (where the cache
|
||||
* could be stored on a local server as well as a shared cache). Specifying the version means
|
||||
* that it will automatically retrieve the correct version if available, either from the local
|
||||
* server or [if that has an older version] from the shared server.
|
||||
*
|
||||
* If the cached version is newer than specified version, it will be returned regardless. For
|
||||
* example, if you request version 4, but the locally cached version is 5, it will be returned.
|
||||
* If you request version 6, and the locally cached version is 5, then the system will look in
|
||||
* higher-level caches (if any); if there still isn't a version 6 or greater, it will return
|
||||
* null.
|
||||
*
|
||||
* You must use this function if you use set_versioned.
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param int $requiredversion Minimum required version of the data
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @param mixed $actualversion If specified, will be set to the actual version number retrieved
|
||||
* @return mixed Data from the cache, or false if the key did not exist or was too old
|
||||
*/
|
||||
public function get_versioned($key, int $requiredversion, int $strictness = IGNORE_MISSING, &$actualversion = null);
|
||||
|
||||
/**
|
||||
* Retrieves an array of values for an array of keys.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache
|
||||
* store does support it, but you should be aware of this fact.
|
||||
*
|
||||
* @param array $keys The keys of the data being requested.
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @return array An array of key value pairs for the items that could be retrieved from the cache.
|
||||
* If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
|
||||
* Otherwise any key that did not exist will have a data value of false within the results.
|
||||
*/
|
||||
public function get_many(array $keys, $strictness = IGNORE_MISSING);
|
||||
|
||||
/**
|
||||
* Sends a key => value pair to the cache.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set('main', 'http://moodle.org');
|
||||
* $cache->set('docs', 'http://docs.moodle.org');
|
||||
* $cache->set('tracker', 'http://tracker.moodle.org');
|
||||
* $cache->set('qa', 'http://qa.moodle.net');
|
||||
* </code>
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @return bool True on success, false otherwise.
|
||||
*/
|
||||
public function set($key, $data);
|
||||
|
||||
/**
|
||||
* Sets the value for the given key with the given version.
|
||||
*
|
||||
* The cache does not store multiple versions - any existing version will be overwritten with
|
||||
* this one. This function should only be used if there is a known 'current version' (e.g.
|
||||
* stored in a database table). It only ensures that the cache does not return outdated data.
|
||||
*
|
||||
* This function can be used to help implement localisable caches (where the cache could be
|
||||
* stored on a local server as well as a shared cache). The version will be recorded alongside
|
||||
* the item and get_versioned will always return the correct version.
|
||||
*
|
||||
* The version number must be an integer that always increases. This could be based on the
|
||||
* current time, or a stored value that increases by 1 each time it changes, etc.
|
||||
*
|
||||
* If you use this function you must use get_versioned to retrieve the data.
|
||||
*
|
||||
* @param string|int $key The key for the data being set.
|
||||
* @param int $version Integer for the version of the data
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @return bool True on success, false otherwise.
|
||||
*/
|
||||
public function set_versioned($key, int $version, $data): bool;
|
||||
|
||||
/**
|
||||
* Sends several key => value pairs to the cache.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set_many(array(
|
||||
* 'main' => 'http://moodle.org',
|
||||
* 'docs' => 'http://docs.moodle.org',
|
||||
* 'tracker' => 'http://tracker.moodle.org',
|
||||
* 'qa' => ''http://qa.moodle.net'
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
* @param array $keyvaluearray An array of key => value pairs to send to the cache.
|
||||
* @return int The number of items successfully set. It is up to the developer to check this matches the number of items.
|
||||
* ... if they care that is.
|
||||
*/
|
||||
public function set_many(array $keyvaluearray);
|
||||
|
||||
/**
|
||||
* Test is a cache has a key.
|
||||
*
|
||||
* The use of the has methods is strongly discouraged. In a high load environment the cache may well change between the
|
||||
* test and any subsequent action (get, set, delete etc).
|
||||
* Instead it is recommended to write your code in such a way they it performs the following steps:
|
||||
* <ol>
|
||||
* <li>Attempt to retrieve the information.</li>
|
||||
* <li>Generate the information.</li>
|
||||
* <li>Attempt to set the information</li>
|
||||
* </ol>
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the cache has the requested key, false otherwise.
|
||||
*/
|
||||
public function has($key);
|
||||
|
||||
/**
|
||||
* Test if a cache has at least one of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has at least one of the given keys
|
||||
*/
|
||||
public function has_any(array $keys);
|
||||
|
||||
/**
|
||||
* Test is a cache has all of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has all of the given keys, false otherwise.
|
||||
*/
|
||||
public function has_all(array $keys);
|
||||
|
||||
/**
|
||||
* Delete the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return bool True of success, false otherwise.
|
||||
*/
|
||||
public function delete($key, $recurse = true);
|
||||
|
||||
/**
|
||||
* Delete all of the given keys from the cache.
|
||||
*
|
||||
* @param array $keys The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
public function delete_many(array $keys, $recurse = true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache Loader supporting locking.
|
||||
*
|
||||
* This interface should be given to classes already implementing cache_loader that also wish to support locking.
|
||||
* It outlines the required structure for utilising locking functionality when using a cache.
|
||||
*
|
||||
* Can be implemented by any class already implementing the cache_loader interface.
|
||||
*/
|
||||
interface cache_loader_with_locking {
|
||||
|
||||
/**
|
||||
* Acquires a lock for the given key.
|
||||
*
|
||||
* Please note that this happens automatically if the cache definition requires locking.
|
||||
* it is still made a public method so that adhoc caches can use it if they choose.
|
||||
* However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
|
||||
* locks are acquired, checked, and released.
|
||||
*
|
||||
* Prior to Moodle 4,3 this function used to return false if the lock cannot be obtained. It
|
||||
* now always returns true, and throws an exception if the lock cannot be obtained.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool Always returns true (for backwards compatibility)
|
||||
* @throws moodle_exception If the lock cannot be obtained after a timeout
|
||||
*/
|
||||
public function acquire_lock($key);
|
||||
|
||||
/**
|
||||
* Checks if the cache loader owns the lock for the given key.
|
||||
*
|
||||
* Please note that this happens automatically if the cache definition requires locking.
|
||||
* it is still made a public method so that adhoc caches can use it if they choose.
|
||||
* However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
|
||||
* locks are acquired, checked, and released.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if this code has the lock, false if there is a lock but this code doesn't have it,
|
||||
* null if there is no lock.
|
||||
*/
|
||||
public function check_lock_state($key);
|
||||
|
||||
/**
|
||||
* Releases the lock for the given key.
|
||||
*
|
||||
* Please note that this happens automatically if the cache definition requires locking.
|
||||
* it is still made a public method so that adhoc caches can use it if they choose.
|
||||
* However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
|
||||
* locks are acquired, checked, and released.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the lock has been released, false if there was a problem releasing the lock.
|
||||
*/
|
||||
public function release_lock($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache store feature: locking
|
||||
*
|
||||
* This is a feature that cache stores can implement if they wish to support locking themselves rather
|
||||
* than having the cache loader handle it for them.
|
||||
*
|
||||
* Can be implemented by classes already implementing cache_store.
|
||||
*/
|
||||
interface cache_is_lockable {
|
||||
|
||||
/**
|
||||
* Acquires a lock on the given key for the given identifier.
|
||||
*
|
||||
* @param string $key The key we are locking.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* The use of this property is entirely optional and implementations can act as they like upon it.
|
||||
* @return bool True if the lock could be acquired, false otherwise.
|
||||
*/
|
||||
public function acquire_lock($key, $ownerid);
|
||||
|
||||
/**
|
||||
* Test if there is already a lock for the given key and if there is whether it belongs to the calling code.
|
||||
*
|
||||
* @param string $key The key we are locking.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* @return bool True if this code has the lock, false if there is a lock but this code doesn't have it, null if there
|
||||
* is no lock.
|
||||
*/
|
||||
public function check_lock_state($key, $ownerid);
|
||||
|
||||
/**
|
||||
* Releases the lock on the given key.
|
||||
*
|
||||
* @param string $key The key we are locking.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* The use of this property is entirely optional and implementations can act as they like upon it.
|
||||
* @return bool True if the lock has been released, false if there was a problem releasing the lock.
|
||||
*/
|
||||
public function release_lock($key, $ownerid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache store feature: key awareness.
|
||||
*
|
||||
* This is a feature that cache stores and cache loaders can both choose to implement.
|
||||
* If a cache store implements this then it will be made responsible for tests for items within the cache.
|
||||
* If the cache store being used doesn't implement this then it will be the responsibility of the cache loader to use the
|
||||
* equivalent get methods to mimick the functionality of these tests.
|
||||
*
|
||||
* Cache stores should only override these methods if they natively support such features or if they have a better performing
|
||||
* means of performing these tests than the handling that would otherwise take place in the cache_loader.
|
||||
*
|
||||
* Can be implemented by classes already implementing cache_store.
|
||||
*/
|
||||
interface cache_is_key_aware {
|
||||
|
||||
/**
|
||||
* Test is a cache has a key.
|
||||
*
|
||||
* The use of the has methods is strongly discouraged. In a high load environment the cache may well change between the
|
||||
* test and any subsequent action (get, set, delete etc).
|
||||
* Instead it is recommended to write your code in such a way they it performs the following steps:
|
||||
* <ol>
|
||||
* <li>Attempt to retrieve the information.</li>
|
||||
* <li>Generate the information.</li>
|
||||
* <li>Attempt to set the information</li>
|
||||
* </ol>
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the cache has the requested key, false otherwise.
|
||||
*/
|
||||
public function has($key);
|
||||
|
||||
/**
|
||||
* Test if a cache has at least one of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has at least one of the given keys
|
||||
*/
|
||||
public function has_any(array $keys);
|
||||
|
||||
/**
|
||||
* Test is a cache has all of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has all of the given keys, false otherwise.
|
||||
*/
|
||||
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 Moodle 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.
|
||||
* It requires the implementation of methods required to convert form data into the a configuration array for the
|
||||
* store instance, and then the reverse converting configuration data into an array that can be used to set the
|
||||
* data for the edit form.
|
||||
*
|
||||
* Can be implemented by classes already implementing cache_store.
|
||||
*/
|
||||
interface cache_is_configurable {
|
||||
|
||||
/**
|
||||
* Given the data from the add instance form this function creates a configuration array.
|
||||
*
|
||||
* @param stdClass $data
|
||||
* @return array
|
||||
*/
|
||||
public static function config_get_configuration_array($data);
|
||||
|
||||
/**
|
||||
* Allows the cache store to set its data against the edit form before it is shown to the user.
|
||||
*
|
||||
* @param moodleform $editform
|
||||
* @param array $config
|
||||
*/
|
||||
public static function config_set_edit_form_data(moodleform $editform, array $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache Data Source.
|
||||
*
|
||||
* The cache data source interface can be implemented by any class within Moodle.
|
||||
* If implemented then the class can be reference in a cache definition and will be used to load information that cannot be
|
||||
* retrieved from the cache. As part of its retrieval that information will also be loaded into the cache.
|
||||
*
|
||||
* This allows developers to created a complete cache solution that can be used through code ensuring consistent cache
|
||||
* interaction and loading. Allowing them in turn to centralise code and help keeps things more easily maintainable.
|
||||
*
|
||||
* Can be implemented by any class.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface cache_data_source {
|
||||
|
||||
/**
|
||||
* Returns an instance of the data source class that the cache can use for loading data using the other methods
|
||||
* specified by this interface.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return object
|
||||
*/
|
||||
public static function get_instance_for_cache(cache_definition $definition);
|
||||
|
||||
/**
|
||||
* Loads the data for the key provided ready formatted for caching.
|
||||
*
|
||||
* @param string|int $key The key to load.
|
||||
* @return mixed What ever data should be returned, or false if it can't be loaded.
|
||||
*/
|
||||
public function load_for_cache($key);
|
||||
|
||||
/**
|
||||
* Loads several keys for the cache.
|
||||
*
|
||||
* @param array $keys An array of keys each of which will be string|int.
|
||||
* @return array An array of matching data items.
|
||||
*/
|
||||
public function load_many_for_cache(array $keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Versionable cache data source.
|
||||
*
|
||||
* This interface extends the main cache data source interface to add an extra required method if
|
||||
* the data source is to be used for a versioned cache.
|
||||
*
|
||||
* @package core_cache
|
||||
*/
|
||||
interface cache_data_source_versionable extends cache_data_source {
|
||||
/**
|
||||
* Loads the data for the key provided ready formatted for caching.
|
||||
*
|
||||
* If there is no data for that key, or if the data for the required key has an older version
|
||||
* than the specified $requiredversion, then this returns null.
|
||||
*
|
||||
* If there is data then $actualversion should be set to the actual version number retrieved
|
||||
* (may be the same as $requiredversion or newer).
|
||||
*
|
||||
* @param string|int $key The key to load.
|
||||
* @param int $requiredversion Minimum required version
|
||||
* @param mixed $actualversion Should be set to the actual version number retrieved
|
||||
* @return mixed What ever data should be returned, or false if it can't be loaded.
|
||||
*/
|
||||
public function load_for_cache_versioned($key, int $requiredversion, &$actualversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cacheable object.
|
||||
*
|
||||
* This interface can be implemented by any class that is going to be passed into a cache and allows it to take control of the
|
||||
* structure and the information about to be cached, as well as how to deal with it when it is retrieved from a cache.
|
||||
* Think of it like serialisation and the __sleep and __wakeup methods.
|
||||
* This is used because cache stores are responsible for how they interact with data and what they do when storing it. This
|
||||
* interface ensures there is always a guaranteed action.
|
||||
*/
|
||||
interface cacheable_object {
|
||||
|
||||
/**
|
||||
* Prepares the object for caching. Works like the __sleep method.
|
||||
*
|
||||
* @return mixed The data to cache, can be anything except a class that implements the cacheable_object... that would
|
||||
* be dumb.
|
||||
*/
|
||||
public function prepare_to_cache();
|
||||
|
||||
/**
|
||||
* Takes the data provided by prepare_to_cache and reinitialises an instance of the associated from it.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return object The instance for the given data.
|
||||
*/
|
||||
public static function wake_from_cache($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache lock interface
|
||||
*
|
||||
* This interface needs to be inherited by all cache lock plugins.
|
||||
*/
|
||||
interface cache_lock_interface {
|
||||
/**
|
||||
* Constructs an instance of the cache lock given its name and its configuration data
|
||||
*
|
||||
* @param string $name The unique name of the lock instance
|
||||
* @param array $configuration
|
||||
*/
|
||||
public function __construct($name, array $configuration = array());
|
||||
|
||||
/**
|
||||
* Acquires a lock on a given key.
|
||||
*
|
||||
* @param string $key The key to acquire a lock for.
|
||||
* @param string $ownerid An unique identifier for the owner of this lock. It is entirely optional for the cache lock plugin
|
||||
* to use this. Each implementation can decide for themselves.
|
||||
* @param bool $block If set to true the application will wait until a lock can be acquired
|
||||
* @return bool True if the lock can be acquired false otherwise.
|
||||
*/
|
||||
public function lock($key, $ownerid, $block = false);
|
||||
|
||||
/**
|
||||
* Releases the lock held on a certain key.
|
||||
*
|
||||
* @param string $key The key to release the lock for.
|
||||
* @param string $ownerid An unique identifier for the owner of this lock. It is entirely optional for the cache lock plugin
|
||||
* to use this. Each implementation can decide for themselves.
|
||||
* @param bool $forceunlock If set to true the lock will be removed if it exists regardless of whether or not we own it.
|
||||
*/
|
||||
public function unlock($key, $ownerid, $forceunlock = false);
|
||||
|
||||
/**
|
||||
* Checks the state of the given key.
|
||||
*
|
||||
* Returns true if the key is locked and belongs to the ownerid.
|
||||
* Returns false if the key is locked but does not belong to the ownerid.
|
||||
* Returns null if there is no lock
|
||||
*
|
||||
* @param string $key The key we are checking for.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* @return bool True if this code has the lock, false if there is a lock but this code doesn't have it, null if there
|
||||
* is no lock.
|
||||
*/
|
||||
public function check_state($key, $ownerid);
|
||||
|
||||
/**
|
||||
* Cleans up any left over locks.
|
||||
*
|
||||
* This function MUST clean up any locks that have been acquired and not released during processing.
|
||||
* Although the situation of acquiring a lock and not releasing it should be insanely rare we need to deal with it.
|
||||
* Things such as unfortunate timeouts etc could cause this situation.
|
||||
*/
|
||||
public function __destruct();
|
||||
}
|
82
cache/classes/key_aware_cache_interface.php
vendored
Normal file
82
cache/classes/key_aware_cache_interface.php
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache store feature: key awareness.
|
||||
*
|
||||
* This is a feature that cache stores and cache loaders can both choose to implement.
|
||||
* If a cache store implements this then it will be made responsible for tests for items within the cache.
|
||||
* If the cache store being used doesn't implement this then it will be the responsibility of the cache loader to use the
|
||||
* equivalent get methods to mimick the functionality of these tests.
|
||||
*
|
||||
* Cache stores should only override these methods if they natively support such features or if they have a better performing
|
||||
* means of performing these tests than the handling that would otherwise take place in the cache_loader.
|
||||
*
|
||||
* Can be implemented by classes already implementing cache_store.
|
||||
*/
|
||||
interface cache_is_key_aware {
|
||||
|
||||
/**
|
||||
* Test is a cache has a key.
|
||||
*
|
||||
* The use of the has methods is strongly discouraged. In a high load environment the cache may well change between the
|
||||
* test and any subsequent action (get, set, delete etc).
|
||||
* Instead it is recommended to write your code in such a way they it performs the following steps:
|
||||
* <ol>
|
||||
* <li>Attempt to retrieve the information.</li>
|
||||
* <li>Generate the information.</li>
|
||||
* <li>Attempt to set the information</li>
|
||||
* </ol>
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the cache has the requested key, false otherwise.
|
||||
*/
|
||||
public function has($key);
|
||||
|
||||
/**
|
||||
* Test if a cache has at least one of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has at least one of the given keys
|
||||
*/
|
||||
public function has_any(array $keys);
|
||||
|
||||
/**
|
||||
* Test is a cache has all of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has all of the given keys, false otherwise.
|
||||
*/
|
||||
public function has_all(array $keys);
|
||||
}
|
217
cache/classes/loader_interface.php
vendored
Normal file
217
cache/classes/loader_interface.php
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache Loader.
|
||||
*
|
||||
* This cache loader interface provides the required structure for classes that wish to be interacted with as a
|
||||
* means of accessing and interacting with a cache.
|
||||
*
|
||||
* Can be implemented by any class wishing to be a cache loader.
|
||||
*/
|
||||
interface cache_loader {
|
||||
|
||||
/**
|
||||
* Retrieves the value for the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @return mixed The data retrieved from the cache, or false if the key did not exist within the cache.
|
||||
* If MUST_EXIST was used then an exception will be thrown if the key does not exist within the cache.
|
||||
*/
|
||||
public function get($key, $strictness = IGNORE_MISSING);
|
||||
|
||||
/**
|
||||
* Retrieves the value and actual version for the given key, with at least the required version.
|
||||
*
|
||||
* If there is no value for the key, or there is a value but it doesn't have the required
|
||||
* version, then this function will return false (or throw an exception if you set strictness
|
||||
* to MUST_EXIST).
|
||||
*
|
||||
* This function can be used to make it easier to support localisable caches (where the cache
|
||||
* could be stored on a local server as well as a shared cache). Specifying the version means
|
||||
* that it will automatically retrieve the correct version if available, either from the local
|
||||
* server or [if that has an older version] from the shared server.
|
||||
*
|
||||
* If the cached version is newer than specified version, it will be returned regardless. For
|
||||
* example, if you request version 4, but the locally cached version is 5, it will be returned.
|
||||
* If you request version 6, and the locally cached version is 5, then the system will look in
|
||||
* higher-level caches (if any); if there still isn't a version 6 or greater, it will return
|
||||
* null.
|
||||
*
|
||||
* You must use this function if you use set_versioned.
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param int $requiredversion Minimum required version of the data
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @param mixed $actualversion If specified, will be set to the actual version number retrieved
|
||||
* @return mixed Data from the cache, or false if the key did not exist or was too old
|
||||
*/
|
||||
public function get_versioned($key, int $requiredversion, int $strictness = IGNORE_MISSING, &$actualversion = null);
|
||||
|
||||
/**
|
||||
* Retrieves an array of values for an array of keys.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache
|
||||
* store does support it, but you should be aware of this fact.
|
||||
*
|
||||
* @param array $keys The keys of the data being requested.
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @return array An array of key value pairs for the items that could be retrieved from the cache.
|
||||
* If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
|
||||
* Otherwise any key that did not exist will have a data value of false within the results.
|
||||
*/
|
||||
public function get_many(array $keys, $strictness = IGNORE_MISSING);
|
||||
|
||||
/**
|
||||
* Sends a key => value pair to the cache.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set('main', 'http://moodle.org');
|
||||
* $cache->set('docs', 'http://docs.moodle.org');
|
||||
* $cache->set('tracker', 'http://tracker.moodle.org');
|
||||
* $cache->set('qa', 'http://qa.moodle.net');
|
||||
* </code>
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @return bool True on success, false otherwise.
|
||||
*/
|
||||
public function set($key, $data);
|
||||
|
||||
/**
|
||||
* Sets the value for the given key with the given version.
|
||||
*
|
||||
* The cache does not store multiple versions - any existing version will be overwritten with
|
||||
* this one. This function should only be used if there is a known 'current version' (e.g.
|
||||
* stored in a database table). It only ensures that the cache does not return outdated data.
|
||||
*
|
||||
* This function can be used to help implement localisable caches (where the cache could be
|
||||
* stored on a local server as well as a shared cache). The version will be recorded alongside
|
||||
* the item and get_versioned will always return the correct version.
|
||||
*
|
||||
* The version number must be an integer that always increases. This could be based on the
|
||||
* current time, or a stored value that increases by 1 each time it changes, etc.
|
||||
*
|
||||
* If you use this function you must use get_versioned to retrieve the data.
|
||||
*
|
||||
* @param string|int $key The key for the data being set.
|
||||
* @param int $version Integer for the version of the data
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @return bool True on success, false otherwise.
|
||||
*/
|
||||
public function set_versioned($key, int $version, $data): bool;
|
||||
|
||||
/**
|
||||
* Sends several key => value pairs to the cache.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set_many(array(
|
||||
* 'main' => 'http://moodle.org',
|
||||
* 'docs' => 'http://docs.moodle.org',
|
||||
* 'tracker' => 'http://tracker.moodle.org',
|
||||
* 'qa' => ''http://qa.moodle.net'
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
* @param array $keyvaluearray An array of key => value pairs to send to the cache.
|
||||
* @return int The number of items successfully set. It is up to the developer to check this matches the number of items.
|
||||
* ... if they care that is.
|
||||
*/
|
||||
public function set_many(array $keyvaluearray);
|
||||
|
||||
/**
|
||||
* Test is a cache has a key.
|
||||
*
|
||||
* The use of the has methods is strongly discouraged. In a high load environment the cache may well change between the
|
||||
* test and any subsequent action (get, set, delete etc).
|
||||
* Instead it is recommended to write your code in such a way they it performs the following steps:
|
||||
* <ol>
|
||||
* <li>Attempt to retrieve the information.</li>
|
||||
* <li>Generate the information.</li>
|
||||
* <li>Attempt to set the information</li>
|
||||
* </ol>
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the cache has the requested key, false otherwise.
|
||||
*/
|
||||
public function has($key);
|
||||
|
||||
/**
|
||||
* Test if a cache has at least one of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has at least one of the given keys
|
||||
*/
|
||||
public function has_any(array $keys);
|
||||
|
||||
/**
|
||||
* Test is a cache has all of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has all of the given keys, false otherwise.
|
||||
*/
|
||||
public function has_all(array $keys);
|
||||
|
||||
/**
|
||||
* Delete the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return bool True of success, false otherwise.
|
||||
*/
|
||||
public function delete($key, $recurse = true);
|
||||
|
||||
/**
|
||||
* Delete all of the given keys from the cache.
|
||||
*
|
||||
* @param array $keys The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
public function delete_many(array $keys, $recurse = true);
|
||||
}
|
69
cache/classes/loader_with_locking_interface.php
vendored
Normal file
69
cache/classes/loader_with_locking_interface.php
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache Loader supporting locking.
|
||||
*
|
||||
* This interface should be given to classes already implementing cache_loader that also wish to support locking.
|
||||
* It outlines the required structure for utilising locking functionality when using a cache.
|
||||
*
|
||||
* Can be implemented by any class already implementing the cache_loader interface.
|
||||
*/
|
||||
interface cache_loader_with_locking {
|
||||
/**
|
||||
* Acquires a lock for the given key.
|
||||
*
|
||||
* Please note that this happens automatically if the cache definition requires locking.
|
||||
* it is still made a public method so that adhoc caches can use it if they choose.
|
||||
* However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
|
||||
* locks are acquired, checked, and released.
|
||||
*
|
||||
* Prior to Moodle 4,3 this function used to return false if the lock cannot be obtained. It
|
||||
* now always returns true, and throws an exception if the lock cannot be obtained.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool Always returns true (for backwards compatibility)
|
||||
* @throws moodle_exception If the lock cannot be obtained after a timeout
|
||||
*/
|
||||
public function acquire_lock($key);
|
||||
|
||||
/**
|
||||
* Checks if the cache loader owns the lock for the given key.
|
||||
*
|
||||
* Please note that this happens automatically if the cache definition requires locking.
|
||||
* it is still made a public method so that adhoc caches can use it if they choose.
|
||||
* However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
|
||||
* locks are acquired, checked, and released.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if this code has the lock, false if there is a lock but this code doesn't have it,
|
||||
* null if there is no lock.
|
||||
*/
|
||||
public function check_lock_state($key);
|
||||
|
||||
/**
|
||||
* Releases the lock for the given key.
|
||||
*
|
||||
* Please note that this happens automatically if the cache definition requires locking.
|
||||
* it is still made a public method so that adhoc caches can use it if they choose.
|
||||
* However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
|
||||
* locks are acquired, checked, and released.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @return bool True if the lock has been released, false if there was a problem releasing the lock.
|
||||
*/
|
||||
public function release_lock($key);
|
||||
}
|
56
cache/classes/lockable_cache_interface.php
vendored
Normal file
56
cache/classes/lockable_cache_interface.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache store feature: locking
|
||||
*
|
||||
* This is a feature that cache stores can implement if they wish to support locking themselves rather
|
||||
* than having the cache loader handle it for them.
|
||||
*
|
||||
* Can be implemented by classes already implementing cache_store.
|
||||
*/
|
||||
interface cache_is_lockable {
|
||||
|
||||
/**
|
||||
* Acquires a lock on the given key for the given identifier.
|
||||
*
|
||||
* @param string $key The key we are locking.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* The use of this property is entirely optional and implementations can act as they like upon it.
|
||||
* @return bool True if the lock could be acquired, false otherwise.
|
||||
*/
|
||||
public function acquire_lock($key, $ownerid);
|
||||
|
||||
/**
|
||||
* Test if there is already a lock for the given key and if there is whether it belongs to the calling code.
|
||||
*
|
||||
* @param string $key The key we are locking.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* @return bool True if this code has the lock, false if there is a lock but this code doesn't have it, null if there
|
||||
* is no lock.
|
||||
*/
|
||||
public function check_lock_state($key, $ownerid);
|
||||
|
||||
/**
|
||||
* Releases the lock on the given key.
|
||||
*
|
||||
* @param string $key The key we are locking.
|
||||
* @param string $ownerid The identifier so we can check if we have the lock or if it is someone else.
|
||||
* The use of this property is entirely optional and implementations can act as they like upon it.
|
||||
* @return bool True if the lock has been released, false if there was a problem releasing the lock.
|
||||
*/
|
||||
public function release_lock($key, $ownerid);
|
||||
}
|
35
cache/classes/request_cache.php
vendored
Normal file
35
cache/classes/request_cache.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* An request cache.
|
||||
*
|
||||
* This class is used for request caches returned by the cache::make methods.
|
||||
*
|
||||
* This cache class should never be interacted with directly. Instead you should always use the cache::make methods.
|
||||
* It is technically possible to call those methods through this class however there is no guarantee that you will get an
|
||||
* instance of this class back again.
|
||||
*
|
||||
* @internal don't use me directly.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_request extends cache {
|
||||
// This comment appeases code pre-checker ;) !
|
||||
}
|
39
cache/classes/searchable_cache_interface.php
vendored
Normal file
39
cache/classes/searchable_cache_interface.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* 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 Moodle 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);
|
||||
}
|
576
cache/classes/session_cache.php
vendored
Normal file
576
cache/classes/session_cache.php
vendored
Normal file
@ -0,0 +1,576 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A session cache.
|
||||
*
|
||||
* This class is used for session caches returned by the cache::make methods.
|
||||
*
|
||||
* It differs from the application loader in a couple of noteable ways:
|
||||
* 1. Sessions are always expected to exist.
|
||||
* Because of this we don't ever use the static acceleration array.
|
||||
* 2. Session data for a loader instance (store + definition) is consolidate into a
|
||||
* single array for storage within the store.
|
||||
* Along with this we embed a lastaccessed time with the data. This way we can
|
||||
* check sessions for a last access time.
|
||||
* 3. Session stores are required to support key searching and must
|
||||
* implement cache_is_searchable. This ensures stores used for the cache can be
|
||||
* targetted for garbage collection of session data.
|
||||
*
|
||||
* This cache class should never be interacted with directly. Instead you should always use the cache::make methods.
|
||||
* It is technically possible to call those methods through this class however there is no guarantee that you will get an
|
||||
* instance of this class back again.
|
||||
*
|
||||
* @todo we should support locking in the session as well. Should be pretty simple to set up.
|
||||
*
|
||||
* @internal don't use me directly.
|
||||
* @method cache_store|cache_is_searchable get_store() Returns the cache store which must implement both cache_is_searchable.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_session extends cache {
|
||||
/**
|
||||
* The user the session has been established for.
|
||||
* @var int
|
||||
*/
|
||||
protected static $loadeduserid = null;
|
||||
|
||||
/**
|
||||
* The userid this cache is currently using.
|
||||
* @var int
|
||||
*/
|
||||
protected $currentuserid = null;
|
||||
|
||||
/**
|
||||
* The session id we are currently using.
|
||||
* @var array
|
||||
*/
|
||||
protected $sessionid = null;
|
||||
|
||||
/**
|
||||
* The session data for the above session id.
|
||||
* @var array
|
||||
*/
|
||||
protected $session = null;
|
||||
|
||||
/**
|
||||
* Constant used to prefix keys.
|
||||
*/
|
||||
const KEY_PREFIX = 'sess_';
|
||||
|
||||
/**
|
||||
* This is the key used to track last access.
|
||||
*/
|
||||
const LASTACCESS = '__lastaccess__';
|
||||
|
||||
/**
|
||||
* Override the cache::construct method.
|
||||
*
|
||||
* This function gets overriden so that we can process any invalidation events if need be.
|
||||
* If the definition doesn't have any invalidation events then this occurs exactly as it would for the cache class.
|
||||
* Otherwise we look at the last invalidation time and then check the invalidation data for events that have occured
|
||||
* between then now.
|
||||
*
|
||||
* You should not call this method from your code, instead you should use the cache::make methods.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @param cache_store $store
|
||||
* @param cache_loader|cache_data_source $loader
|
||||
*/
|
||||
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
|
||||
// First up copy the loadeduserid to the current user id.
|
||||
$this->currentuserid = self::$loadeduserid;
|
||||
$this->set_session_id();
|
||||
parent::__construct($definition, $store, $loader);
|
||||
|
||||
// This will trigger check tracked user. If this gets removed a call to that will need to be added here in its place.
|
||||
$this->set(self::LASTACCESS, cache::now());
|
||||
|
||||
$this->handle_invalidation_events();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session id for the loader.
|
||||
*/
|
||||
protected function set_session_id() {
|
||||
$this->sessionid = preg_replace('#[^a-zA-Z0-9_]#', '_', session_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix used for all keys.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_key_prefix() {
|
||||
return 'u'.$this->currentuserid.'_'.$this->sessionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the key turning it into a string (or array is required) suitable to be passed to the cache store.
|
||||
*
|
||||
* This function is called for every operation that uses keys. For this reason we use this function to also check
|
||||
* that the current user is the same as the user who last used this cache.
|
||||
*
|
||||
* On top of that if prepends the string 'sess_' to the start of all keys. The _ ensures things are easily identifiable.
|
||||
*
|
||||
* @param string|int $key As passed to get|set|delete etc.
|
||||
* @return string|array String unless the store supports multi-identifiers in which case an array if returned.
|
||||
*/
|
||||
protected function parse_key($key) {
|
||||
$prefix = $this->get_key_prefix();
|
||||
if ($key === self::LASTACCESS) {
|
||||
return $key.$prefix;
|
||||
}
|
||||
return $prefix.'_'.parent::parse_key($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that this cache instance is tracking the current user.
|
||||
*/
|
||||
protected function check_tracked_user() {
|
||||
if (isset($_SESSION['USER']->id) && $_SESSION['USER']->id !== null) {
|
||||
// Get the id of the current user.
|
||||
$new = $_SESSION['USER']->id;
|
||||
} else {
|
||||
// No user set up yet.
|
||||
$new = 0;
|
||||
}
|
||||
if ($new !== self::$loadeduserid) {
|
||||
// The current user doesn't match the tracked userid for this request.
|
||||
if (!is_null(self::$loadeduserid)) {
|
||||
// Purge the data we have for the old user.
|
||||
// This way we don't bloat the session.
|
||||
$this->purge();
|
||||
}
|
||||
self::$loadeduserid = $new;
|
||||
$this->currentuserid = $new;
|
||||
} else if ($new !== $this->currentuserid) {
|
||||
// The current user matches the loaded user but not the user last used by this cache.
|
||||
$this->purge_current_user();
|
||||
$this->currentuserid = $new;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the session cache of all data belonging to the current user.
|
||||
*/
|
||||
public function purge_current_user() {
|
||||
$keys = $this->get_store()->find_by_prefix($this->get_key_prefix());
|
||||
$this->get_store()->delete_many($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value for the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* It can be any structure although using a scalar string or int is recommended in the interests of performance.
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param int $requiredversion Minimum required version of the data or cache::VERSION_NONE
|
||||
* @param int $strictness One of IGNORE_MISSING | MUST_EXIST
|
||||
* @param mixed &$actualversion If specified, will be set to the actual version number retrieved
|
||||
* @return mixed|false The data from the cache or false if the key did not exist within the cache.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
protected function get_implementation($key, int $requiredversion, int $strictness, &$actualversion = null) {
|
||||
// Check the tracked user.
|
||||
$this->check_tracked_user();
|
||||
|
||||
// Use parent code.
|
||||
return parent::get_implementation($key, $requiredversion, $strictness, $actualversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a key => value pair to the cache.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set('main', 'http://moodle.org');
|
||||
* $cache->set('docs', 'http://docs.moodle.org');
|
||||
* $cache->set('tracker', 'http://tracker.moodle.org');
|
||||
* $cache->set('qa', 'http://qa.moodle.net');
|
||||
* </code>
|
||||
*
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* It can be any structure although using a scalar string or int is recommended in the interests of performance.
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param mixed $data The data to set against the key.
|
||||
* @return bool True on success, false otherwise.
|
||||
*/
|
||||
public function set($key, $data) {
|
||||
$this->check_tracked_user();
|
||||
$loader = $this->get_loader();
|
||||
if ($loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$loader->set($key, $data);
|
||||
}
|
||||
if (is_object($data) && $data instanceof cacheable_object) {
|
||||
$data = new cache_cached_object($data);
|
||||
} else if (!$this->get_store()->supports_dereferencing_objects() && !is_scalar($data)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$data = $this->unref($data);
|
||||
}
|
||||
// We dont' support native TTL here as we consolidate data for sessions.
|
||||
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
|
||||
$data = new cache_ttl_wrapper($data, $this->get_definition()->get_ttl());
|
||||
}
|
||||
$success = $this->get_store()->set($this->parse_key($key), $data);
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_set($this->get_store(), $this->get_definition(), 1,
|
||||
$this->get_store()->get_last_io_bytes());
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given key from the cache.
|
||||
*
|
||||
* @param string|int $key The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return bool True of success, false otherwise.
|
||||
*/
|
||||
public function delete($key, $recurse = true) {
|
||||
$parsedkey = $this->parse_key($key);
|
||||
if ($recurse && $this->get_loader() !== false) {
|
||||
// Delete from the bottom of the stack first.
|
||||
$this->get_loader()->delete($key, $recurse);
|
||||
}
|
||||
return $this->get_store()->delete($parsedkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array of values for an array of keys.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* @param array $keys The keys of the data being requested.
|
||||
* Each key can be any structure although using a scalar string or int is recommended in the interests of performance.
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
|
||||
* @return array An array of key value pairs for the items that could be retrieved from the cache.
|
||||
* If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
|
||||
* Otherwise any key that did not exist will have a data value of false within the results.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get_many(array $keys, $strictness = IGNORE_MISSING) {
|
||||
$this->check_tracked_user();
|
||||
$parsedkeys = array();
|
||||
$keymap = array();
|
||||
foreach ($keys as $key) {
|
||||
$parsedkey = $this->parse_key($key);
|
||||
$parsedkeys[$key] = $parsedkey;
|
||||
$keymap[$parsedkey] = $key;
|
||||
}
|
||||
$result = $this->get_store()->get_many($parsedkeys);
|
||||
if ($this->perfdebug) {
|
||||
$readbytes = $this->get_store()->get_last_io_bytes();
|
||||
}
|
||||
$return = array();
|
||||
$missingkeys = array();
|
||||
$hasmissingkeys = false;
|
||||
foreach ($result as $parsedkey => $value) {
|
||||
$key = $keymap[$parsedkey];
|
||||
if ($value instanceof cache_ttl_wrapper) {
|
||||
/* @var cache_ttl_wrapper $value */
|
||||
if ($value->has_expired()) {
|
||||
$this->delete($keymap[$parsedkey]);
|
||||
$value = false;
|
||||
} else {
|
||||
$value = $value->data;
|
||||
}
|
||||
}
|
||||
if ($value instanceof cache_cached_object) {
|
||||
/* @var cache_cached_object $value */
|
||||
$value = $value->restore_object();
|
||||
} else if (!$this->get_store()->supports_dereferencing_objects() && !is_scalar($value)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$value = $this->unref($value);
|
||||
}
|
||||
$return[$key] = $value;
|
||||
if ($value === false) {
|
||||
$hasmissingkeys = true;
|
||||
$missingkeys[$parsedkey] = $key;
|
||||
}
|
||||
}
|
||||
if ($hasmissingkeys) {
|
||||
// We've got missing keys - we've got to check any loaders or data sources.
|
||||
$loader = $this->get_loader();
|
||||
$datasource = $this->get_datasource();
|
||||
if ($loader !== false) {
|
||||
foreach ($loader->get_many($missingkeys) as $key => $value) {
|
||||
if ($value !== false) {
|
||||
$return[$key] = $value;
|
||||
unset($missingkeys[$parsedkeys[$key]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$hasmissingkeys = count($missingkeys) > 0;
|
||||
if ($datasource !== false && $hasmissingkeys) {
|
||||
// We're still missing keys but we've got a datasource.
|
||||
foreach ($datasource->load_many_for_cache($missingkeys) as $key => $value) {
|
||||
if ($value !== false) {
|
||||
$return[$key] = $value;
|
||||
unset($missingkeys[$parsedkeys[$key]]);
|
||||
}
|
||||
}
|
||||
$hasmissingkeys = count($missingkeys) > 0;
|
||||
}
|
||||
}
|
||||
if ($hasmissingkeys && $strictness === MUST_EXIST) {
|
||||
throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
}
|
||||
if ($this->perfdebug) {
|
||||
$hits = 0;
|
||||
$misses = 0;
|
||||
foreach ($return as $value) {
|
||||
if ($value === false) {
|
||||
$misses++;
|
||||
} else {
|
||||
$hits++;
|
||||
}
|
||||
}
|
||||
cache_helper::record_cache_hit($this->get_store(), $this->get_definition(), $hits, $readbytes);
|
||||
cache_helper::record_cache_miss($this->get_store(), $this->get_definition(), $misses);
|
||||
}
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all of the given keys from the cache.
|
||||
*
|
||||
* @param array $keys The key to delete.
|
||||
* @param bool $recurse When set to true the key will also be deleted from all stacked cache loaders and their stores.
|
||||
* This happens by default and ensure that all the caches are consistent. It is NOT recommended to change this.
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
public function delete_many(array $keys, $recurse = true) {
|
||||
$parsedkeys = array_map(array($this, 'parse_key'), $keys);
|
||||
if ($recurse && $this->get_loader() !== false) {
|
||||
// Delete from the bottom of the stack first.
|
||||
$this->get_loader()->delete_many($keys, $recurse);
|
||||
}
|
||||
return $this->get_store()->delete_many($parsedkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends several key => value pairs to the cache.
|
||||
*
|
||||
* Using this function comes with potential performance implications.
|
||||
* Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
|
||||
* the equivalent singular method for each item provided.
|
||||
* This should not deter you from using this function as there is a performance benefit in situations where the cache store
|
||||
* does support it, but you should be aware of this fact.
|
||||
*
|
||||
* <code>
|
||||
* // This code will add four entries to the cache, one for each url.
|
||||
* $cache->set_many(array(
|
||||
* 'main' => 'http://moodle.org',
|
||||
* 'docs' => 'http://docs.moodle.org',
|
||||
* 'tracker' => 'http://tracker.moodle.org',
|
||||
* 'qa' => ''http://qa.moodle.net'
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
* @param array $keyvaluearray An array of key => value pairs to send to the cache.
|
||||
* @return int The number of items successfully set. It is up to the developer to check this matches the number of items.
|
||||
* ... if they care that is.
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
$this->check_tracked_user();
|
||||
$loader = $this->get_loader();
|
||||
if ($loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$loader->set_many($keyvaluearray);
|
||||
}
|
||||
$data = array();
|
||||
$definitionid = $this->get_definition()->get_ttl();
|
||||
$simulatettl = $this->has_a_ttl() && !$this->store_supports_native_ttl();
|
||||
foreach ($keyvaluearray as $key => $value) {
|
||||
if (is_object($value) && $value instanceof cacheable_object) {
|
||||
$value = new cache_cached_object($value);
|
||||
} else if (!$this->get_store()->supports_dereferencing_objects() && !is_scalar($value)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$value = $this->unref($value);
|
||||
}
|
||||
if ($simulatettl) {
|
||||
$value = new cache_ttl_wrapper($value, $definitionid);
|
||||
}
|
||||
$data[$key] = array(
|
||||
'key' => $this->parse_key($key),
|
||||
'value' => $value
|
||||
);
|
||||
}
|
||||
$successfullyset = $this->get_store()->set_many($data);
|
||||
if ($this->perfdebug && $successfullyset) {
|
||||
cache_helper::record_cache_set($this->get_store(), $this->get_definition(), $successfullyset,
|
||||
$this->get_store()->get_last_io_bytes());
|
||||
}
|
||||
return $successfullyset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the cache store, and loader if there is one.
|
||||
*
|
||||
* @return bool True on success, false otherwise
|
||||
*/
|
||||
public function purge() {
|
||||
$this->get_store()->purge();
|
||||
if ($this->get_loader()) {
|
||||
$this->get_loader()->purge();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test is a cache has a key.
|
||||
*
|
||||
* The use of the has methods is strongly discouraged. In a high load environment the cache may well change between the
|
||||
* test and any subsequent action (get, set, delete etc).
|
||||
* Instead it is recommended to write your code in such a way they it performs the following steps:
|
||||
* <ol>
|
||||
* <li>Attempt to retrieve the information.</li>
|
||||
* <li>Generate the information.</li>
|
||||
* <li>Attempt to set the information</li>
|
||||
* </ol>
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @param bool $tryloadifpossible If set to true, the cache doesn't contain the key, and there is another cache loader or
|
||||
* data source then the code will try load the key value from the next item in the chain.
|
||||
* @return bool True if the cache has the requested key, false otherwise.
|
||||
*/
|
||||
public function has($key, $tryloadifpossible = false) {
|
||||
$this->check_tracked_user();
|
||||
$parsedkey = $this->parse_key($key);
|
||||
$store = $this->get_store();
|
||||
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
|
||||
// The data has a TTL and the store doesn't support it natively.
|
||||
// We must fetch the data and expect a ttl wrapper.
|
||||
$data = $store->get($parsedkey);
|
||||
$has = ($data instanceof cache_ttl_wrapper && !$data->has_expired());
|
||||
} else if (!$this->store_supports_key_awareness()) {
|
||||
// The store doesn't support key awareness, get the data and check it manually... puke.
|
||||
// Either no TTL is set of the store supports its handling natively.
|
||||
$data = $store->get($parsedkey);
|
||||
$has = ($data !== false);
|
||||
} else {
|
||||
// The store supports key awareness, this is easy!
|
||||
// Either no TTL is set of the store supports its handling natively.
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$has = $store->has($parsedkey);
|
||||
}
|
||||
if (!$has && $tryloadifpossible) {
|
||||
$result = null;
|
||||
if ($this->get_loader() !== false) {
|
||||
$result = $this->get_loader()->get($parsedkey);
|
||||
} else if ($this->get_datasource() !== null) {
|
||||
$result = $this->get_datasource()->load_for_cache($key);
|
||||
}
|
||||
$has = ($result !== null);
|
||||
if ($has) {
|
||||
$this->set($key, $result);
|
||||
}
|
||||
}
|
||||
return $has;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test is a cache has all of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has all of the given keys, false otherwise.
|
||||
*/
|
||||
public function has_all(array $keys) {
|
||||
$this->check_tracked_user();
|
||||
if (($this->has_a_ttl() && !$this->store_supports_native_ttl()) || !$this->store_supports_key_awareness()) {
|
||||
foreach ($keys as $key) {
|
||||
if (!$this->has($key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// The cache must be key aware and if support native ttl if it a ttl is set.
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$store = $this->get_store();
|
||||
return $store->has_all(array_map(array($this, 'parse_key'), $keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a cache has at least one of the given keys.
|
||||
*
|
||||
* It is strongly recommended to avoid the use of this function if not absolutely required.
|
||||
* In a high load environment the cache may well change between the test and any subsequent action (get, set, delete etc).
|
||||
*
|
||||
* Its also worth mentioning that not all stores support key tests.
|
||||
* For stores that don't support key tests this functionality is mimicked by using the equivalent get method.
|
||||
* Just one more reason you should not use these methods unless you have a very good reason to do so.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return bool True if the cache has at least one of the given keys
|
||||
*/
|
||||
public function has_any(array $keys) {
|
||||
if (($this->has_a_ttl() && !$this->store_supports_native_ttl()) || !$this->store_supports_key_awareness()) {
|
||||
foreach ($keys as $key) {
|
||||
if ($this->has($key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$store = $this->get_store();
|
||||
return $store->has_any(array_map(array($this, 'parse_key'), $keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* The session loader never uses static acceleration.
|
||||
* Instead it stores things in the static $session variable. Shared between all session loaders.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function use_static_acceleration() {
|
||||
return false;
|
||||
}
|
||||
}
|
59
cache/classes/ttl_wrapper.php
vendored
Normal file
59
cache/classes/ttl_wrapper.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A wrapper class used to handle ttl when the cache store doesn't natively support it.
|
||||
*
|
||||
* This class is exactly why you should use event driving invalidation of cache data rather than relying on ttl.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_ttl_wrapper {
|
||||
|
||||
/**
|
||||
* The data being stored.
|
||||
* @var mixed
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* When the cache data expires as a timestamp.
|
||||
* @var int
|
||||
*/
|
||||
public $expires;
|
||||
|
||||
/**
|
||||
* Constructs a ttl cache wrapper.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param int $ttl The time to live in seconds.
|
||||
*/
|
||||
public function __construct($data, $ttl) {
|
||||
$this->data = $data;
|
||||
$this->expires = cache::now() + (int)$ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the data has expired.
|
||||
* @return int
|
||||
*/
|
||||
public function has_expired() {
|
||||
return ($this->expires < cache::now());
|
||||
}
|
||||
}
|
41
cache/classes/versionable_data_source_interface.php
vendored
Normal file
41
cache/classes/versionable_data_source_interface.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Versionable cache data source.
|
||||
*
|
||||
* This interface extends the main cache data source interface to add an extra required method if
|
||||
* the data source is to be used for a versioned cache.
|
||||
*
|
||||
* @package core_cache
|
||||
*/
|
||||
interface cache_data_source_versionable extends cache_data_source {
|
||||
/**
|
||||
* Loads the data for the key provided ready formatted for caching.
|
||||
*
|
||||
* If there is no data for that key, or if the data for the required key has an older version
|
||||
* than the specified $requiredversion, then this returns null.
|
||||
*
|
||||
* If there is data then $actualversion should be set to the actual version number retrieved
|
||||
* (may be the same as $requiredversion or newer).
|
||||
*
|
||||
* @param string|int $key The key to load.
|
||||
* @param int $requiredversion Minimum required version
|
||||
* @param mixed $actualversion Should be set to the actual version number retrieved
|
||||
* @return mixed What ever data should be returned, or false if it can't be loaded.
|
||||
*/
|
||||
public function load_for_cache_versioned($key, int $requiredversion, &$actualversion);
|
||||
}
|
193
cache/lib.php
vendored
193
cache/lib.php
vendored
@ -31,198 +31,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// Include the required classes.
|
||||
require_once($CFG->dirroot.'/cache/classes/interfaces.php');
|
||||
require_once($CFG->dirroot.'/cache/classes/config.php');
|
||||
require_once($CFG->dirroot.'/cache/classes/helper.php');
|
||||
require_once($CFG->dirroot.'/cache/classes/factory.php');
|
||||
require_once($CFG->dirroot.'/cache/classes/loaders.php');
|
||||
require_once($CFG->dirroot.'/cache/classes/store.php');
|
||||
require_once($CFG->dirroot.'/cache/classes/definition.php');
|
||||
|
||||
/**
|
||||
* A cached object wrapper.
|
||||
*
|
||||
* This class gets used when the data is an object that has implemented the cacheable_object interface.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_cached_object {
|
||||
|
||||
/**
|
||||
* The class of the cacheable object
|
||||
* @var string
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* The data returned by the cacheable_object prepare_to_cache method.
|
||||
* @var mixed
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Constructs a cached object wrapper.
|
||||
* @param cacheable_object $obj
|
||||
*/
|
||||
public function __construct(cacheable_object $obj) {
|
||||
$this->class = get_class($obj);
|
||||
$this->data = $obj->prepare_to_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the data as an instance of the cacheable_object class.
|
||||
* @return object
|
||||
*/
|
||||
public function restore_object() {
|
||||
$class = $this->class;
|
||||
return $class::wake_from_cache($this->data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper class used to handle ttl when the cache store doesn't natively support it.
|
||||
*
|
||||
* This class is exactly why you should use event driving invalidation of cache data rather than relying on ttl.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_ttl_wrapper {
|
||||
|
||||
/**
|
||||
* The data being stored.
|
||||
* @var mixed
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* When the cache data expires as a timestamp.
|
||||
* @var int
|
||||
*/
|
||||
public $expires;
|
||||
|
||||
/**
|
||||
* Constructs a ttl cache wrapper.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param int $ttl The time to live in seconds.
|
||||
*/
|
||||
public function __construct($data, $ttl) {
|
||||
$this->data = $data;
|
||||
$this->expires = cache::now() + (int)$ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the data has expired.
|
||||
* @return int
|
||||
*/
|
||||
public function has_expired() {
|
||||
return ($this->expires < cache::now());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cache exception class. Just allows people to catch cache exceptions.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_exception extends moodle_exception {
|
||||
/**
|
||||
* Constructs a new exception
|
||||
*
|
||||
* @param string $errorcode
|
||||
* @param string $module
|
||||
* @param string $link
|
||||
* @param mixed $a
|
||||
* @param mixed $debuginfo
|
||||
*/
|
||||
public function __construct($errorcode, $module = 'cache', $link = '', $a = null, $debuginfo = null) {
|
||||
// This may appear like a useless override but you will notice that we have set a MUCH more useful default for $module.
|
||||
parent::__construct($errorcode, $module, $link, $a, $debuginfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of cacheable objects.
|
||||
*
|
||||
* This class allows a developer to create an array of cacheable objects and store that.
|
||||
* The cache API doesn't check items within an array to see whether they are cacheable. Such a check would be very costly to both
|
||||
* arrays using cacheable object and those that don't.
|
||||
* Instead the developer must explicitly use a cacheable_object_array instance.
|
||||
*
|
||||
* The following is one example of how this class can be used.
|
||||
* <code>
|
||||
* $data = array();
|
||||
* $data[] = new cacheable_object('one');
|
||||
* $data[] = new cacheable_object('two');
|
||||
* $data[] = new cacheable_object('three');
|
||||
* $cache->set(new cacheable_object_array($data));
|
||||
* </code>
|
||||
* Another example would be
|
||||
* <code>
|
||||
* $data = new cacheable_object_array();
|
||||
* $data[] = new cacheable_object('one');
|
||||
* $data[] = new cacheable_object('two');
|
||||
* $data[] = new cacheable_object('three');
|
||||
* $cache->set($data);
|
||||
* </code>
|
||||
*
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cacheable_object_array extends ArrayObject implements cacheable_object {
|
||||
|
||||
/**
|
||||
* Constructs a new array object instance.
|
||||
* @param array $items
|
||||
*/
|
||||
final public function __construct(array $items = array()) {
|
||||
parent::__construct($items, ArrayObject::STD_PROP_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data to cache for this object.
|
||||
*
|
||||
* @return array An array of cache_cached_object instances.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
final public function prepare_to_cache() {
|
||||
$result = array();
|
||||
foreach ($this as $key => $value) {
|
||||
if ($value instanceof cacheable_object) {
|
||||
$value = new cache_cached_object($value);
|
||||
} else {
|
||||
throw new coding_exception('Only cacheable_object instances can be added to a cacheable_array');
|
||||
}
|
||||
$result[$key] = $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cacheable_object_array that was originally sent to the cache.
|
||||
*
|
||||
* @param array $data
|
||||
* @return cacheable_object_array
|
||||
* @throws coding_exception
|
||||
*/
|
||||
final public static function wake_from_cache($data) {
|
||||
if (!is_array($data)) {
|
||||
throw new coding_exception('Invalid data type when reviving cacheable_array data');
|
||||
}
|
||||
$result = array();
|
||||
foreach ($data as $key => $value) {
|
||||
$result[$key] = $value->restore_object();
|
||||
}
|
||||
$class = __CLASS__;
|
||||
return new $class($result);
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,31 @@ $legacyclasses = [
|
||||
\required_capability_exception::class => 'exception/required_capability_exception.php',
|
||||
\webservice_parameter_exception::class => 'exception/webservice_parameter_exception.php',
|
||||
|
||||
// Cache API.
|
||||
\cache::class => 'cache.php',
|
||||
\cache_application::class => 'application_cache.php',
|
||||
\cache_request::class => 'request_cache.php',
|
||||
\cache_session::class => 'session_cache.php',
|
||||
\cache_cached_object::class => 'cached_object.php',
|
||||
\cache_config::class => 'config.php',
|
||||
\cache_data_source::class => 'data_source_interface.php',
|
||||
\cache_data_source_versionable::class => 'versionable_data_source_interface.php',
|
||||
\cache_exception::class => 'exception/cache_exception.php',
|
||||
\cache_factory::class => 'factory.php',
|
||||
\cache_helper::class => 'helper.php',
|
||||
\cache_is_key_aware::class => 'key_aware_cache_interface.php',
|
||||
\cache_is_lockable::class => 'lockable_cache_interface.php',
|
||||
\cache_is_searchable::class => 'searchable_cache_interface.php',
|
||||
\cache_is_configurable::class => 'configurable_cache_interface.php',
|
||||
\cache_loader::class => 'loader_interface.php',
|
||||
\cache_loader_with_locking::class => 'loader_with_locking_interface.php',
|
||||
\cache_lock_interface::class => 'cache_lock_interface.php',
|
||||
\cache_store::class => 'store.php',
|
||||
\cache_ttl_wrapper::class => 'ttl_wrapper.php',
|
||||
\cache_store_interface::class => 'store_interface.php',
|
||||
\cacheable_object::class => 'cacheable_object_interface.php',
|
||||
\cacheable_object_array::class => 'cacheable_object_array.php',
|
||||
|
||||
// Output API.
|
||||
\theme_config::class => 'output/theme_config.php',
|
||||
\xhtml_container_stack::class => 'output/xhtml_container_stack.php',
|
||||
|
Loading…
x
Reference in New Issue
Block a user