Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of https://github.com/Vendini/php-memcached int…

…o Vendini-master

Conflicts:
	memcached.ini
	php_memcached.c
	php_memcached.h
	php_memcached_session.c
  • Loading branch information...
commit 40ce9b4633de5d70f056e4d434d9b064263348d0 2 parents 5ff9516 + faf84af
@iliaal iliaal authored
View
14 memcached.ini
@@ -25,7 +25,20 @@ memcached.sess_prefix = "memc.sess.key."
; default is Off
memcached.sess_consistent_hash = Off
+; Allow failed memcached server to automatically be removed
+memcached.sess_remove_failed = 1
+
+; Write data to a number of additional memcached servers
+; This is "poor man's HA" as libmemcached calls it.
+; If this value is positive and sess_remove_failed is enabled
+; when a memcached server fails the session will continue to be available
+; from a replica. However, if the failed memcache server
+; becomes available again it will read the session from there
+; which could have old data or no data at all
+memcached.sess_num_replicas = 0;
+
; memcached session binary mode
+; libmemcached replicas only work if binary mode is enabled
memcached.sess_binary = Off
; memcached session number of replicas
@@ -68,4 +81,3 @@ memcached.compression_threshold = 2000
;
; The default is igbinary if available and php otherwise.
memcached.serializer = "igbinary"
-
View
9 php_memcached.c
@@ -289,8 +289,11 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("memcached.sess_binary", "0", PHP_INI_ALL, OnUpdateBool, sess_binary_enabled, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_lock_wait", "150000", PHP_INI_ALL, OnUpdateLongGEZero,sess_lock_wait, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_prefix", "memc.sess.key.", PHP_INI_ALL, OnUpdateString, sess_prefix, zend_php_memcached_globals, php_memcached_globals)
+
STD_PHP_INI_ENTRY("memcached.sess_number_of_replicas", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_number_of_replicas, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_randomize_replica_read", "0", PHP_INI_ALL, OnUpdateBool, sess_randomize_replica_read, zend_php_memcached_globals, php_memcached_globals)
+ STD_PHP_INI_ENTRY("memcached.sess_consistent_hashing", "0", PHP_INI_ALL, OnUpdateBool, sess_consistent_hashing_enabled, zend_php_memcached_globals, php_memcached_globals)
+ STD_PHP_INI_ENTRY("memcached.sess_remove_failed", "0", PHP_INI_ALL, OnUpdateBool, sess_remove_failed_enabled, zend_php_memcached_globals, php_memcached_globals)
#endif
STD_PHP_INI_ENTRY("memcached.compression_type", "fastlz", PHP_INI_ALL, OnUpdateCompressionType, compression_type, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.compression_factor", "1.3", PHP_INI_ALL, OnUpdateReal, compression_factor, zend_php_memcached_globals, php_memcached_globals)
@@ -2589,7 +2592,8 @@ static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr,
/*
* API does not allow to get at this field.
add_assoc_long(array, "weight", instance->weight);
- */
+ */
+
add_next_index_zval(context->return_value, array);
return MEMCACHED_SUCCESS;
}
@@ -3038,6 +3042,9 @@ static void php_memc_init_globals(zend_php_memcached_globals *php_memcached_glob
#ifdef HAVE_MEMCACHED_SESSION
MEMC_G(sess_locking_enabled) = 1;
MEMC_G(sess_binary_enabled) = 1;
+ MEMC_G(sess_consistent_hashing_enabled) = 0;
+ MEMC_G(sess_number_of_replicas) = 0;
+ MEMC_G(sess_remove_failed_enabled) = 0;
MEMC_G(sess_prefix) = NULL;
MEMC_G(sess_lock_wait) = 0;
MEMC_G(sess_locked) = 0;
View
3  php_memcached.h
@@ -66,8 +66,11 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached)
zend_bool sess_locked;
char* sess_lock_key;
int sess_lock_key_len;
+
int sess_number_of_replicas;
zend_bool sess_randomize_replica_read;
+ zend_bool sess_remove_failed_enabled;
+ zend_bool sess_consistent_hashing_enabled;
#endif
char *serializer_name;
enum memcached_serializer serializer;
View
46 php_memcached_session.c
@@ -48,6 +48,7 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
char *lock_key = NULL;
int lock_key_len = 0;
unsigned long attempts;
+ long write_retry_attempts = 0;
long lock_maxwait;
long lock_wait = MEMC_G(sess_lock_wait);
time_t expiration;
@@ -64,6 +65,11 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
expiration = time(NULL) + lock_maxwait + 1;
attempts = (unsigned long)((1000000.0 / lock_wait) * lock_maxwait);
+ /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server */
+ if (MEMC_G(sess_remove_failed_enabled)) {
+ write_retry_attempts = MEMC_G(sess_number_of_replicas) * ( memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT) + 1);
+ }
+
lock_key_len = spprintf(&lock_key, 0, "lock.%s", key);
do {
status = memcached_add(memc, lock_key, lock_key_len, "1", sizeof("1")-1, expiration, 0);
@@ -73,6 +79,11 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
MEMC_G(sess_lock_key_len) = lock_key_len;
return 0;
} else if (status != MEMCACHED_NOTSTORED && status != MEMCACHED_DATA_EXISTS) {
+ if (write_retry_attempts > 0) {
+ write_retry_attempts--;
+ continue;
+ }
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Write of lock failed");
break;
}
@@ -214,6 +225,20 @@ PS_OPEN_FUNC(memcached)
}
if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, (uint64_t) MEMC_G(sess_randomize_replica_read)) == MEMCACHED_FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session randomize replica read");
+ }
+ }
+
+ if (MEMC_G(sess_consistent_hashing_enabled)) {
+ if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_KETAMA, (uint64_t) 1) == MEMCACHED_FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached consistent hashing");
+ return FAILURE;
+ }
+ }
+
+ /* Allow libmemcached remove failed servers */
+ if (MEMC_G(sess_remove_failed_enabled)) {
+ if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, (uint64_t) 1) == MEMCACHED_FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set: remove failed servers");
return FAILURE;
}
}
@@ -266,6 +291,7 @@ PS_READ_FUNC(memcached)
if (MEMC_G(sess_locking_enabled)) {
if (php_memc_sess_lock(memc_sess->memc_sess, key TSRMLS_CC) < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to clear session lock record");
return FAILURE;
}
}
@@ -286,6 +312,7 @@ PS_WRITE_FUNC(memcached)
{
int key_len = strlen(key);
time_t expiration = 0;
+ long write_try_attempts = 1;
memcached_return status;
memcached_sess *memc_sess = PS_GET_MOD_DATA();
size_t key_length;
@@ -300,13 +327,22 @@ PS_WRITE_FUNC(memcached)
if (PS(gc_maxlifetime) > 0) {
expiration = PS(gc_maxlifetime);
}
- status = memcached_set(memc_sess->memc_sess, key, key_len, val, vallen, expiration, 0);
- if (status == MEMCACHED_SUCCESS) {
- return SUCCESS;
- } else {
- return FAILURE;
+ /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server plus the initial write */
+ if (MEMC_G(sess_remove_failed_enabled)) {
+ write_try_attempts = 1 + MEMC_G(sess_number_of_replicas) * ( memcached_behavior_get(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT) + 1);
}
+
+ do {
+ status = memcached_set(memc_sess->memc_sess, key, key_len, val, vallen, expiration, 0);
+ if (status == MEMCACHED_SUCCESS) {
+ return SUCCESS;
+ } else {
+ write_try_attempts--;
+ }
+ } while (write_try_attempts > 0);
+
+ return FAILURE;
}
PS_DESTROY_FUNC(memcached)
View
4 tests/experimental/getmulti_badserver.phpt
@@ -21,10 +21,10 @@ switch ($m->getResultCode()) {
echo $m->getResultMessage(), "\n";
}
---EXPECT--
+--EXPECTF--
array(0) {
}
NO SERVERS DEFINED
array(0) {
}
-3: CONNECTION FAILURE
+%d: %s
View
5 tests/experimental/moduleinfo.phpt
@@ -24,6 +24,11 @@ memcached.compression_threshold => %d => %d
memcached.compression_type => %s => %s
memcached.serializer => %s => %s
memcached.sess_binary => %d => %d
+memcached.sess_consistent_hash => %d => %d
+memcached.sess_consistent_hashing => %d => %d
memcached.sess_lock_wait => %d => %d
memcached.sess_locking => %d => %d
+memcached.sess_number_of_replicas => %d => %d
memcached.sess_prefix => %s => %s
+memcached.sess_randomize_replica_read => %d => %d
+memcached.sess_remove_failed => %d => %d
View
2  tests/types.phpt
@@ -33,7 +33,7 @@ $data = array(
array('array', array(1,2,3,"foo")),
array('object_array_empty', (object)array()),
- array('object_array', (object)array(1,2,3)),
+ array('object_array', (object)array("a" => "1","b" => "2","c" => "3")),
array('object_dummy', new testclass()),
);
Please sign in to comment.
Something went wrong with that request. Please try again.