mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-48506 cachestore_memcached: added shared cache config option
When added a memcached instance you can now select whether the cache is being shared by other applications. The setting will determine the purging strategy. Shared caches will have individual keys deleted while dedicated caches will have the entire cache purged (better performance over networks). Note: This option only works with the correct version of the php memcached extension and with the multi-site safe changes.
This commit is contained in:
parent
7797d7ead0
commit
33688fbfe6
14
cache/stores/memcached/addinstanceform.php
vendored
14
cache/stores/memcached/addinstanceform.php
vendored
@ -42,6 +42,8 @@ class cachestore_memcached_addinstance_form extends cachestore_addinstance_form
|
||||
*/
|
||||
protected function configuration_definition() {
|
||||
$form = $this->_form;
|
||||
$version = phpversion('memcached');
|
||||
$hasrequiredversion = ($version || version_compare($version, cachestore_memcached::REQUIRED_VERSION, '>='));
|
||||
|
||||
$form->addElement('textarea', 'servers', get_string('servers', 'cachestore_memcached'), array('cols' => 75, 'rows' => 5));
|
||||
$form->addHelpButton('servers', 'servers', 'cachestore_memcached');
|
||||
@ -75,6 +77,15 @@ class cachestore_memcached_addinstance_form extends cachestore_addinstance_form
|
||||
$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'));
|
||||
@ -87,8 +98,7 @@ class cachestore_memcached_addinstance_form extends cachestore_addinstance_form
|
||||
$form->disabledIf('setservers', 'clustered');
|
||||
$form->setType('setservers', PARAM_RAW);
|
||||
|
||||
$version = phpversion('memcached');
|
||||
if (!$version || !version_compare($version, cachestore_memcached::REQUIRED_VERSION, '>=')) {
|
||||
if (!$hasrequiredversion) {
|
||||
$form->addElement('header', 'upgradenotice', get_string('notice', 'cachestore_memcached'));
|
||||
$form->setExpanded('upgradenotice');
|
||||
$form->addElement('html', nl2br(get_string('upgrade200recommended', 'cachestore_memcached')));
|
||||
|
@ -46,6 +46,13 @@ $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['notice'] = 'Notice';
|
||||
$string['pluginname'] = 'Memcached';
|
||||
$string['prefix'] = 'Prefix key';
|
||||
|
29
cache/stores/memcached/lib.php
vendored
29
cache/stores/memcached/lib.php
vendored
@ -124,11 +124,11 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
protected $candeletemulti = false;
|
||||
|
||||
/**
|
||||
* True if Memcached::getAllKeys can be used, false otherwise.
|
||||
* True if the memcached server is shared, false otherwise.
|
||||
* This required extension version 2.0.0 or greater.
|
||||
* @var bool
|
||||
*/
|
||||
protected $cangetallkeys = false;
|
||||
protected $isshared = false;
|
||||
|
||||
/**
|
||||
* Constructs the store instance.
|
||||
@ -222,9 +222,12 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($configuration['isshared'])) {
|
||||
$this->isshared = $configuration['isshared'];
|
||||
}
|
||||
|
||||
$version = phpversion('memcached');
|
||||
$this->candeletemulti = ($version && version_compare($version, self::REQUIRED_VERSION, '>='));
|
||||
$this->cangetallkeys = $this->candeletemulti;
|
||||
|
||||
// Test the connection to the main connection.
|
||||
$this->isready = @$this->connection->set("ping", 'ping', 1);
|
||||
@ -469,9 +472,13 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
*/
|
||||
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 ($this->candeletemulti && $this->cangetallkeys) {
|
||||
if ($candeletemulti) {
|
||||
$keys = self::get_prefixed_keys($connection, $this->prefix);
|
||||
$connection->deleteMulti($keys);
|
||||
} else {
|
||||
@ -479,7 +486,7 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
$connection->flush();
|
||||
}
|
||||
}
|
||||
} else if ($this->candeletemulti && $this->cangetallkeys) {
|
||||
} else if ($candeletemulti) {
|
||||
$keys = self::get_prefixed_keys($this->connection, $this->prefix);
|
||||
$this->connection->deleteMulti($keys);
|
||||
} else {
|
||||
@ -495,7 +502,6 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
* 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.
|
||||
* You should always check $this->cangetallkeys before calling this.
|
||||
*
|
||||
* @param Memcached $connection
|
||||
* @param string $prefix
|
||||
@ -588,6 +594,11 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
}
|
||||
}
|
||||
|
||||
$isshared = false;
|
||||
if (isset($data->isshared)) {
|
||||
$isshared = $data->isshared;
|
||||
}
|
||||
|
||||
return array(
|
||||
'servers' => $servers,
|
||||
'compression' => $data->compression,
|
||||
@ -596,7 +607,8 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
'hash' => $data->hash,
|
||||
'bufferwrites' => $data->bufferwrites,
|
||||
'clustered' => $clustered,
|
||||
'setservers' => $setservers
|
||||
'setservers' => $setservers,
|
||||
'isshared' => $isshared
|
||||
);
|
||||
}
|
||||
|
||||
@ -640,6 +652,9 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
}
|
||||
$data['setservers'] = join("\n", $servers);
|
||||
}
|
||||
if (isset($config['isshared'])) {
|
||||
$data['isshared'] = $config['isshared'];
|
||||
}
|
||||
$editform->set_data($data);
|
||||
}
|
||||
|
||||
|
72
cache/stores/memcached/tests/memcached_test.php
vendored
72
cache/stores/memcached/tests/memcached_test.php
vendored
@ -276,7 +276,8 @@ class cachestore_memcached_test extends cachestore_tests {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that memcached cache store doesn't just flush everything and instead deletes only what belongs to it.
|
||||
* 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')) {
|
||||
@ -284,7 +285,7 @@ class cachestore_memcached_test extends cachestore_tests {
|
||||
}
|
||||
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcached', 'phpunit_test');
|
||||
$cachestore = cachestore_memcached::initialise_unit_test_instance($definition);
|
||||
$cachestore = $this->create_test_cache_with_config($definition, array('isshared' => true));
|
||||
$connection = new Memcached(crc32(__METHOD__));
|
||||
$connection->addServers($this->get_servers(TEST_CACHESTORE_MEMCACHED_TESTSERVERS));
|
||||
$connection->setOptions(array(
|
||||
@ -318,6 +319,49 @@ class cachestore_memcached_test extends cachestore_tests {
|
||||
$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.
|
||||
*
|
||||
@ -340,4 +384,28 @@ class cachestore_memcached_test extends cachestore_tests {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
2
cache/upgrade.txt
vendored
2
cache/upgrade.txt
vendored
@ -6,8 +6,6 @@ Information provided here is intended especially for developers.
|
||||
This allows the cache loader to decide if it needs to handle dereferencing or whether the data
|
||||
coming directly to it has already had references resolved.
|
||||
- see supports_dereferencing_objects in store.php.
|
||||
* The Memcached cache store no longer flushes the memcache servers it is connected to providing your memcached php extension is version 2.0.0 or greater.
|
||||
There is a notice to this effect when adding or editing a memcached cache store instance.
|
||||
|
||||
=== 2.9 ===
|
||||
* Cache data source aggregation functionality has been removed. This functionality was found to be broken and unused.
|
||||
|
Loading…
x
Reference in New Issue
Block a user