Skip to content

Commit de47520

Browse files
JeremyJeremy Andrews
Jeremy
authored and
Jeremy Andrews
committed
Issue #332094 by Jeremy, nirl, markpavlitski: Add support for server weight
1 parent 666a460 commit de47520

File tree

6 files changed

+152
-108
lines changed

6 files changed

+152
-108
lines changed

README.txt

+9
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ to $conf; memcache_servers and memcache_bins. The arrays follow this pattern:
102102
binS => clusterS
103103
)
104104

105+
You can optionally assign a weight to each server, favoring one server more than
106+
another. For example, to make it 10 times more likely to store an item on
107+
server1 versus server2:
108+
109+
'memcache_servers' => array(
110+
server1:port => array('cluster' => cluster1, 'weight' => 10),
111+
server2:port => array('cluster' => cluster2, 'weight' => 1'),
112+
)
113+
105114
The bin/cluster/server model can be described as follows:
106115

107116
- Servers are memcached instances identified by host:port.

dmemcache.inc

+71-55
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,17 @@ function dmemcache_stats($stats_bin = 'cache', $stats_type = 'default', $aggrega
579579
// passed to the Memcache memcache_get_extended_stats() function.
580580
elseif ($mc instanceof Memcache) {
581581
if ($stats_type == 'default' || $stats_type == '') {
582-
$stats[$bin] = $mc->getExtendedStats();
582+
$rc = $mc->getExtendedStats();
583+
if (is_array($rc)) {
584+
foreach ($rc as $server => $data) {
585+
if (empty($data)) {
586+
unset($rc[$server]);
587+
}
588+
}
589+
if (!empty($rc)) {
590+
$stats[$bin] = $rc;
591+
}
592+
}
583593
}
584594
// If $slab isn't zero, then we are dumping the contents of a
585595
// specific cache slab.
@@ -777,14 +787,13 @@ function dmemcache_instance($bin = 'cache') {
777787
* @param string $server
778788
* A server string of the format "localhost:11211" or
779789
* "unix:///path/to/socket".
780-
* @param bool $connection
781-
* TRUE or FALSE, whether the $memcache instance already has at least one
782-
* open connection.
790+
* @param integer $weight
791+
* Weighted probability of talking to this server.
783792
*
784793
* @return bool
785794
* TRUE or FALSE if connection was successful.
786795
*/
787-
function dmemcache_connect($memcache, $server, $connection) {
796+
function dmemcache_connect($memcache, $server, $weight) {
788797
static $memcache_persistent = NULL;
789798

790799
$extension = dmemcache_extension();
@@ -798,40 +807,16 @@ function dmemcache_connect($memcache, $server, $connection) {
798807
$memcache_persistent = variable_get('memcache_persistent', TRUE);
799808
}
800809

810+
$port_error = FALSE;
801811
if ($extension == 'Memcache') {
802-
803812
// Support unix sockets of the format 'unix:///path/to/socket'.
804813
if ($host == 'unix') {
805814
// Use full protocol and path as expected by Memcache extension.
806815
$host = $server;
807816
$port = 0;
808817
}
809818
else if (!isset($port)) {
810-
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);
811-
}
812-
813-
// When using the PECL memcache extension, we must use ->(p)connect
814-
// for the first connection.
815-
if (!$connection) {
816-
$track_errors = ini_set('track_errors', '1');
817-
$php_errormsg = '';
818-
819-
// The Memcache extension requires us to use (p)connect for the first
820-
// server we connect to.
821-
if ($memcache_persistent) {
822-
$rc = @$memcache->pconnect($host, $port);
823-
}
824-
else {
825-
$rc = @$memcache->connect($host, $port);
826-
}
827-
if (!empty($php_errormsg)) {
828-
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);
829-
$php_errormsg = '';
830-
}
831-
ini_set('track_errors', $track_errors);
832-
}
833-
else {
834-
$rc = $memcache->addServer($host, $port, $memcache_persistent);
819+
$port_error = TRUE;
835820
}
836821
}
837822
elseif ($extension == 'Memcached') {
@@ -842,27 +827,34 @@ function dmemcache_connect($memcache, $server, $connection) {
842827
$port = 0;
843828
}
844829
else if (!isset($port)) {
845-
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);
830+
$port_error = TRUE;
846831
}
832+
}
833+
834+
if ($port_error) {
835+
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);
836+
}
837+
838+
if ($extension == 'Memcache') {
839+
$rc = $memcache->addServer($host, $port, $memcache_persistent, $weight);
840+
}
841+
elseif ($extension == 'Memcached') {
842+
$match = FALSE;
847843
if ($memcache_persistent) {
848844
$servers = $memcache->getServerList();
849-
$match = FALSE;
850845
foreach ($servers as $s) {
851846
if ($s['host'] == $host && $s['port'] == $port) {
852847
$match = TRUE;
853848
break;
854849
}
855850
}
856-
if (!$match) {
857-
$rc = $memcache->addServer($host, $port);
858-
}
859-
else {
860-
$rc = TRUE;
861-
}
862851
}
863-
else {
852+
if (!$match) {
864853
$rc = $memcache->addServer($host, $port);
865854
}
855+
else {
856+
$rc = TRUE;
857+
}
866858
}
867859
else {
868860
$rc = FALSE;
@@ -946,22 +938,23 @@ function dmemcache_object($bin = NULL, $flush = FALSE) {
946938

947939
// Track whether or not we've opened any memcache connections.
948940
$connection = FALSE;
949-
950941
// Link all the servers to this cluster.
951-
foreach ($memcache_servers as $server => $c) {
952-
if ($c == $cluster && !isset($failed_connections[$server])) {
953-
$rc = dmemcache_connect($memcache, $server, $connection);
954-
if ($rc !== FALSE) {
955-
// We've made at least one successful connection.
956-
$connection = TRUE;
957-
}
958-
else {
959-
// Memcache connection failure. We can't log to watchdog directly
960-
// because we're in an early Drupal bootstrap phase where watchdog
961-
// is non-functional. Instead, register a shutdown handler so it
962-
// gets recorded at the end of the page load.
963-
register_shutdown_function('watchdog', 'memcache', 'Failed to connect to memcache server: !server', array('!server' => $server), WATCHDOG_ERROR);
964-
$failed_connections[$server] = FALSE;
942+
foreach ($memcache_servers as $server => $b) {
943+
if ($c = dmemcache_object_cluster($b)) {
944+
if ($c['cluster'] == $cluster && !isset($failed_connections[$server])) {
945+
$rc = dmemcache_connect($memcache, $server, $c['weight'], $connection);
946+
if ($rc) {
947+
// We've made at least one connection.
948+
$connection = TRUE;
949+
}
950+
else {
951+
// Memcache connection failure. We can't log to watchdog directly
952+
// because we're in an early Drupal bootstrap phase where watchdog
953+
// is non-functional. Instead, register a shutdown handler so it
954+
// gets recorded at the end of the page load.
955+
register_shutdown_function('watchdog', 'memcache', 'Failed to connect to memcache server: !server', array('!server' => $server), WATCHDOG_ERROR);
956+
$failed_connections[$server] = FALSE;
957+
}
965958
}
966959
}
967960
}
@@ -984,6 +977,29 @@ function dmemcache_object($bin = NULL, $flush = FALSE) {
984977
return empty($memcache_cache[$bin]) ? FALSE : $memcache_cache[$bin];
985978
}
986979

980+
/**
981+
* Ensure that we're working with a proper cluster array.
982+
*/
983+
function dmemcache_object_cluster($cluster) {
984+
if (!is_array($cluster)) {
985+
// Set defaults.
986+
$cluster = array(
987+
'cluster' => $cluster,
988+
'weight' => 1,
989+
);
990+
}
991+
if (!isset($cluster['cluster']) || !is_string($cluster['cluster'])) {
992+
// Cluster is required, complain if it's missing or invalid.
993+
register_shutdown_function('watchdog', 'memcache', 'Ignoring invalid or missing cluster definition, review your memcache_servers configuration.', array(), WATCHDOG_ERROR);
994+
return FALSE;
995+
}
996+
if (!isset($cluster['weight']) || !is_int($cluster['weight']) || $cluster['weight'] < 1) {
997+
// Weight is optional.
998+
$cluster['weight'] = 1;
999+
}
1000+
return $cluster;
1001+
}
1002+
9871003
/**
9881004
* Prefixes a key and ensures it is url safe.
9891005
*

memcache-lock-code.inc

+11
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ function lock_initialize() {
3232
function lock_acquire($name, $timeout = 30) {
3333
global $locks;
3434

35+
// Special case variable_init, as on memcache errors we can get stuck in an
36+
// infinite loop.
37+
static $variable_init = 0;
38+
if ($name == 'variable_init') {
39+
if ($variable_init > 25) {
40+
register_shutdown_function('watchdog', 'memcache', 'Broke out of loop trying to grab lock for variable_init.');
41+
return TRUE;
42+
}
43+
$variable_init++;
44+
}
45+
3546
// Ensure that the timeout is at least 1 sec. This is a limitation
3647
// imposed by memcached.
3748
$timeout = (int) max($timeout, 1);

memcache-lock.inc

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ require_once dirname(__FILE__) . '/dmemcache.inc';
1212
// @todo get rid of this conditional include as soon as this is done:
1313
// http://drupal.org/node/1225404
1414
$lock_file = dirname(__FILE__) . '/memcache-lock-code.inc';
15-
if (!dmemcache_object('semaphore')) {
15+
$mc = dmemcache_object('semaphore');
16+
// dmemcache_object always returns TRUE, we don't need these stats but it forces
17+
// us to try and connect to memcache. If this fails, we can't store locks in
18+
// memcache.
19+
if (!$mc->getStats()) {
1620
$lock_file = DRUPAL_ROOT . '/includes/lock.inc';
1721
}
1822
require_once $lock_file;

memcache.install

+18-14
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ function memcache_enable() {
3131
// Make a test connection to all configured memcache servers.
3232
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
3333
foreach ($memcache_servers as $server => $bin) {
34-
$memcache = dmemcache_instance($bin);
35-
if (dmemcache_connect($memcache, $server, FALSE) === FALSE) {
36-
$error = TRUE;
37-
}
38-
else {
39-
if (!variable_get('memcache_persistent', TRUE)) {
40-
dmemcache_close($memcache);
34+
if ($cluster = dmemcache_object_cluster($bin)) {
35+
$memcache = dmemcache_instance($cluster['cluster']);
36+
if (dmemcache_connect($memcache, $server, $cluster['weight']) === FALSE) {
37+
$error = TRUE;
38+
}
39+
else {
40+
if (!variable_get('memcache_persistent', TRUE)) {
41+
dmemcache_close($memcache);
42+
}
4143
}
4244
}
4345
}
@@ -114,13 +116,15 @@ function memcache_requirements($phase) {
114116
// Make a test connection to all configured memcache servers.
115117
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
116118
foreach ($memcache_servers as $server => $bin) {
117-
$memcache = dmemcache_instance($bin);
118-
if (dmemcache_connect($memcache, $server, FALSE) === FALSE) {
119-
$errors[] = $t('Failed to connect to memcached server instance at %server.', array('%server' => $server));
120-
}
121-
else {
122-
if (!variable_get('memcache_persistent', TRUE)) {
123-
dmemcache_close($memcache);
119+
if ($cluster = dmemcache_object_cluster($bin)) {
120+
$memcache = dmemcache_instance($cluster['cluster']);
121+
if (dmemcache_connect($memcache, $server, $cluster['weight']) === FALSE) {
122+
$errors[] = $t('Failed to connect to memcached server instance at %server.', array('%server' => $server));
123+
}
124+
else {
125+
if (!variable_get('memcache_persistent', TRUE)) {
126+
dmemcache_close($memcache);
127+
}
124128
}
125129
}
126130
}

memcache_admin/memcache_admin.module

+38-38
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,11 @@ function memcache_admin_menu() {
5959
);
6060
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
6161
$clusters = array();
62-
foreach ($memcache_servers as $server => $cluster) {
63-
$clusters[$cluster]['servers'][] = $server;
64-
$clusters[$cluster]['bin'] = _memcache_admin_get_bin_for_cluster($cluster);
62+
foreach ($memcache_servers as $server => $bin) {
63+
if ($cluster = dmemcache_object_cluster($bin)) {
64+
$clusters[$cluster]['servers'][] = $server;
65+
$clusters[$cluster]['bin'] = _memcache_admin_get_bin_for_cluster($cluster['cluster']);
66+
}
6567
}
6668

6769
$count = 0;
@@ -272,47 +274,45 @@ function memcache_admin_stats($bin = 'default') {
272274
$output = '';
273275
$server = array();
274276
$stats = dmemcache_stats($bin, 'default', TRUE);
275-
if (empty($stats)) {
277+
if (empty($stats[$bin])) {
276278
// Failed to load statistics. Provide a useful error about where to get
277279
// more information and help.
278-
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');
280+
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');
279281
}
280282
else {
281-
if (count($stats[$bin])) {
282-
$stats = $stats[$bin];
283-
$aggregate = array_pop($stats);
284-
$mc = dmemcache_object($bin);
285-
if ($mc instanceof Memcached) {
286-
$version = t('Memcached v!version', array('!version' => phpversion('Memcached')));
287-
}
288-
elseif ($mc instanceof Memcache) {
289-
$version = t('Memcache v!version', array('!version' => phpversion('Memcache')));
283+
$stats = $stats[$bin];
284+
$aggregate = array_pop($stats);
285+
$mc = dmemcache_object($bin);
286+
if ($mc instanceof Memcached) {
287+
$version = t('Memcached v!version', array('!version' => phpversion('Memcached')));
288+
}
289+
elseif ($mc instanceof Memcache) {
290+
$version = t('Memcache v!version', array('!version' => phpversion('Memcache')));
291+
}
292+
else {
293+
$version = t('Unknown');
294+
drupal_set_message(t('Failed to detect the memcache PECL extension.'), 'error');
295+
}
296+
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
297+
298+
foreach ($stats as $server => $statistics) {
299+
if (empty($statistics['uptime'])) {
300+
drupal_set_message(t('Failed to connect to server at %address.', array('%address' => $server)), 'error');
290301
}
291302
else {
292-
$version = t('Unknown');
293-
drupal_set_message(t('Failed to detect the memcache PECL extension.'), 'error');
294-
}
295-
$memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
296-
297-
foreach ($stats as $server => $statistics) {
298-
if (empty($statistics['uptime'])) {
299-
drupal_set_message(t('Failed to connect to server at %address.', array('%address' => $server)), 'error');
300-
}
301-
else {
302-
$servers[] = $server;
303-
$data['server_overview'][$server] = t('v!version running !uptime', array('!version' => check_plain($statistics['version']), '!uptime' => format_interval($statistics['uptime'])));
304-
$data['server_pecl'][$server] = t('n/a');
305-
$data['server_serialize'][$server] = t('n/a');
306-
$data['server_time'][$server] = format_date($statistics['time']);
307-
$data['server_connections'][$server] = _memcache_admin_stats_connections($statistics);
308-
$data['cache_sets'][$server] = _memcache_admin_stats_sets($statistics);
309-
$data['cache_gets'][$server] = _memcache_admin_stats_gets($statistics);
310-
$data['cache_counters'][$server] = _memcache_admin_stats_counters($statistics);
311-
$data['cache_transfer'][$server] = _memcache_admin_stats_transfer($statistics);
312-
$data['cache_average'][$server] = _memcache_admin_stats_average($statistics);
313-
$data['memory_available'][$server] = _memcache_admin_stats_memory($statistics);
314-
$data['memory_evictions'][$server] = number_format($statistics['evictions']);
315-
}
303+
$servers[] = $server;
304+
$data['server_overview'][$server] = t('v!version running !uptime', array('!version' => check_plain($statistics['version']), '!uptime' => format_interval($statistics['uptime'])));
305+
$data['server_pecl'][$server] = t('n/a');
306+
$data['server_serialize'][$server] = t('n/a');
307+
$data['server_time'][$server] = format_date($statistics['time']);
308+
$data['server_connections'][$server] = _memcache_admin_stats_connections($statistics);
309+
$data['cache_sets'][$server] = _memcache_admin_stats_sets($statistics);
310+
$data['cache_gets'][$server] = _memcache_admin_stats_gets($statistics);
311+
$data['cache_counters'][$server] = _memcache_admin_stats_counters($statistics);
312+
$data['cache_transfer'][$server] = _memcache_admin_stats_transfer($statistics);
313+
$data['cache_average'][$server] = _memcache_admin_stats_average($statistics);
314+
$data['memory_available'][$server] = _memcache_admin_stats_memory($statistics);
315+
$data['memory_evictions'][$server] = number_format($statistics['evictions']);
316316
}
317317
}
318318

0 commit comments

Comments
 (0)