Skip to content

Commit

Permalink
Merge branch 'MDL-42071_MK3' of https://github.com/merrill-oakland/mo…
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Hemelryk committed Jun 30, 2014
2 parents a014556 + 7abaa5f commit 21e57e8
Show file tree
Hide file tree
Showing 10 changed files with 773 additions and 10 deletions.
44 changes: 44 additions & 0 deletions cache/stores/memcache/addinstanceform.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,49 @@ protected function configuration_definition() {
$form->setType('prefix', PARAM_TEXT); // We set to text but we have a rule to limit to alphanumext.
$form->setDefault('prefix', 'mdl_');
$form->addRule('prefix', get_string('prefixinvalid', 'cachestore_memcache'), 'regex', '#^[a-zA-Z0-9\-_]+$#');

$form->addElement('header', 'clusteredheader', get_string('clustered', 'cachestore_memcache'));

$form->addElement('checkbox', 'clustered', get_string('clustered', 'cachestore_memcache'));
$form->setDefault('checkbox', false);
$form->addHelpButton('clustered', 'clustered', 'cachestore_memcache');

$form->addElement('textarea', 'setservers', get_string('setservers', 'cachestore_memcache'),
array('cols' => 75, 'rows' => 5));
$form->addHelpButton('setservers', 'setservers', 'cachestore_memcache');
$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']) || empty(trim($data['setservers']))) {
$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_memcache');
}
}

return $errors;
}
}
21 changes: 21 additions & 0 deletions cache/stores/memcache/lang/en/cachestore_memcache.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@

defined('MOODLE_INTERNAL') || die();

$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['pluginname'] = 'Memcache';
$string['prefix'] = 'Key prefix';
$string['prefix_help'] = 'This prefix is used for all key names on the memcache server.
Expand All @@ -42,6 +49,20 @@
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 manchine, 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 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['testservers'] = 'Test servers';
$string['testservers_desc'] = 'The test servers get used for unit tests and for performance tests. It is entirely optional to set up test servers. Servers should be defined one per line and consist of a server address and optionally a port and weight.
Expand Down
119 changes: 117 additions & 2 deletions cache/stores/memcache/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
*/
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();

/**
* Default prefix for key names.
* @var string
Expand Down Expand Up @@ -123,6 +141,30 @@ public function __construct($name, array $configuration = array()) {
}
$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;
}
}

if (empty($configuration['prefix'])) {
$this->prefix = self::DEFAULT_PREFIX;
} else {
Expand All @@ -133,6 +175,16 @@ public function __construct($name, array $configuration = array()) {
foreach ($this->servers as $server) {
$this->connection->addServer($server[0], (int) $server[1], true, (int) $server[2]);
}

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 Memcache;
$connection->addServer($setserver[0], $setserver[1]);
$this->setconnections[] = $connection;
}
}

// Test the connection to the pool of servers.
$this->isready = @$this->connection->set($this->parse_key('ping'), 'ping', MEMCACHE_COMPRESSED, 1);
}
Expand Down Expand Up @@ -280,6 +332,15 @@ public function get_many($keys) {
* @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($this->parse_key($key), $data, MEMCACHE_COMPRESSED, $this->definition->get_ttl())
&& $status;
}
return $status;
}

return $this->connection->set($this->parse_key($key), $data, MEMCACHE_COMPRESSED, $this->definition->get_ttl());
}

Expand All @@ -294,7 +355,7 @@ public function set($key, $data) {
public function set_many(array $keyvaluearray) {
$count = 0;
foreach ($keyvaluearray as $pair) {
if ($this->connection->set($this->parse_key($pair['key']), $pair['value'], MEMCACHE_COMPRESSED, $this->definition->get_ttl())) {
if ($this->set($pair['key'], $pair['value'])) {
$count++;
}
}
Expand All @@ -308,6 +369,14 @@ public function set_many(array $keyvaluearray) {
* @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($this->parse_key($key)) && $status;
}
return $status;
}

return $this->connection->delete($this->parse_key($key));
}

Expand All @@ -334,7 +403,13 @@ public function delete_many(array $keys) {
*/
public function purge() {
if ($this->isready) {
$this->connection->flush();
if ($this->clustered) {
foreach ($this->setconnections as $connection) {
$connection->flush();
}
} else {
$this->connection->flush();
}
}

return true;
Expand All @@ -358,9 +433,33 @@ public static function config_get_configuration_array($data) {
}
$servers[] = explode(':', $line, 3);
}

$clustered = false;
if (isset($data->clustered)) {
$clustered = true;
}

$lines = explode("\n", $data->setservers);
$setservers = array();
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('Memcache Set Server '.$setserver[0].' has too many parameters.');
}
$setservers[] = $setserver;
}

return array(
'servers' => $servers,
'prefix' => $data->prefix,
'clustered' => $clustered,
'setservers' => $setservers
);
}

Expand All @@ -384,6 +483,16 @@ public static function config_set_edit_form_data(moodleform $editform, array $co
} else {
$data['prefix'] = self::DEFAULT_PREFIX;
}
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);
}

$editform->set_data($data);
}
Expand Down Expand Up @@ -423,6 +532,12 @@ public static function initialise_test_instance(cache_definition $definition) {

$configuration = array();
$configuration['servers'] = explode("\n", $config->testservers);
if (!empty($config->testclustered)) {
$configuration['clustered'] = $config->testclustered;
}
if (!empty($config->testsetservers)) {
$configuration['setservers'] = explode("\n", $config->testsetservers);
}

$store = new cachestore_memcache('Test memcache', $configuration);
$store->initialise($definition);
Expand Down
2 changes: 1 addition & 1 deletion cache/stores/memcache/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
'cachestore_memcache/testservers',
new lang_string('testservers', 'cachestore_memcache'),
new lang_string('testservers_desc', 'cachestore_memcache'),
'', PARAM_RAW, 60, 3));
'', PARAM_RAW, 60, 3));
Loading

0 comments on commit 21e57e8

Please sign in to comment.