summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy2017-02-17 07:38:17 (GMT)
committerJeremy Andrews2017-02-17 07:38:17 (GMT)
commitde47520276da818487cb4766fb751d0d306d2d5f (patch)
tree04a5628694e6c6a3f79038742be8e8e3607e6c23
parent666a46015a6f4c728aeaccdeccdbd563027f3a65 (diff)
Issue #332094 by Jeremy, nirl, markpavlitski: Add support for server weight7.x-1.6-rc3
-rw-r--r--README.txt9
-rw-r--r--dmemcache.inc126
-rw-r--r--memcache-lock-code.inc11
-rw-r--r--memcache-lock.inc6
-rw-r--r--memcache.install32
-rw-r--r--memcache_admin/memcache_admin.module76
6 files changed, 152 insertions, 108 deletions
diff --git a/README.txt b/README.txt
index f978c56..7ba5d01 100644
--- a/README.txt
+++ b/README.txt
@@ -102,6 +102,15 @@ to $conf; memcache_servers and memcache_bins. The arrays follow this pattern:
binS => clusterS
)
+You can optionally assign a weight to each server, favoring one server more than
+another. For example, to make it 10 times more likely to store an item on
+server1 versus server2:
+
+'memcache_servers' => array(
+ server1:port => array('cluster' => cluster1, 'weight' => 10),
+ server2:port => array('cluster' => cluster2, 'weight' => 1'),
+)
+
The bin/cluster/server model can be described as follows:
- Servers are memcached instances identified by host:port.
diff --git a/dmemcache.inc b/dmemcache.inc
index 02df1cb..f598284 100644
--- a/dmemcache.inc
+++ b/dmemcache.inc
@@ -579,7 +579,17 @@ function dmemcache_stats($stats_bin = 'cache', $stats_type = 'default', $aggrega
// passed to the Memcache memcache_get_extended_stats() function.
elseif ($mc instanceof Memcache) {
if ($stats_type == 'default' || $stats_type == '') {
- $stats[$bin] = $mc->getExtendedStats();
+ $rc = $mc->getExtendedStats();
+ if (is_array($rc)) {
+ foreach ($rc as $server => $data) {
+ if (empty($data)) {
+ unset($rc[$server]);
+ }
+ }
+ if (!empty($rc)) {
+ $stats[$bin] = $rc;
+ }
+ }
}
// If $slab isn't zero, then we are dumping the contents of a
// specific cache slab.
@@ -777,14 +787,13 @@ function dmemcache_instance($bin = 'cache') {
* @param string $server
* A server string of the format "localhost:11211" or
* "unix:///path/to/socket".
- * @param bool $connection
- * TRUE or FALSE, whether the $memcache instance already has at least one
- * open connection.
+ * @param integer $weight
+ * Weighted probability of talking to this server.
*
* @return bool
* TRUE or FALSE if connection was successful.
*/
-function dmemcache_connect($memcache, $server, $connection) {
+function dmemcache_connect($memcache, $server, $weight) {
static $memcache_persistent = NULL;
$extension = dmemcache_extension();
@@ -798,8 +807,8 @@ function dmemcache_connect($memcache, $server, $connection) {
$memcache_persistent = variable_get('memcache_persistent', TRUE);
}
+ $port_error = FALSE;
if ($extension == 'Memcache') {
-
// Support unix sockets of the format 'unix:///path/to/socket'.
if ($host == 'unix') {
// Use full protocol and path as expected by Memcache extension.
@@ -807,31 +816,7 @@ function dmemcache_connect($memcache, $server, $connection) {
$port = 0;
}
else if (!isset($port)) {
- register_shutdown_function('watchdog', 'memcache', 'You have specified an invalid address of "!server" in settings.php which does not include a port. Please review README.txt for proper configuration. You must specify both a server address and port such as "!ip" or "!host", or a unix socket such as "!socket".', array('!server' => $server, '!ip' => t('127.0.0.1:11211'), '!host' => t('localhost:11211'), '!socket' => t('unix:///path/to/socket')), WATCHDOG_WARNING);
- }
-
- // When using the PECL memcache extension, we must use ->(p)connect
- // for the first connection.
- if (!$connection) {
- $track_errors = ini_set('track_errors', '1');
- $php_errormsg = '';
-
- // The Memcache extension requires us to use (p)connect for the first
- // server we connect to.
- if ($memcache_persistent) {
- $rc = @$memcache->pconnect($host, $port);
- }
- else {
- $rc = @$memcache->connect($host, $port);
- }
- if (!empty($php_errormsg)) {
- register_shutdown_function('watchdog', 'memcache', 'Exception caught in dmemcache_connect while connecting to !host:!port: !msg', array('!host' => $host, '!port' => $port, '!msg' => $php_errormsg), WATCHDOG_WARNING);
- $php_errormsg = '';
- }
- ini_set('track_errors', $track_errors);
- }
- else {
- $rc = $memcache->addServer($host, $port, $memcache_persistent);
+ $port_error = TRUE;
}
}
elseif ($extension == 'Memcached') {
@@ -842,27 +827,34 @@ function dmemcache_connect($memcache, $server, $connection) {
$port = 0;
}
else if (!isset($port)) {
- register_shutdown_function('watchdog', 'memcache', 'You have specified an invalid address of "!server" in settings.php which does not include a port. Please review README.txt for proper configuration. You must specify both a server address and port such as "!ip" or "!host", or a unix socket such as "!socket".', array('!server' => $server, '!ip' => t('127.0.0.1:11211'), '!host' => t('localhost:11211'), '!socket' => t('unix:///path/to/socket')), WATCHDOG_WARNING);
+ $port_error = TRUE;
}
+ }
+
+ if ($port_error) {
+ register_shutdown_function('watchdog', 'memcache', 'You have specified an invalid address of "!server" in settings.php which does not include a port. Please review README.txt for proper configuration. You must specify both a server address and port such as "!ip" or "!host", or a unix socket such as "!socket".', array('!server' => $server, '!ip' => t('127.0.0.1:11211'), '!host' => t('localhost:11211'), '!socket' => t('unix:///path/to/socket')), WATCHDOG_WARNING);
+ }
+
+ if ($extension == 'Memcache') {
+ $rc = $memcache->addServer($host, $port, $memcache_persistent, $weight);
+ }
+ elseif ($extension == 'Memcached') {
+ $match = FALSE;
if ($memcache_persistent) {
$servers = $memcache->getServerList();
- $match = FALSE;
foreach ($servers as $s) {
if ($s['host'] == $host && $s['port'] == $port) {
$match = TRUE;
break;
}
}
- if (!$match) {
- $rc = $memcache->addServer($host, $port);
- }
- else {
- $rc = TRUE;
- }
}
- else {
+ if (!$match) {
$rc = $memcache->addServer($host, $port);
}
+ else {
+ $rc = TRUE;
+ }
}
else {
$rc = FALSE;
@@ -946,22 +938,23 @@ function dmemcache_object($bin = NULL, $flush = FALSE) {
// Track whether or not we've opened any memcache connections.
$connection = FALSE;
-
// Link all the servers to this cluster.
- foreach ($memcache_servers as $server => $c) {
- if ($c == $cluster && !isset($failed_connections[$server])) {
- $rc = dmemcache_connect($memcache, $server, $connection);
- if ($rc !== FALSE) {
- // We've made at least one successful connection.
- $connection = TRUE;
- }
- else {
- // Memcache connection failure. We can't log to watchdog directly
- // because we're in an early Drupal bootstrap phase where watchdog
- // is non-functional. Instead, register a shutdown handler so it
- // gets recorded at the end of the page load.
- register_shutdown_function('watchdog', 'memcache', 'Failed to connect to memcache server: !server', array('!server' => $server), WATCHDOG_ERROR);
- $failed_connections[$server] = FALSE;
+ foreach ($memcache_servers as $server => $b) {
+ if ($c = dmemcache_object_cluster($b)) {
+ if ($c['cluster'] == $cluster && !isset($failed_connections[$server])) {
+ $rc = dmemcache_connect($memcache, $server, $c['weight'], $connection);
+ if ($rc) {
+ // We've made at least one connection.
+ $connection = TRUE;
+ }
+ else {
+ // Memcache connection failure. We can't log to watchdog directly
+ // because we're in an early Drupal bootstrap phase where watchdog
+ // is non-functional. Instead, register a shutdown handler so it
+ // gets recorded at the end of the page load.
+ register_shutdown_function('watchdog', 'memcache', 'Failed to connect to memcache server: !server', array('!server' => $server), WATCHDOG_ERROR);
+ $failed_connections[$server] = FALSE;
+ }
}
}
}
@@ -985,6 +978,29 @@ function dmemcache_object($bin = NULL, $flush = FALSE) {
}
/**
+ * Ensure that we're working with a proper cluster array.
+ */
+function dmemcache_object_cluster($cluster) {
+ if (!is_array($cluster)) {
+ // Set defaults.
+ $cluster = array(
+ 'cluster' => $cluster,
+ 'weight' => 1,
+ );
+ }
+ if (!isset($cluster['cluster']) || !is_string($cluster['cluster'])) {
+ // Cluster is required, complain if it's missing or invalid.
+ register_shutdown_function('watchdog', 'memcache', 'Ignoring invalid or missing cluster definition, review your memcache_servers configuration.', array(), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ if (!isset($cluster['weight']) || !is_int($cluster['weight']) || $cluster['weight'] < 1) {
+ // Weight is optional.
+ $cluster['weight'] = 1;
+ }
+ return $cluster;
+}
+
+/**
* Prefixes a key and ensures it is url safe.
*
* @param string $key
diff --git a/memcache-lock-code.inc b/memcache-lock-code.inc
index 5ebdb27..165e506 100644
--- a/memcache-lock-code.inc
+++ b/memcache-lock-code.inc
@@ -32,6 +32,17 @@ function lock_initialize() {
function lock_acquire($name, $timeout = 30) {
global $locks;
+ // Special case variable_init, as on memcache errors we can get stuck in an
+ // infinite loop.
+ static $variable_init = 0;
+ if ($name == 'variable_init') {
+ if ($variable_init > 25) {
+ register_shutdown_function('watchdog', 'memcache', 'Broke out of loop trying to grab lock for variable_init.');
+ return TRUE;
+ }
+ $variable_init++;
+ }
+
// Ensure that the timeout is at least 1 sec. This is a limitation
// imposed by memcached.
$timeout = (int) max($timeout, 1);
diff --git a/memcache-lock.inc b/memcache-lock.inc
index ef176df..7e3b3b6 100644
--- a/memcache-lock.inc
+++ b/memcache-lock.inc
@@ -12,7 +12,11 @@ require_once dirname(__FILE__) . '/dmemcache.inc';
// @todo get rid of this conditional include as soon as this is done:
// http://drupal.org/node/1225404
$lock_file = dirname(__FILE__) . '/memcache-lock-code.inc';
-if (!dmemcache_object('semaphore')) {
+$mc = dmemcache_object('semaphore');
+// dmemcache_object always returns TRUE, we don't need these stats but it forces
+// us to try and connect to memcache. If this fails, we can't store locks in
+// memcache.
+if (!$mc->getStats()) {
$lock_file = DRUPAL_ROOT . '/includes/lock.inc';
}
require_once $lock_file;
diff --git a/memcache.install b/memcache.install
index 91b7a68..aee97dc 100644
--- a/memcache.install
+++ b/memcache.install
@@ -31,13 +31,15 @@ function memcache_enable() {
// Make a test connection to all configured memcache servers.
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
foreach ($memcache_servers as $server => $bin) {
- $memcache = dmemcache_instance($bin);
- if (dmemcache_connect($memcache, $server, FALSE) === FALSE) {
- $error = TRUE;
- }
- else {
- if (!variable_get('memcache_persistent', TRUE)) {
- dmemcache_close($memcache);
+ if ($cluster = dmemcache_object_cluster($bin)) {
+ $memcache = dmemcache_instance($cluster['cluster']);
+ if (dmemcache_connect($memcache, $server, $cluster['weight']) === FALSE) {
+ $error = TRUE;
+ }
+ else {
+ if (!variable_get('memcache_persistent', TRUE)) {
+ dmemcache_close($memcache);
+ }
}
}
}
@@ -114,13 +116,15 @@ function memcache_requirements($phase) {
// Make a test connection to all configured memcache servers.
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
foreach ($memcache_servers as $server => $bin) {
- $memcache = dmemcache_instance($bin);
- if (dmemcache_connect($memcache, $server, FALSE) === FALSE) {
- $errors[] = $t('Failed to connect to memcached server instance at %server.', array('%server' => $server));
- }
- else {
- if (!variable_get('memcache_persistent', TRUE)) {
- dmemcache_close($memcache);
+ if ($cluster = dmemcache_object_cluster($bin)) {
+ $memcache = dmemcache_instance($cluster['cluster']);
+ if (dmemcache_connect($memcache, $server, $cluster['weight']) === FALSE) {
+ $errors[] = $t('Failed to connect to memcached server instance at %server.', array('%server' => $server));
+ }
+ else {
+ if (!variable_get('memcache_persistent', TRUE)) {
+ dmemcache_close($memcache);
+ }
}
}
}
diff --git a/memcache_admin/memcache_admin.module b/memcache_admin/memcache_admin.module
index 5ac5bc8..b4c12ac 100644
--- a/memcache_admin/memcache_admin.module
+++ b/memcache_admin/memcache_admin.module
@@ -59,9 +59,11 @@ function memcache_admin_menu() {
);
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
$clusters = array();
- foreach ($memcache_servers as $server => $cluster) {
- $clusters[$cluster]['servers'][] = $server;
- $clusters[$cluster]['bin'] = _memcache_admin_get_bin_for_cluster($cluster);
+ foreach ($memcache_servers as $server => $bin) {
+ if ($cluster = dmemcache_object_cluster($bin)) {
+ $clusters[$cluster]['servers'][] = $server;
+ $clusters[$cluster]['bin'] = _memcache_admin_get_bin_for_cluster($cluster['cluster']);
+ }
}
$count = 0;
@@ -272,47 +274,45 @@ function memcache_admin_stats($bin = 'default') {
$output = '';
$server = array();
$stats = dmemcache_stats($bin, 'default', TRUE);
- if (empty($stats)) {
+ if (empty($stats[$bin])) {
// Failed to load statistics. Provide a useful error about where to get
// more information and help.
- drupal_set_message(t('There may be a problem with your Memcache configuration. Please review %readme and !more for more information.', array('%readme' => 'README.txt', 'admin/reports/status', '!more' => module_exists('memcache') ? t('visit the Drupal admin !status page', array('!status' => l(t('status report'), 'admin/reports/status'))) : t('!enable the memcache module', array('!enable' => l(t('enable'), 'admin/modules', array('fragment' => 'edit-modules-performance-and-scalability')))))), 'error');
+ drupal_set_message(t('Failed to retreive statistics. There may be a problem with your Memcache configuration. Please review %readme and !more for more information.', array('%readme' => 'README.txt', 'admin/reports/status', '!more' => module_exists('memcache') ? t('visit the Drupal admin !status page', array('!status' => l(t('status report'), 'admin/reports/status'))) : t('!enable the memcache module', array('!enable' => l(t('enable'), 'admin/modules', array('fragment' => 'edit-modules-performance-and-scalability')))))), 'error');
}
else {
- if (count($stats[$bin])) {
- $stats = $stats[$bin];
- $aggregate = array_pop($stats);
- $mc = dmemcache_object($bin);
- if ($mc instanceof Memcached) {
- $version = t('Memcached v!version', array('!version' => phpversion('Memcached')));
- }
- elseif ($mc instanceof Memcache) {
- $version = t('Memcache v!version', array('!version' => phpversion('Memcache')));
+ $stats = $stats[$bin];
+ $aggregate = array_pop($stats);
+ $mc = dmemcache_object($bin);
+ if ($mc instanceof Memcached) {
+ $version = t('Memcached v!version', array('!version' => phpversion('Memcached')));
+ }
+ elseif ($mc instanceof Memcache) {
+ $version = t('Memcache v!version', array('!version' => phpversion('Memcache')));
+ }
+ else {
+ $version = t('Unknown');
+ drupal_set_message(t('Failed to detect the memcache PECL extension.'), 'error');
+ }
+ $memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
+
+ foreach ($stats as $server => $statistics) {
+ if (empty($statistics['uptime'])) {
+ drupal_set_message(t('Failed to connect to server at %address.', array('%address' => $server)), 'error');
}
else {
- $version = t('Unknown');
- drupal_set_message(t('Failed to detect the memcache PECL extension.'), 'error');
- }
- $memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
-
- foreach ($stats as $server => $statistics) {
- if (empty($statistics['uptime'])) {
- drupal_set_message(t('Failed to connect to server at %address.', array('%address' => $server)), 'error');
- }
- else {
- $servers[] = $server;
- $data['server_overview'][$server] = t('v!version running !uptime', array('!version' => check_plain($statistics['version']), '!uptime' => format_interval($statistics['uptime'])));
- $data['server_pecl'][$server] = t('n/a');
- $data['server_serialize'][$server] = t('n/a');
- $data['server_time'][$server] = format_date($statistics['time']);
- $data['server_connections'][$server] = _memcache_admin_stats_connections($statistics);
- $data['cache_sets'][$server] = _memcache_admin_stats_sets($statistics);
- $data['cache_gets'][$server] = _memcache_admin_stats_gets($statistics);
- $data['cache_counters'][$server] = _memcache_admin_stats_counters($statistics);
- $data['cache_transfer'][$server] = _memcache_admin_stats_transfer($statistics);
- $data['cache_average'][$server] = _memcache_admin_stats_average($statistics);
- $data['memory_available'][$server] = _memcache_admin_stats_memory($statistics);
- $data['memory_evictions'][$server] = number_format($statistics['evictions']);
- }
+ $servers[] = $server;
+ $data['server_overview'][$server] = t('v!version running !uptime', array('!version' => check_plain($statistics['version']), '!uptime' => format_interval($statistics['uptime'])));
+ $data['server_pecl'][$server] = t('n/a');
+ $data['server_serialize'][$server] = t('n/a');
+ $data['server_time'][$server] = format_date($statistics['time']);
+ $data['server_connections'][$server] = _memcache_admin_stats_connections($statistics);
+ $data['cache_sets'][$server] = _memcache_admin_stats_sets($statistics);
+ $data['cache_gets'][$server] = _memcache_admin_stats_gets($statistics);
+ $data['cache_counters'][$server] = _memcache_admin_stats_counters($statistics);
+ $data['cache_transfer'][$server] = _memcache_admin_stats_transfer($statistics);
+ $data['cache_average'][$server] = _memcache_admin_stats_average($statistics);
+ $data['memory_available'][$server] = _memcache_admin_stats_memory($statistics);
+ $data['memory_evictions'][$server] = number_format($statistics['evictions']);
}
}