mirror of
https://github.com/moodle/moodle.git
synced 2025-07-24 15:51:56 +02:00
MDL-77161 cachestore_memcached: Remove from core
This commit is contained in:
6
cache/README.md
vendored
6
cache/README.md
vendored
@@ -242,16 +242,14 @@ Both the cache API and the cache stores have tests.
|
||||
Please be aware that several of the cache stores require configuration in order to be able operate in the tests.
|
||||
Tests for stores requiring configuration that haven't been configured will be skipped.
|
||||
All configuration is done in your sites config.php through definitions.
|
||||
The following snippet illustrates how to configure the three core cache stores that require configuration.
|
||||
The following snippet illustrates how to configure core cache stores that require configuration.
|
||||
|
||||
define('TEST_CACHESTORE_MEMCACHE_TESTSERVERS', '127.0.0.1:11211');
|
||||
define('TEST_CACHESTORE_MEMCACHED_TESTSERVERS', '127.0.0.1:11211');
|
||||
define('TEST_CACHESTORE_MONGODB_TESTSERVER', 'mongodb://localhost:27017');
|
||||
|
||||
As of Moodle 2.8 it is also possible to set the default cache stores used when running tests.
|
||||
You can do this by adding the following define to your config.php file:
|
||||
|
||||
// xxx is one of Memcache, Memcached, mongodb or other cachestore with a test define.
|
||||
// xxx is one of the installed stored (for example redis) or other cachestore with a test define.
|
||||
define('TEST_CACHE_USING_APPLICATION_STORE', 'xxx');
|
||||
|
||||
This allows you to run tests against a defined test store. It uses the defined value to identify a store to test against with a matching TEST_CACHESTORE define.
|
||||
|
147
cache/stores/memcached/addinstanceform.php
vendored
147
cache/stores/memcached/addinstanceform.php
vendored
@@ -1,147 +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/>.
|
||||
|
||||
/**
|
||||
* The library file for the memcached cache store.
|
||||
*
|
||||
* This file is part of the memcached cache store, it contains the API for interacting with an instance of the store.
|
||||
*
|
||||
* @package cachestore_memcached
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot.'/cache/forms.php');
|
||||
require_once($CFG->dirroot.'/cache/stores/memcached/lib.php');
|
||||
|
||||
/**
|
||||
* Form for adding a memcached instance.
|
||||
*
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cachestore_memcached_addinstance_form extends cachestore_addinstance_form {
|
||||
|
||||
/**
|
||||
* Adds the desired form elements.
|
||||
*/
|
||||
protected function configuration_definition() {
|
||||
global $OUTPUT;
|
||||
|
||||
$form = $this->_form;
|
||||
$version = phpversion('memcached');
|
||||
$hasrequiredversion = ($version || version_compare($version, cachestore_memcached::REQUIRED_VERSION, '>='));
|
||||
|
||||
if (!$hasrequiredversion) {
|
||||
$notify = new \core\output\notification(nl2br(get_string('upgrade200recommended', 'cachestore_memcached')),
|
||||
\core\output\notification::NOTIFY_WARNING);
|
||||
$form->addElement('html', $OUTPUT->render($notify));
|
||||
}
|
||||
|
||||
$form->addElement('textarea', 'servers', get_string('servers', 'cachestore_memcached'), array('cols' => 75, 'rows' => 5));
|
||||
$form->addHelpButton('servers', 'servers', 'cachestore_memcached');
|
||||
$form->addRule('servers', get_string('required'), 'required');
|
||||
$form->setType('servers', PARAM_RAW);
|
||||
|
||||
$form->addElement('selectyesno', 'compression', get_string('usecompression', 'cachestore_memcached'));
|
||||
$form->addHelpButton('compression', 'usecompression', 'cachestore_memcached');
|
||||
$form->setDefault('compression', 1);
|
||||
$form->setType('compression', PARAM_BOOL);
|
||||
|
||||
$serialiseroptions = cachestore_memcached::config_get_serialiser_options();
|
||||
$form->addElement('select', 'serialiser', get_string('useserialiser', 'cachestore_memcached'), $serialiseroptions);
|
||||
$form->addHelpButton('serialiser', 'useserialiser', 'cachestore_memcached');
|
||||
$form->setDefault('serialiser', Memcached::SERIALIZER_PHP);
|
||||
$form->setType('serialiser', PARAM_INT);
|
||||
|
||||
$form->addElement('text', 'prefix', get_string('prefix', 'cachestore_memcached'), array('size' => 16));
|
||||
$form->setType('prefix', PARAM_TEXT); // We set to text but we have a rule to limit to alphanumext.
|
||||
$form->addHelpButton('prefix', 'prefix', 'cachestore_memcached');
|
||||
$form->addRule('prefix', get_string('prefixinvalid', 'cachestore_memcached'), 'regex', '#^[a-zA-Z0-9\-_]+$#');
|
||||
$form->setForceLtr('prefix');
|
||||
|
||||
$hashoptions = cachestore_memcached::config_get_hash_options();
|
||||
$form->addElement('select', 'hash', get_string('hash', 'cachestore_memcached'), $hashoptions);
|
||||
$form->addHelpButton('hash', 'hash', 'cachestore_memcached');
|
||||
$form->setDefault('serialiser', Memcached::HASH_DEFAULT);
|
||||
$form->setType('serialiser', PARAM_INT);
|
||||
|
||||
$form->addElement('selectyesno', 'bufferwrites', get_string('bufferwrites', 'cachestore_memcached'));
|
||||
$form->addHelpButton('bufferwrites', 'bufferwrites', 'cachestore_memcached');
|
||||
$form->setDefault('bufferwrites', 0);
|
||||
$form->setType('bufferwrites', PARAM_BOOL);
|
||||
|
||||
if ($hasrequiredversion) {
|
||||
// Only show this option if we have the required version of memcache extension installed.
|
||||
// If it's not installed then this option does nothing, so there is no point in displaying it.
|
||||
$form->addElement('selectyesno', 'isshared', get_string('isshared', 'cachestore_memcached'));
|
||||
$form->addHelpButton('isshared', 'isshared', 'cachestore_memcached');
|
||||
$form->setDefault('isshared', 0);
|
||||
$form->setType('isshared', PARAM_BOOL);
|
||||
}
|
||||
|
||||
$form->addElement('header', 'clusteredheader', get_string('clustered', 'cachestore_memcached'));
|
||||
|
||||
$form->addElement('checkbox', 'clustered', get_string('clustered', 'cachestore_memcached'));
|
||||
$form->setDefault('checkbox', false);
|
||||
$form->addHelpButton('clustered', 'clustered', 'cachestore_memcached');
|
||||
|
||||
$form->addElement('textarea', 'setservers', get_string('setservers', 'cachestore_memcached'),
|
||||
array('cols' => 75, 'rows' => 5));
|
||||
$form->addHelpButton('setservers', 'setservers', 'cachestore_memcached');
|
||||
$form->disabledIf('setservers', 'clustered');
|
||||
$form->setType('setservers', PARAM_RAW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform minimal validation on the settings form.
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $files
|
||||
*/
|
||||
public function validation($data, $files) {
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
if (isset($data['clustered']) && ($data['clustered'] == 1)) {
|
||||
// Set servers is required with in cluster mode.
|
||||
if (!isset($data['setservers'])) {
|
||||
$errors['setservers'] = get_string('required');
|
||||
} else {
|
||||
$trimmed = trim($data['setservers']);
|
||||
if (empty($trimmed)) {
|
||||
$errors['setservers'] = get_string('required');
|
||||
}
|
||||
}
|
||||
|
||||
$validservers = false;
|
||||
if (isset($data['servers'])) {
|
||||
$servers = trim($data['servers']);
|
||||
$servers = explode("\n", $servers);
|
||||
if (count($servers) === 1) {
|
||||
$validservers = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$validservers) {
|
||||
$errors['servers'] = get_string('serversclusterinvalid', 'cachestore_memcached');
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
109
cache/stores/memcached/classes/privacy/provider.php
vendored
109
cache/stores/memcached/classes/privacy/provider.php
vendored
@@ -1,109 +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/>.
|
||||
|
||||
/**
|
||||
* Privacy Subsystem implementation for cachestore_memcached.
|
||||
*
|
||||
* @package cachestore_memcached
|
||||
* @category privacy
|
||||
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace cachestore_memcached\privacy;
|
||||
|
||||
use core_privacy\local\metadata\collection;
|
||||
use core_privacy\local\request\approved_contextlist;
|
||||
use core_privacy\local\request\approved_userlist;
|
||||
use core_privacy\local\request\contextlist;
|
||||
use core_privacy\local\request\userlist;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Privacy Subsystem for cachestore_memcached.
|
||||
*
|
||||
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements
|
||||
\core_privacy\local\metadata\provider,
|
||||
\core_privacy\local\request\plugin\provider,
|
||||
\core_privacy\local\request\core_userlist_provider {
|
||||
|
||||
/**
|
||||
* Returns meta data about this system.
|
||||
*
|
||||
* @param collection $collection The initialised collection to add items to.
|
||||
* @return collection A listing of user data stored through this system.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$collection->add_external_location_link('memcached', [
|
||||
'data' => 'privacy:metadata:memcached:data',
|
||||
], 'privacy:metadata:memcached');
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of contexts that contain user information for the specified user.
|
||||
*
|
||||
* @param int $userid The user to search.
|
||||
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
|
||||
*/
|
||||
public static function get_contexts_for_userid(int $userid) : contextlist {
|
||||
return new contextlist();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of users who have data within a context.
|
||||
*
|
||||
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
|
||||
*/
|
||||
public static function get_users_in_context(userlist $userlist) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for the specified user, in the specified contexts.
|
||||
*
|
||||
* @param approved_contextlist $contextlist The approved contexts to export information for.
|
||||
*/
|
||||
public static function export_user_data(approved_contextlist $contextlist) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all use data which matches the specified deletion_criteria.
|
||||
*
|
||||
* @param \context $context A user context.
|
||||
*/
|
||||
public static function delete_data_for_all_users_in_context(\context $context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all user data for the specified user, in the specified contexts.
|
||||
*
|
||||
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
|
||||
*/
|
||||
public static function delete_data_for_user(approved_contextlist $contextlist) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple users within a single context.
|
||||
*
|
||||
* @param approved_userlist $userlist The approved context and user information to delete information for.
|
||||
*/
|
||||
public static function delete_data_for_users(approved_userlist $userlist) {
|
||||
}
|
||||
}
|
@@ -1,101 +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/>.
|
||||
|
||||
/**
|
||||
* The library file for the memcached cache store.
|
||||
*
|
||||
* This file is part of the memcached cache store, it contains the API for interacting with an instance of the store.
|
||||
*
|
||||
* @package cachestore_memcached
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['bufferwrites'] = 'Buffer writes';
|
||||
$string['bufferwrites_help'] = 'Enables or disables buffered I/O. Enabling buffered I/O causes storage commands to "buffer" instead of being sent. Any action that retrieves data causes this buffer to be sent to the remote connection. Quitting the connection or closing down the connection will also cause the buffered data to be pushed to the remote connection.';
|
||||
$string['clustered'] = 'Enable clustered servers';
|
||||
$string['clustered_help'] = 'This is used to allow read-one, set-multi functionality.
|
||||
|
||||
The intended use case is to create an improved store for load-balanced configurations. The store will fetch from one server (usually localhost), but set to many (all the servers in the load-balance pool). For caches with very high read to set ratios, this saves a significant amount of network overhead.
|
||||
|
||||
When this setting is enabled, the server listed above will be used for fetching.';
|
||||
$string['clusteredheader'] = 'Split servers';
|
||||
$string['hash'] = 'Hash method';
|
||||
$string['hash_help'] = 'Specifies the hashing algorithm used for the item keys. Each hash algorithm has its advantages and its disadvantages. Go with the default if you don\'t know or don\'t care.';
|
||||
$string['hash_default'] = 'Default (one-at-a-time)';
|
||||
$string['hash_md5'] = 'MD5';
|
||||
$string['hash_crc'] = 'CRC';
|
||||
$string['hash_fnv1_64'] = 'FNV1_64';
|
||||
$string['hash_fnv1a_64'] = 'FNV1A_64';
|
||||
$string['hash_fnv1_32'] = 'FNV1_32';
|
||||
$string['hash_fnv1a_32'] = 'FNV1A_32';
|
||||
$string['hash_hsieh'] = 'Hsieh';
|
||||
$string['hash_murmur'] = 'Murmur';
|
||||
$string['isshared'] = 'Shared cache';
|
||||
$string['isshared_help'] = "Is your memcached server also being used by other applications?
|
||||
|
||||
If the cache is shared by other applications then each key will be deleted individually to ensure that only data owned by this application is purged (leaving external application cache data unchanged). This can result in reduced performance when purging the cache, depending on your server configuration.
|
||||
|
||||
If you are running a dedicated cache for this application then the entire cache can safely be flushed without any risk of destroying another application's cache data. This should result in increased performance when purging the cache.
|
||||
";
|
||||
$string['pluginname'] = 'Memcached';
|
||||
$string['privacy:metadata:memcached'] = 'The Memcached cachestore plugin stores data briefly as part of its caching functionality. This data is stored on an Memcache server where data is regularly removed.';
|
||||
$string['privacy:metadata:memcached:data'] = 'The various data stored in the cache';
|
||||
$string['prefix'] = 'Prefix key';
|
||||
$string['prefix_help'] = 'This can be used to create a "domain" for your item keys allowing you to create multiple memcached stores on a single memcached installation. It cannot be longer than 16 characters in order to ensure key length issues are not encountered.';
|
||||
$string['prefixinvalid'] = 'Invalid prefix. You can only use a-z A-Z 0-9-_.';
|
||||
$string['serialiser_igbinary'] = 'The igbinary serializer.';
|
||||
$string['serialiser_json'] = 'The JSON serializer.';
|
||||
$string['serialiser_php'] = 'The default PHP serializer.';
|
||||
$string['servers'] = 'Servers';
|
||||
$string['servers_help'] = 'This sets the servers that should be utilised by this memcached adapter.
|
||||
Servers should be defined one per line and consist of a server address and optionally a port and weight.
|
||||
If no port is provided then the default port (11211) is used.
|
||||
|
||||
For example:
|
||||
<pre>
|
||||
server.url.com
|
||||
ipaddress:port
|
||||
servername:port:weight
|
||||
</pre>
|
||||
|
||||
If *Enable clustered servers* is enabled below, there must be only one server listed here. This would usually be a name that always resolves to the local machine, like 127.0.0.1 or localhost.';
|
||||
$string['serversclusterinvalid'] = 'Exactly one server is required when clustering is enabled.';
|
||||
$string['setservers'] = 'Set Servers';
|
||||
$string['setservers_help'] = 'This is the list of servers that will be updated when data is modified in the cache. Generally the fully qualified name of each server in the pool.
|
||||
It **must** include the server listed in *Servers* above, even if by a different hostname.
|
||||
Servers should be defined one per line and consist of a server address and optionally a port.
|
||||
If no port is provided then the default port (11211) is used.
|
||||
|
||||
For example:
|
||||
<pre>
|
||||
server.url.com
|
||||
ipaddress:port
|
||||
</pre>';
|
||||
$string['sessionhandlerconflict'] = 'Warning: A memcached instance ({$a}) has being configured to use the same memcached server as sessions. Purging all caches will lead to sessions also being purged.';
|
||||
$string['testservers'] = 'Test servers';
|
||||
$string['testservers_desc'] = 'One or more connection strings for memcached servers to test against. If a test server has been specified then memcached performance can be tested using the cache performance page in the administration block.
|
||||
As an example: 127.0.0.1:11211';
|
||||
$string['usecompression'] = 'Use compression';
|
||||
$string['usecompression_help'] = 'Enables or disables payload compression. When enabled, item values longer than a certain threshold (currently 100 bytes) will be compressed during storage and decompressed during retrieval transparently.';
|
||||
$string['useserialiser'] = 'Use serialiser';
|
||||
$string['useserialiser_help'] = 'Specifies the serializer to use for serializing non-scalar values.
|
||||
The valid serializers are Memcached::SERIALIZER_PHP or Memcached::SERIALIZER_IGBINARY.
|
||||
The latter is supported only when memcached is configured with --enable-memcached-igbinary option and the igbinary extension is loaded.';
|
||||
$string['upgrade200recommended'] = 'We recommend you upgrade your Memcached PHP extension to version 2.0.0 or greater.
|
||||
The version of the Memcached PHP extension you are currently using does not provide the functionality Moodle uses to ensure a sandboxed cache. Until you upgrade we recommend you do not configure any other applications to use the same Memcached servers as Moodle is configured to use.';
|
853
cache/stores/memcached/lib.php
vendored
853
cache/stores/memcached/lib.php
vendored
@@ -1,853 +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/>.
|
||||
|
||||
/**
|
||||
* The library file for the memcached cache store.
|
||||
*
|
||||
* This file is part of the memcached cache store, it contains the API for interacting with an instance of the store.
|
||||
*
|
||||
* @package cachestore_memcached
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The memcached store.
|
||||
*
|
||||
* (Not to be confused with the memcache store)
|
||||
*
|
||||
* Configuration options:
|
||||
* servers: string: host:port:weight , ...
|
||||
* compression: true, false
|
||||
* serialiser: SERIALIZER_PHP, SERIALIZER_JSON, SERIALIZER_IGBINARY
|
||||
* prefix: string: defaults to instance name
|
||||
* hashmethod: HASH_DEFAULT, HASH_MD5, HASH_CRC, HASH_FNV1_64, HASH_FNV1A_64, HASH_FNV1_32,
|
||||
* HASH_FNV1A_32, HASH_HSIEH, HASH_MURMUR
|
||||
* bufferwrites: true, false
|
||||
*
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cachestore_memcached extends cache_store implements cache_is_configurable {
|
||||
|
||||
/**
|
||||
* The minimum required version of memcached in order to use this store.
|
||||
*/
|
||||
const REQUIRED_VERSION = '2.0.0';
|
||||
|
||||
/**
|
||||
* The name of the store
|
||||
* @var store
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The memcached connection
|
||||
* @var Memcached
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* An array of servers to use during connection
|
||||
* @var array
|
||||
*/
|
||||
protected $servers = array();
|
||||
|
||||
/**
|
||||
* The options used when establishing the connection
|
||||
* @var array
|
||||
*/
|
||||
protected $options = array();
|
||||
|
||||
/**
|
||||
* True when this instance is ready to be initialised.
|
||||
* @var bool
|
||||
*/
|
||||
protected $isready = false;
|
||||
|
||||
/**
|
||||
* Set to true when this store instance has been initialised.
|
||||
* @var bool
|
||||
*/
|
||||
protected $isinitialised = false;
|
||||
|
||||
/**
|
||||
* The cache definition this store was initialised with.
|
||||
* @var cache_definition
|
||||
*/
|
||||
protected $definition;
|
||||
|
||||
/**
|
||||
* Set to true when this store is clustered.
|
||||
* @var bool
|
||||
*/
|
||||
protected $clustered = false;
|
||||
|
||||
/**
|
||||
* Array of servers to set when in clustered mode.
|
||||
* @var array
|
||||
*/
|
||||
protected $setservers = array();
|
||||
|
||||
/**
|
||||
* The an array of memcache connections for the set servers, once established.
|
||||
* @var array
|
||||
*/
|
||||
protected $setconnections = array();
|
||||
|
||||
/**
|
||||
* The prefix to use on all keys.
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = '';
|
||||
|
||||
/**
|
||||
* True if Memcached::deleteMulti can be used, false otherwise.
|
||||
* This required extension version 2.0.0 or greater.
|
||||
* @var bool
|
||||
*/
|
||||
protected $candeletemulti = false;
|
||||
|
||||
/**
|
||||
* True if the memcached server is shared, false otherwise.
|
||||
* This required extension version 2.0.0 or greater.
|
||||
* @var bool
|
||||
*/
|
||||
protected $isshared = false;
|
||||
|
||||
/**
|
||||
* Constructs the store instance.
|
||||
*
|
||||
* Noting that this function is not an initialisation. It is used to prepare the store for use.
|
||||
* The store will be initialised when required and will be provided with a cache_definition at that time.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $configuration
|
||||
*/
|
||||
public function __construct($name, array $configuration = array()) {
|
||||
$this->name = $name;
|
||||
if (!array_key_exists('servers', $configuration) || empty($configuration['servers'])) {
|
||||
// Nothing configured.
|
||||
return;
|
||||
}
|
||||
if (!is_array($configuration['servers'])) {
|
||||
$configuration['servers'] = array($configuration['servers']);
|
||||
}
|
||||
|
||||
$compression = array_key_exists('compression', $configuration) ? (bool)$configuration['compression'] : true;
|
||||
if (array_key_exists('serialiser', $configuration)) {
|
||||
$serialiser = (int)$configuration['serialiser'];
|
||||
} else {
|
||||
$serialiser = Memcached::SERIALIZER_PHP;
|
||||
}
|
||||
$prefix = (!empty($configuration['prefix'])) ? (string)$configuration['prefix'] : crc32($name);
|
||||
$hashmethod = (array_key_exists('hash', $configuration)) ? (int)$configuration['hash'] : Memcached::HASH_DEFAULT;
|
||||
$bufferwrites = array_key_exists('bufferwrites', $configuration) ? (bool)$configuration['bufferwrites'] : false;
|
||||
|
||||
foreach ($configuration['servers'] as $server) {
|
||||
if (!is_array($server)) {
|
||||
$server = explode(':', $server, 3);
|
||||
}
|
||||
if (!array_key_exists(1, $server)) {
|
||||
$server[1] = 11211;
|
||||
$server[2] = 100;
|
||||
} else if (!array_key_exists(2, $server)) {
|
||||
$server[2] = 100;
|
||||
}
|
||||
$this->servers[] = $server;
|
||||
}
|
||||
|
||||
$this->clustered = array_key_exists('clustered', $configuration) ? (bool)$configuration['clustered'] : false;
|
||||
|
||||
if ($this->clustered) {
|
||||
if (!array_key_exists('setservers', $configuration) || (count($configuration['setservers']) < 1)) {
|
||||
// Can't setup clustering without set servers.
|
||||
return;
|
||||
}
|
||||
if (count($this->servers) !== 1) {
|
||||
// Can only setup cluster with exactly 1 get server.
|
||||
return;
|
||||
}
|
||||
foreach ($configuration['setservers'] as $server) {
|
||||
// We do not use weights (3rd part) on these servers.
|
||||
if (!is_array($server)) {
|
||||
$server = explode(':', $server, 3);
|
||||
}
|
||||
if (!array_key_exists(1, $server)) {
|
||||
$server[1] = 11211;
|
||||
}
|
||||
$this->setservers[] = $server;
|
||||
}
|
||||
}
|
||||
|
||||
$this->options[Memcached::OPT_COMPRESSION] = $compression;
|
||||
$this->options[Memcached::OPT_SERIALIZER] = $serialiser;
|
||||
$this->options[Memcached::OPT_PREFIX_KEY] = $this->prefix = (string)$prefix;
|
||||
$this->options[Memcached::OPT_HASH] = $hashmethod;
|
||||
$this->options[Memcached::OPT_BUFFER_WRITES] = $bufferwrites;
|
||||
|
||||
$this->connection = new Memcached(crc32($this->name));
|
||||
$servers = $this->connection->getServerList();
|
||||
if (empty($servers)) {
|
||||
foreach ($this->options as $key => $value) {
|
||||
$this->connection->setOption($key, $value);
|
||||
}
|
||||
$this->connection->addServers($this->servers);
|
||||
}
|
||||
|
||||
if ($this->clustered) {
|
||||
foreach ($this->setservers as $setserver) {
|
||||
// Since we will have a number of them with the same name, append server and port.
|
||||
$connection = new Memcached(crc32($this->name.$setserver[0].$setserver[1]));
|
||||
foreach ($this->options as $key => $value) {
|
||||
$connection->setOption($key, $value);
|
||||
}
|
||||
$connection->addServer($setserver[0], $setserver[1]);
|
||||
$this->setconnections[] = $connection;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($configuration['isshared'])) {
|
||||
$this->isshared = $configuration['isshared'];
|
||||
}
|
||||
|
||||
$version = phpversion('memcached');
|
||||
$this->candeletemulti = ($version && version_compare($version, self::REQUIRED_VERSION, '>='));
|
||||
|
||||
$this->isready = $this->is_connection_ready();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm whether the connection is ready and usable.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_connection_ready() {
|
||||
if (!@$this->connection->set("ping", 'ping', 1)) {
|
||||
// Test the connection to the server.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isshared) {
|
||||
// There is a bug in libmemcached which means that it is not possible to purge the cache in a shared cache
|
||||
// configuration.
|
||||
// This issue currently affects:
|
||||
// - memcached 1.4.23+ with php-memcached <= 2.2.0
|
||||
// The following combinations are not affected:
|
||||
// - memcached <= 1.4.22 with any version of php-memcached
|
||||
// - any version of memcached with php-memcached >= 3.0.1
|
||||
|
||||
|
||||
// This check is cheapest as it does not involve connecting to the server at all.
|
||||
$safecombination = false;
|
||||
$extension = new ReflectionExtension('memcached');
|
||||
if ((version_compare($extension->getVersion(), '3.0.1') >= 0)) {
|
||||
// This is php-memcached version >= 3.0.1 which is a safe combination.
|
||||
$safecombination = true;
|
||||
}
|
||||
|
||||
if (!$safecombination) {
|
||||
$allsafe = true;
|
||||
foreach ($this->connection->getVersion() as $version) {
|
||||
$allsafe = $allsafe && (version_compare($version, '1.4.22') <= 0);
|
||||
}
|
||||
// All memcached servers connected are version <= 1.4.22 which is a safe combination.
|
||||
$safecombination = $allsafe;
|
||||
}
|
||||
|
||||
if (!$safecombination) {
|
||||
// This is memcached 1.4.23+ and php-memcached < 3.0.1.
|
||||
// The issue may have been resolved in a subsequent update to any of the three libraries.
|
||||
// The only way to safely determine if the combination is safe is to call getAllKeys.
|
||||
// A safe combination will return an array, whilst an affected combination will return false.
|
||||
// This is the most expensive check.
|
||||
if (!is_array($this->connection->getAllKeys())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the cache.
|
||||
*
|
||||
* Once this has been done the cache is all set to be used.
|
||||
*
|
||||
* @throws coding_exception if the instance has already been initialised.
|
||||
* @param cache_definition $definition
|
||||
*/
|
||||
public function initialise(cache_definition $definition) {
|
||||
if ($this->is_initialised()) {
|
||||
throw new coding_exception('This memcached instance has already been initialised.');
|
||||
}
|
||||
$this->definition = $definition;
|
||||
$this->isinitialised = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true once this instance has been initialised.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_initialised() {
|
||||
return ($this->isinitialised);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this store instance is ready to be used.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_ready() {
|
||||
return $this->isready;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the store requirements are met.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function are_requirements_met() {
|
||||
return extension_loaded('memcached') && class_exists('Memcached');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given mode is supported by this store.
|
||||
*
|
||||
* @param int $mode One of cache_store::MODE_*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_supported_mode($mode) {
|
||||
return ($mode === self::MODE_APPLICATION || $mode === self::MODE_SESSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supported features as a combined int.
|
||||
*
|
||||
* @param array $configuration
|
||||
* @return int
|
||||
*/
|
||||
public static function get_supported_features(array $configuration = array()) {
|
||||
return self::SUPPORTS_NATIVE_TTL + self::DEREFERENCES_OBJECTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false as this store does not support multiple identifiers.
|
||||
* (This optional function is a performance optimisation; it must be
|
||||
* consistent with the value from get_supported_features.)
|
||||
*
|
||||
* @return bool False
|
||||
*/
|
||||
public function supports_multiple_identifiers() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supported modes as a combined int.
|
||||
*
|
||||
* @param array $configuration
|
||||
* @return int
|
||||
*/
|
||||
public static function get_supported_modes(array $configuration = array()) {
|
||||
return self::MODE_APPLICATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an item from the cache store given its key.
|
||||
*
|
||||
* @param string $key The key to retrieve
|
||||
* @return mixed The data that was associated with the key, or false if the key did not exist.
|
||||
*/
|
||||
public function get($key) {
|
||||
return $this->connection->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves several items from the cache store in a single transaction.
|
||||
*
|
||||
* If not all of the items are available in the cache then the data value for those that are missing will be set to false.
|
||||
*
|
||||
* @param array $keys The array of keys to retrieve
|
||||
* @return array An array of items from the cache. There will be an item for each key, those that were not in the store will
|
||||
* be set to false.
|
||||
*/
|
||||
public function get_many($keys) {
|
||||
$return = array();
|
||||
$result = $this->connection->getMulti($keys);
|
||||
if (!is_array($result)) {
|
||||
$result = array();
|
||||
}
|
||||
foreach ($keys as $key) {
|
||||
if (!array_key_exists($key, $result)) {
|
||||
$return[$key] = false;
|
||||
} else {
|
||||
$return[$key] = $result[$key];
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an item in the cache given its key and data value.
|
||||
*
|
||||
* @param string $key The key to use.
|
||||
* @param mixed $data The data to set.
|
||||
* @return bool True if the operation was a success false otherwise.
|
||||
*/
|
||||
public function set($key, $data) {
|
||||
if ($this->clustered) {
|
||||
$status = true;
|
||||
foreach ($this->setconnections as $connection) {
|
||||
$status = $connection->set($key, $data, $this->definition->get_ttl()) && $status;
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
return $this->connection->set($key, $data, $this->definition->get_ttl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets many items in the cache in a single transaction.
|
||||
*
|
||||
* @param array $keyvaluearray An array of key value pairs. Each item in the array will be an associative array with two
|
||||
* keys, 'key' and 'value'.
|
||||
* @return int The number of items successfully set. It is up to the developer to check this matches the number of items
|
||||
* sent ... if they care that is.
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
$pairs = array();
|
||||
foreach ($keyvaluearray as $pair) {
|
||||
$pairs[$pair['key']] = $pair['value'];
|
||||
}
|
||||
|
||||
$status = true;
|
||||
if ($this->clustered) {
|
||||
foreach ($this->setconnections as $connection) {
|
||||
$status = $connection->setMulti($pairs, $this->definition->get_ttl()) && $status;
|
||||
}
|
||||
} else {
|
||||
$status = $this->connection->setMulti($pairs, $this->definition->get_ttl());
|
||||
}
|
||||
|
||||
if ($status) {
|
||||
return count($keyvaluearray);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an item from the cache store.
|
||||
*
|
||||
* @param string $key The key to delete.
|
||||
* @return bool Returns true if the operation was a success, false otherwise.
|
||||
*/
|
||||
public function delete($key) {
|
||||
if ($this->clustered) {
|
||||
$status = true;
|
||||
foreach ($this->setconnections as $connection) {
|
||||
$status = $connection->delete($key) && $status;
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
return $this->connection->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes several keys from the cache in a single action.
|
||||
*
|
||||
* @param array $keys The keys to delete
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
public function delete_many(array $keys) {
|
||||
if ($this->clustered) {
|
||||
// Get the minimum deleted from any of the connections.
|
||||
$count = count($keys);
|
||||
foreach ($this->setconnections as $connection) {
|
||||
$count = min($this->delete_many_connection($connection, $keys), $count);
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
return $this->delete_many_connection($this->connection, $keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes several keys from the cache in a single action for a specific connection.
|
||||
*
|
||||
* @param Memcached $connection The connection to work on.
|
||||
* @param array $keys The keys to delete
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
protected function delete_many_connection(Memcached $connection, array $keys) {
|
||||
$count = 0;
|
||||
if ($this->candeletemulti) {
|
||||
// We can use deleteMulti, this is a bit faster yay!
|
||||
$result = $connection->deleteMulti($keys);
|
||||
foreach ($result as $key => $outcome) {
|
||||
if ($outcome === true) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
// They are running an older version of the php memcached extension.
|
||||
foreach ($keys as $key) {
|
||||
if ($connection->delete($key)) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the cache deleting all items within it.
|
||||
*
|
||||
* @return boolean True on success. False otherwise.
|
||||
*/
|
||||
public function purge() {
|
||||
if ($this->isready) {
|
||||
// Only use delete multi if we have the correct extension installed and if the memcached
|
||||
// server is shared (flushing the cache is quicker otherwise).
|
||||
$candeletemulti = ($this->candeletemulti && $this->isshared);
|
||||
|
||||
if ($this->clustered) {
|
||||
foreach ($this->setconnections as $connection) {
|
||||
if ($candeletemulti) {
|
||||
$keys = self::get_prefixed_keys($connection, $this->prefix);
|
||||
$connection->deleteMulti($keys);
|
||||
} else {
|
||||
// Oh damn, this isn't multi-site safe.
|
||||
$connection->flush();
|
||||
}
|
||||
}
|
||||
} else if ($candeletemulti) {
|
||||
$keys = self::get_prefixed_keys($this->connection, $this->prefix);
|
||||
$this->connection->deleteMulti($keys);
|
||||
} else {
|
||||
// Oh damn, this isn't multi-site safe.
|
||||
$this->connection->flush();
|
||||
}
|
||||
}
|
||||
// It never fails. Ever.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the keys in the given connection that belong to this cache store instance.
|
||||
*
|
||||
* Requires php memcached extension version 2.0.0 or greater.
|
||||
*
|
||||
* @param Memcached $connection
|
||||
* @param string $prefix
|
||||
* @return array
|
||||
*/
|
||||
protected static function get_prefixed_keys(Memcached $connection, $prefix) {
|
||||
$connkeys = $connection->getAllKeys();
|
||||
if (empty($connkeys)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$keys = array();
|
||||
$start = strlen($prefix);
|
||||
foreach ($connkeys as $key) {
|
||||
if (strpos($key, $prefix) === 0) {
|
||||
$keys[] = substr($key, $start);
|
||||
}
|
||||
}
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of options to use as the serialiser.
|
||||
* @return array
|
||||
*/
|
||||
public static function config_get_serialiser_options() {
|
||||
$options = array(
|
||||
Memcached::SERIALIZER_PHP => get_string('serialiser_php', 'cachestore_memcached')
|
||||
);
|
||||
if (Memcached::HAVE_JSON) {
|
||||
$options[Memcached::SERIALIZER_JSON] = get_string('serialiser_json', 'cachestore_memcached');
|
||||
}
|
||||
if (Memcached::HAVE_IGBINARY) {
|
||||
$options[Memcached::SERIALIZER_IGBINARY] = get_string('serialiser_igbinary', 'cachestore_memcached');
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of hash options available during configuration.
|
||||
* @return array
|
||||
*/
|
||||
public static function config_get_hash_options() {
|
||||
$options = array(
|
||||
Memcached::HASH_DEFAULT => get_string('hash_default', 'cachestore_memcached'),
|
||||
Memcached::HASH_MD5 => get_string('hash_md5', 'cachestore_memcached'),
|
||||
Memcached::HASH_CRC => get_string('hash_crc', 'cachestore_memcached'),
|
||||
Memcached::HASH_FNV1_64 => get_string('hash_fnv1_64', 'cachestore_memcached'),
|
||||
Memcached::HASH_FNV1A_64 => get_string('hash_fnv1a_64', 'cachestore_memcached'),
|
||||
Memcached::HASH_FNV1_32 => get_string('hash_fnv1_32', 'cachestore_memcached'),
|
||||
Memcached::HASH_FNV1A_32 => get_string('hash_fnv1a_32', 'cachestore_memcached'),
|
||||
Memcached::HASH_HSIEH => get_string('hash_hsieh', 'cachestore_memcached'),
|
||||
Memcached::HASH_MURMUR => get_string('hash_murmur', 'cachestore_memcached'),
|
||||
);
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$lines = explode("\n", $data->servers);
|
||||
$servers = array();
|
||||
foreach ($lines as $line) {
|
||||
// Trim surrounding colons and default whitespace.
|
||||
$line = trim(trim($line), ":");
|
||||
// Skip blank lines.
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
$servers[] = explode(':', $line, 3);
|
||||
}
|
||||
|
||||
$clustered = false;
|
||||
$setservers = array();
|
||||
if (isset($data->clustered)) {
|
||||
$clustered = true;
|
||||
|
||||
$lines = explode("\n", $data->setservers);
|
||||
foreach ($lines as $line) {
|
||||
// Trim surrounding colons and default whitespace.
|
||||
$line = trim(trim($line), ":");
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
$setserver = explode(':', $line, 3);
|
||||
// We don't use weights, so display a debug message.
|
||||
if (count($setserver) > 2) {
|
||||
debugging('Memcached Set Server '.$setserver[0].' has too many parameters.');
|
||||
}
|
||||
$setservers[] = $setserver;
|
||||
}
|
||||
}
|
||||
|
||||
$isshared = false;
|
||||
if (isset($data->isshared)) {
|
||||
$isshared = $data->isshared;
|
||||
}
|
||||
|
||||
return array(
|
||||
'servers' => $servers,
|
||||
'compression' => $data->compression,
|
||||
'serialiser' => $data->serialiser,
|
||||
'prefix' => $data->prefix,
|
||||
'hash' => $data->hash,
|
||||
'bufferwrites' => $data->bufferwrites,
|
||||
'clustered' => $clustered,
|
||||
'setservers' => $setservers,
|
||||
'isshared' => $isshared
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$data = array();
|
||||
if (!empty($config['servers'])) {
|
||||
$servers = array();
|
||||
foreach ($config['servers'] as $server) {
|
||||
$servers[] = join(":", $server);
|
||||
}
|
||||
$data['servers'] = join("\n", $servers);
|
||||
}
|
||||
if (isset($config['compression'])) {
|
||||
$data['compression'] = (bool)$config['compression'];
|
||||
}
|
||||
if (!empty($config['serialiser'])) {
|
||||
$data['serialiser'] = $config['serialiser'];
|
||||
}
|
||||
if (!empty($config['prefix'])) {
|
||||
$data['prefix'] = $config['prefix'];
|
||||
}
|
||||
if (!empty($config['hash'])) {
|
||||
$data['hash'] = $config['hash'];
|
||||
}
|
||||
if (isset($config['bufferwrites'])) {
|
||||
$data['bufferwrites'] = (bool)$config['bufferwrites'];
|
||||
}
|
||||
if (isset($config['clustered'])) {
|
||||
$data['clustered'] = (bool)$config['clustered'];
|
||||
}
|
||||
if (!empty($config['setservers'])) {
|
||||
$servers = array();
|
||||
foreach ($config['setservers'] as $server) {
|
||||
$servers[] = join(":", $server);
|
||||
}
|
||||
$data['setservers'] = join("\n", $servers);
|
||||
}
|
||||
if (isset($config['isshared'])) {
|
||||
$data['isshared'] = $config['isshared'];
|
||||
}
|
||||
$editform->set_data($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs any necessary clean up when the store instance is being deleted.
|
||||
*/
|
||||
public function instance_deleted() {
|
||||
if ($this->connection) {
|
||||
$connection = $this->connection;
|
||||
} else {
|
||||
$connection = new Memcached(crc32($this->name));
|
||||
$servers = $connection->getServerList();
|
||||
if (empty($servers)) {
|
||||
foreach ($this->options as $key => $value) {
|
||||
$connection->setOption($key, $value);
|
||||
}
|
||||
$connection->addServers($this->servers);
|
||||
}
|
||||
}
|
||||
// We have to flush here to be sure we are completely cleaned up.
|
||||
// Bad for performance but this is incredibly rare.
|
||||
@$connection->flush();
|
||||
unset($connection);
|
||||
unset($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an instance of the cache store that can be used for testing.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return cachestore_memcached|false
|
||||
*/
|
||||
public static function initialise_test_instance(cache_definition $definition) {
|
||||
|
||||
if (!self::are_requirements_met()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$config = get_config('cachestore_memcached');
|
||||
if (empty($config->testservers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$configuration = array();
|
||||
$configuration['servers'] = explode("\n", $config->testservers);
|
||||
if (!empty($config->testcompression)) {
|
||||
$configuration['compression'] = $config->testcompression;
|
||||
}
|
||||
if (!empty($config->testserialiser)) {
|
||||
$configuration['serialiser'] = $config->testserialiser;
|
||||
}
|
||||
if (!empty($config->testprefix)) {
|
||||
$configuration['prefix'] = $config->testprefix;
|
||||
}
|
||||
if (!empty($config->testhash)) {
|
||||
$configuration['hash'] = $config->testhash;
|
||||
}
|
||||
if (!empty($config->testbufferwrites)) {
|
||||
$configuration['bufferwrites'] = $config->testbufferwrites;
|
||||
}
|
||||
if (!empty($config->testclustered)) {
|
||||
$configuration['clustered'] = $config->testclustered;
|
||||
}
|
||||
if (!empty($config->testsetservers)) {
|
||||
$configuration['setservers'] = explode("\n", $config->testsetservers);
|
||||
}
|
||||
if (!empty($config->testname)) {
|
||||
$name = $config->testname;
|
||||
} else {
|
||||
$name = 'Test memcached';
|
||||
}
|
||||
|
||||
$store = new cachestore_memcached($name, $configuration);
|
||||
// If store is ready then only initialise.
|
||||
if ($store->is_ready()) {
|
||||
$store->initialise($definition);
|
||||
}
|
||||
|
||||
return $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the appropriate configuration required for unit testing.
|
||||
*
|
||||
* @return array Array of unit test configuration data to be used by initialise().
|
||||
*/
|
||||
public static function unit_test_configuration() {
|
||||
// If the configuration is not defined correctly, return only the configuration know about.
|
||||
if (!defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS')) {
|
||||
return [];
|
||||
}
|
||||
return ['servers' => explode("\n", TEST_CACHESTORE_MEMCACHED_TESTSERVERS)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this instance.
|
||||
* @return string
|
||||
*/
|
||||
public function my_name() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to notify of configuration conflicts.
|
||||
*
|
||||
* The warnings returned here will be displayed on the cache configuration screen.
|
||||
*
|
||||
* @return string[] Returns an array of warnings (strings)
|
||||
*/
|
||||
public function get_warnings() {
|
||||
global $CFG;
|
||||
$warnings = array();
|
||||
if (isset($CFG->session_memcached_save_path) && count($this->servers)) {
|
||||
$bits = explode(':', $CFG->session_memcached_save_path, 3);
|
||||
$host = array_shift($bits);
|
||||
$port = (count($bits)) ? array_shift($bits) : '11211';
|
||||
|
||||
foreach ($this->servers as $server) {
|
||||
if ((string)$server[0] === $host && (string)$server[1] === $port) {
|
||||
$warnings[] = get_string('sessionhandlerconflict', 'cachestore_memcached', $this->my_name());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this cache store instance is both suitable for testing, and ready for testing.
|
||||
*
|
||||
* Cache stores that support being used as the default store for unit and acceptance testing should
|
||||
* override this function and return true if there requirements have been met.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function ready_to_be_used_for_testing() {
|
||||
return defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS');
|
||||
}
|
||||
}
|
33
cache/stores/memcached/settings.php
vendored
33
cache/stores/memcached/settings.php
vendored
@@ -1,33 +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/>.
|
||||
|
||||
/**
|
||||
* The settings for the memcached store.
|
||||
*
|
||||
* This file is part of the memcached cache store, it contains the API for interacting with an instance of the store.
|
||||
*
|
||||
* @package cachestore_memcached
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$settings->add(new admin_setting_configtextarea(
|
||||
'cachestore_memcached/testservers',
|
||||
new lang_string('testservers', 'cachestore_memcached'),
|
||||
new lang_string('testservers_desc', 'cachestore_memcached'),
|
||||
'', PARAM_RAW, 60, 3));
|
415
cache/stores/memcached/tests/store_test.php
vendored
415
cache/stores/memcached/tests/store_test.php
vendored
@@ -1,415 +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/>.
|
||||
|
||||
namespace cachestore_memcached;
|
||||
|
||||
use cache_definition;
|
||||
use cache_store;
|
||||
use cachestore_memcached;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// Include the necessary evils.
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot.'/cache/tests/fixtures/stores.php');
|
||||
require_once($CFG->dirroot.'/cache/stores/memcached/lib.php');
|
||||
|
||||
/**
|
||||
* Memcached unit test class.
|
||||
*
|
||||
* If you wish to use these unit tests all you need to do is add the following definition to
|
||||
* your config.php file.
|
||||
*
|
||||
* define('TEST_CACHESTORE_MEMCACHED_TESTSERVERS', '127.0.0.1:11211');
|
||||
*
|
||||
* @package cachestore_memcached
|
||||
* @copyright 2013 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class store_test extends \cachestore_tests {
|
||||
/**
|
||||
* Returns the memcached class name
|
||||
* @return string
|
||||
*/
|
||||
protected function get_class_name() {
|
||||
return 'cachestore_memcached';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the valid keys to ensure they work.
|
||||
*/
|
||||
public function test_valid_keys() {
|
||||
if (!cachestore_memcached::are_requirements_met() || !defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS')) {
|
||||
$this->markTestSkipped('Could not test cachestore_memcached. Requirements are not met.');
|
||||
}
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcached', 'phpunit_test');
|
||||
$instance = new cachestore_memcached('Memcached Test', cachestore_memcached::unit_test_configuration());
|
||||
|
||||
if (!$instance->is_ready()) {
|
||||
// Something prevented memcached store to be inited (extension, TEST_CACHESTORE_MEMCACHED_TESTSERVERS...).
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
$instance->initialise($definition);
|
||||
|
||||
$keys = array(
|
||||
// Alphanumeric.
|
||||
'abc', 'ABC', '123', 'aB1', '1aB',
|
||||
// Hyphens.
|
||||
'a-1', '1-a', '-a1', 'a1-',
|
||||
// Underscores.
|
||||
'a_1', '1_a', '_a1', 'a1_'
|
||||
);
|
||||
|
||||
// Set some keys.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue($instance->set($key, $key), "Failed to set key `$key`");
|
||||
}
|
||||
|
||||
// Get some keys.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertEquals($key, $instance->get($key), "Failed to get key `$key`");
|
||||
}
|
||||
|
||||
// Try get many.
|
||||
$values = $instance->get_many($keys);
|
||||
foreach ($values as $key => $value) {
|
||||
$this->assertEquals($key, $value);
|
||||
}
|
||||
|
||||
// Reset a key.
|
||||
$this->assertTrue($instance->set($keys[0], 'New'), "Failed to reset key `$key`");
|
||||
$this->assertEquals('New', $instance->get($keys[0]), "Failed to get reset key `$key`");
|
||||
|
||||
// Delete and check that we can't retrieve.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue($instance->delete($key), "Failed to delete key `$key`");
|
||||
$this->assertFalse($instance->get($key), "Retrieved deleted key `$key`");
|
||||
}
|
||||
|
||||
// Try set many, and check that count is correct.
|
||||
$many = array();
|
||||
foreach ($keys as $key) {
|
||||
$many[] = array('key' => $key, 'value' => $key);
|
||||
}
|
||||
$returncount = $instance->set_many($many);
|
||||
$this->assertEquals(count($many), $returncount, 'Set many count didn\'t match');
|
||||
|
||||
// Check keys retrieved with get_many.
|
||||
$values = $instance->get_many($keys);
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue(isset($values[$key]), "Failed to get_many key `$key`");
|
||||
$this->assertEquals($key, $values[$key], "Failed to match get_many key `$key`");
|
||||
}
|
||||
|
||||
// Delete many, make sure count matches.
|
||||
$returncount = $instance->delete_many($keys);
|
||||
$this->assertEquals(count($many), $returncount, 'Delete many count didn\'t match');
|
||||
|
||||
// Check that each key was deleted.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertFalse($instance->get($key), "Retrieved many deleted key `$key`");
|
||||
}
|
||||
|
||||
// Set the keys again.
|
||||
$returncount = $instance->set_many($many);
|
||||
$this->assertEquals(count($many), $returncount, 'Set many count didn\'t match');
|
||||
|
||||
// Purge.
|
||||
$this->assertTrue($instance->purge(), 'Failure to purge');
|
||||
|
||||
// Delete and check that we can't retrieve.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertFalse($instance->get($key), "Retrieved purged key `$key`");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the clustering feature.
|
||||
*/
|
||||
public function test_clustered() {
|
||||
if (!cachestore_memcached::are_requirements_met() || !defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS')) {
|
||||
$this->markTestSkipped('Could not test cachestore_memcached. Requirements are not met.');
|
||||
}
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$testservers = explode("\n", trim(TEST_CACHESTORE_MEMCACHED_TESTSERVERS));
|
||||
|
||||
if (count($testservers) < 2) {
|
||||
$this->markTestSkipped('Could not test clustered memcached, there are not enough test servers defined.');
|
||||
}
|
||||
|
||||
// Use the first server as our primary.
|
||||
// We need to set a prefix for all, otherwise it uses the name, which will not match between connections.
|
||||
set_config('testprefix', 'pre', 'cachestore_memcached');
|
||||
// We need to set a name, otherwise we get a reused connection.
|
||||
set_config('testname', 'cluster', 'cachestore_memcached');
|
||||
set_config('testservers', $testservers[0], 'cachestore_memcached');
|
||||
set_config('testsetservers', TEST_CACHESTORE_MEMCACHED_TESTSERVERS, 'cachestore_memcached');
|
||||
set_config('testclustered', true, 'cachestore_memcached');
|
||||
|
||||
// First and instance that we can use to test the second server.
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcached', 'phpunit_test');
|
||||
$instance = cachestore_memcached::initialise_test_instance($definition);
|
||||
|
||||
if (!$instance->is_ready()) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
// Now we are going to setup a connection to each independent server.
|
||||
set_config('testclustered', false, 'cachestore_memcached');
|
||||
set_config('testsetservers', '', 'cachestore_memcached');
|
||||
$checkinstances = array();
|
||||
foreach ($testservers as $testserver) {
|
||||
// We need to set a name, otherwise we get a reused connection.
|
||||
set_config('testname', $testserver, 'cachestore_memcached');
|
||||
set_config('testservers', $testserver, 'cachestore_memcached');
|
||||
$checkinstance = cachestore_memcached::initialise_test_instance($definition);
|
||||
if (!$checkinstance->is_ready()) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
$checkinstances[] = $checkinstance;
|
||||
}
|
||||
|
||||
$keys = array(
|
||||
// Alphanumeric.
|
||||
'abc', 'ABC', '123', 'aB1', '1aB',
|
||||
// Hyphens.
|
||||
'a-1', '1-a', '-a1', 'a1-',
|
||||
// Underscores.
|
||||
'a_1', '1_a', '_a1', 'a1_'
|
||||
);
|
||||
|
||||
// Set each key.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue($instance->set($key, $key), "Failed to set key `$key`");
|
||||
}
|
||||
|
||||
// Check each key.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertEquals($key, $instance->get($key), "Failed to get key `$key`");
|
||||
foreach ($checkinstances as $id => $checkinstance) {
|
||||
$this->assertEquals($key, $checkinstance->get($key), "Failed to get key `$key` from server $id");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset a key.
|
||||
$this->assertTrue($instance->set($keys[0], 'New'), "Failed to reset key `$key`");
|
||||
$this->assertEquals('New', $instance->get($keys[0]), "Failed to get reset key `$key`");
|
||||
foreach ($checkinstances as $id => $checkinstance) {
|
||||
$this->assertEquals('New', $checkinstance->get($keys[0]), "Failed to get reset key `$key` from server $id");
|
||||
}
|
||||
|
||||
// Delete and check that we can't retrieve.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue($instance->delete($key), "Failed to delete key `$key`");
|
||||
$this->assertFalse($instance->get($key), "Retrieved deleted key `$key`");
|
||||
foreach ($checkinstances as $id => $checkinstance) {
|
||||
$this->assertFalse($checkinstance->get($key), "Retrieved deleted key `$key` from server $id");
|
||||
}
|
||||
}
|
||||
|
||||
// Try set many, and check that count is correct.
|
||||
$many = array();
|
||||
foreach ($keys as $key) {
|
||||
$many[] = array('key' => $key, 'value' => $key);
|
||||
}
|
||||
$returncount = $instance->set_many($many);
|
||||
$this->assertEquals(count($many), $returncount, 'Set many count didn\'t match');
|
||||
|
||||
// Check keys retrieved with get_many.
|
||||
$values = $instance->get_many($keys);
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue(isset($values[$key]), "Failed to get_many key `$key`");
|
||||
$this->assertEquals($key, $values[$key], "Failed to match get_many key `$key`");
|
||||
}
|
||||
foreach ($checkinstances as $id => $checkinstance) {
|
||||
$values = $checkinstance->get_many($keys);
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue(isset($values[$key]), "Failed to get_many key `$key` from server $id");
|
||||
$this->assertEquals($key, $values[$key], "Failed to get_many key `$key` from server $id");
|
||||
}
|
||||
}
|
||||
|
||||
// Delete many, make sure count matches.
|
||||
$returncount = $instance->delete_many($keys);
|
||||
$this->assertEquals(count($many), $returncount, 'Delete many count didn\'t match');
|
||||
|
||||
// Check that each key was deleted.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertFalse($instance->get($key), "Retrieved many deleted key `$key`");
|
||||
foreach ($checkinstances as $id => $checkinstance) {
|
||||
$this->assertFalse($checkinstance->get($key), "Retrieved many deleted key `$key` from server $id");
|
||||
}
|
||||
}
|
||||
|
||||
// Set the keys again.
|
||||
$returncount = $instance->set_many($many);
|
||||
$this->assertEquals(count($many), $returncount, 'Set many count didn\'t match');
|
||||
|
||||
// Purge.
|
||||
$this->assertTrue($instance->purge(), 'Failure to purge');
|
||||
|
||||
// Delete and check that we can't retrieve.
|
||||
foreach ($keys as $key) {
|
||||
$this->assertFalse($instance->get($key), "Retrieved purged key `$key`");
|
||||
foreach ($checkinstances as $id => $checkinstance) {
|
||||
$this->assertFalse($checkinstance->get($key), "Retrieved purged key `$key` from server 2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that memcached cache store doesn't just flush everything and instead deletes only what belongs to it
|
||||
* when it is marked as a shared cache.
|
||||
*/
|
||||
public function test_multi_use_compatibility() {
|
||||
if (!cachestore_memcached::are_requirements_met() || !defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS')) {
|
||||
$this->markTestSkipped('Could not test cachestore_memcached. Requirements are not met.');
|
||||
}
|
||||
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcached', 'phpunit_test');
|
||||
$cachestore = $this->create_test_cache_with_config($definition, array('isshared' => true));
|
||||
if (!$cachestore->is_connection_ready()) {
|
||||
$this->markTestSkipped('Could not test cachestore_memcached. Connection is not ready.');
|
||||
}
|
||||
|
||||
$connection = new \Memcached(crc32(__METHOD__));
|
||||
$connection->addServers($this->get_servers(TEST_CACHESTORE_MEMCACHED_TESTSERVERS));
|
||||
$connection->setOptions(array(
|
||||
\Memcached::OPT_COMPRESSION => true,
|
||||
\Memcached::OPT_SERIALIZER => \Memcached::SERIALIZER_PHP,
|
||||
\Memcached::OPT_PREFIX_KEY => 'phpunit_',
|
||||
\Memcached::OPT_BUFFER_WRITES => false
|
||||
));
|
||||
|
||||
// We must flush first to make sure nothing is there.
|
||||
$connection->flush();
|
||||
|
||||
// Test the cachestore.
|
||||
$this->assertFalse($cachestore->get('test'));
|
||||
$this->assertTrue($cachestore->set('test', 'cachestore'));
|
||||
$this->assertSame('cachestore', $cachestore->get('test'));
|
||||
|
||||
// Test the connection.
|
||||
$this->assertFalse($connection->get('test'));
|
||||
$this->assertEquals(\Memcached::RES_NOTFOUND, $connection->getResultCode());
|
||||
$this->assertTrue($connection->set('test', 'connection'));
|
||||
$this->assertSame('connection', $connection->get('test'));
|
||||
|
||||
// Test both again and make sure the values are correct.
|
||||
$this->assertSame('cachestore', $cachestore->get('test'));
|
||||
$this->assertSame('connection', $connection->get('test'));
|
||||
|
||||
// Purge the cachestore and check the connection was not purged.
|
||||
$this->assertTrue($cachestore->purge());
|
||||
$this->assertFalse($cachestore->get('test'));
|
||||
$this->assertSame('connection', $connection->get('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that memcached cache store flushes entire cache when it is using a dedicated cache.
|
||||
*/
|
||||
public function test_dedicated_cache() {
|
||||
if (!cachestore_memcached::are_requirements_met() || !defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS')) {
|
||||
$this->markTestSkipped('Could not test cachestore_memcached. Requirements are not met.');
|
||||
}
|
||||
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcached', 'phpunit_test');
|
||||
$cachestore = $this->create_test_cache_with_config($definition, array('isshared' => false));
|
||||
$connection = new \Memcached(crc32(__METHOD__));
|
||||
$connection->addServers($this->get_servers(TEST_CACHESTORE_MEMCACHED_TESTSERVERS));
|
||||
$connection->setOptions(array(
|
||||
\Memcached::OPT_COMPRESSION => true,
|
||||
\Memcached::OPT_SERIALIZER => \Memcached::SERIALIZER_PHP,
|
||||
\Memcached::OPT_PREFIX_KEY => 'phpunit_',
|
||||
\Memcached::OPT_BUFFER_WRITES => false
|
||||
));
|
||||
|
||||
// We must flush first to make sure nothing is there.
|
||||
$connection->flush();
|
||||
|
||||
// Test the cachestore.
|
||||
$this->assertFalse($cachestore->get('test'));
|
||||
$this->assertTrue($cachestore->set('test', 'cachestore'));
|
||||
$this->assertSame('cachestore', $cachestore->get('test'));
|
||||
|
||||
// Test the connection.
|
||||
$this->assertFalse($connection->get('test'));
|
||||
$this->assertEquals(\Memcached::RES_NOTFOUND, $connection->getResultCode());
|
||||
$this->assertTrue($connection->set('test', 'connection'));
|
||||
$this->assertSame('connection', $connection->get('test'));
|
||||
|
||||
// Test both again and make sure the values are correct.
|
||||
$this->assertSame('cachestore', $cachestore->get('test'));
|
||||
$this->assertSame('connection', $connection->get('test'));
|
||||
|
||||
// Purge the cachestore and check the connection was also purged.
|
||||
$this->assertTrue($cachestore->purge());
|
||||
$this->assertFalse($cachestore->get('test'));
|
||||
$this->assertFalse($connection->get('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a server string this returns an array of servers.
|
||||
*
|
||||
* @param string $serverstring
|
||||
* @return array
|
||||
*/
|
||||
public function get_servers($serverstring) {
|
||||
$servers = array();
|
||||
foreach (explode("\n", $serverstring) as $server) {
|
||||
if (!is_array($server)) {
|
||||
$server = explode(':', $server, 3);
|
||||
}
|
||||
if (!array_key_exists(1, $server)) {
|
||||
$server[1] = 11211;
|
||||
$server[2] = 100;
|
||||
} else if (!array_key_exists(2, $server)) {
|
||||
$server[2] = 100;
|
||||
}
|
||||
$servers[] = $server;
|
||||
}
|
||||
return $servers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test instance for unit tests.
|
||||
* @param cache_definition $definition
|
||||
* @param array $configuration
|
||||
* @return null|cachestore_memcached
|
||||
*/
|
||||
private function create_test_cache_with_config(cache_definition $definition, $configuration = array()) {
|
||||
$class = $this->get_class_name();
|
||||
|
||||
if (!$class::are_requirements_met()) {
|
||||
return null;
|
||||
}
|
||||
if (!defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$configuration['servers'] = explode("\n", TEST_CACHESTORE_MEMCACHED_TESTSERVERS);
|
||||
|
||||
$store = new $class('Test memcached', $configuration);
|
||||
$store->initialise($definition);
|
||||
|
||||
return $store;
|
||||
}
|
||||
}
|
31
cache/stores/memcached/version.php
vendored
31
cache/stores/memcached/version.php
vendored
@@ -1,31 +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 memcached store version information.
|
||||
*
|
||||
* Not to be confused with the memcache plugin.
|
||||
*
|
||||
* @package cachestore_memcached
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$plugin->version = 2022112800; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2022111800; // Requires this Moodle version.
|
||||
$plugin->component = 'cachestore_memcached'; // Full name of the plugin.
|
2
cache/upgrade.txt
vendored
2
cache/upgrade.txt
vendored
@@ -1,5 +1,7 @@
|
||||
This files describes API changes in /cache/stores/* - cache store plugins.
|
||||
Information provided here is intended especially for developers.
|
||||
=== 4.2 ===
|
||||
* The memcached cachestore has been removed.
|
||||
|
||||
=== 4.1 ===
|
||||
* Added new `requirelockingbeforewrite` option for cache definitions. This will check that a lock for a given cache key already
|
||||
|
@@ -1729,7 +1729,7 @@ class core_plugin_manager {
|
||||
'qformat' => array('blackboard', 'learnwise', 'examview'),
|
||||
'auth' => array('radius', 'fc', 'nntp', 'pam', 'pop3', 'imap'),
|
||||
'block' => array('course_overview', 'messages', 'community', 'participants', 'quiz_results'),
|
||||
'cachestore' => array('memcache'),
|
||||
'cachestore' => array('memcache', 'memcached'),
|
||||
'enrol' => array('authorize'),
|
||||
'filter' => array('censor'),
|
||||
'media' => array('swf'),
|
||||
@@ -1821,7 +1821,7 @@ class core_plugin_manager {
|
||||
),
|
||||
|
||||
'cachestore' => array(
|
||||
'file', 'memcached', 'mongodb', 'session', 'static', 'apcu', 'redis'
|
||||
'file', 'mongodb', 'session', 'static', 'apcu', 'redis'
|
||||
),
|
||||
|
||||
'calendartype' => array(
|
||||
|
@@ -3072,5 +3072,16 @@ privatefiles,moodle|/user/files.php';
|
||||
upgrade_main_savepoint(true, 2023010300.00);
|
||||
}
|
||||
|
||||
if ($oldversion < 2023020700.00) {
|
||||
// If cachestore_memcached is no longer present, remove it.
|
||||
if (!file_exists($CFG->dirroot . '/cache/stores/memcached/version.php')) {
|
||||
// Clean config.
|
||||
unset_all_config_for_plugin('cachestore_memcached');
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2023020700.00);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -25,13 +25,6 @@ Feature: Breadcrumbs navigation
|
||||
Then I should see "Badges" in the ".breadcrumb" "css_element"
|
||||
And I should see "Manage backpacks" in the ".breadcrumb" "css_element"
|
||||
|
||||
Scenario: Admin user navigates to site adminsitrations plugins caching memcached page
|
||||
Given I log in as "admin"
|
||||
When I navigate to "Plugins > Caching > Cache stores > Memcached" in site administration
|
||||
Then I should see "Caching" in the ".breadcrumb" "css_element"
|
||||
Then I should see "Cache stores" in the ".breadcrumb" "css_element"
|
||||
And I should see "Memcached" in the ".breadcrumb" "css_element"
|
||||
|
||||
Scenario: Admin user changes the default home page and navigates to 'course category management' page
|
||||
Given the following config values are set as admin:
|
||||
| defaulthomepage | 3 |
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2023020300.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2023020700.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.2dev (Build: 20230203)'; // Human-friendly version name
|
||||
|
Reference in New Issue
Block a user