diff --git a/memcached.ini b/memcached.ini index 9767e184..cc11b25c 100644 --- a/memcached.ini +++ b/memcached.ini @@ -17,6 +17,9 @@ memcached.sess_lock_wait = 150000 ; the default value is "memc.sess.key." memcached.sess_prefix = "memc.sess.key." +; memcached session binary mode +memcached.sess_binary = Off + ; Set the compression type ; valid values are: fastlz, zlib ; the default is fastlz diff --git a/php_memcached.c b/php_memcached.c index 67e9909b..6cc93f1a 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -281,6 +281,7 @@ static PHP_INI_MH(OnUpdateSerializer) PHP_INI_BEGIN() #ifdef HAVE_MEMCACHED_SESSION STD_PHP_INI_ENTRY("memcached.sess_locking", "1", PHP_INI_ALL, OnUpdateBool, sess_locking_enabled, zend_php_memcached_globals, php_memcached_globals) + 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) #endif @@ -507,8 +508,6 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) size_t payload_len = 0; uint32_t flags = 0; uint64_t cas = 0; - const char* keys[1] = { NULL }; - size_t key_lens[1] = { 0 }; zval *cas_token = NULL; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; @@ -517,13 +516,16 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|f!z", &server_key, - &server_key_len, &key, &key_len, &fci, &fcc, &cas_token) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|f!z", + &server_key, &server_key_len, + &key, &key_len, + &fci, &fcc, &cas_token) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f!z", &key, &key_len, - &fci, &fcc, &cas_token) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f!z", + &key, &key_len, + &fci, &fcc, &cas_token) == FAILURE) { return; } } @@ -536,122 +538,104 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) RETURN_FROM_GET; } - keys[0] = key; - key_lens[0] = key_len; + zend_bool with_cas = 0; + zend_bool fetch_success = 0; + zend_bool return_value_set = 0; if (cas_token) { + const char* keys[1] = { key }; + size_t key_lens[1] = { key_len }; + uint64_t orig_cas_flag; - /* - * Enable CAS support, but only if it is currently disabled. - */ + /* Enable CAS support, but only if it is currently disabled */ + with_cas = 1; orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); if (orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } + /* Get keys */ status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, keys, key_lens, 1); + /* Restore CAS support to previous state */ if (orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { - RETURN_FROM_GET; - } - - status = MEMCACHED_SUCCESS; + /* Fetch primary result */ memcached_result_create(m_obj->memc, &result); + if (memcached_fetch_result(m_obj->memc, &result, &status) != NULL) { + fetch_success = 1; + + /* Fetch all remaining results */ + memcached_result_st dummy_result; + memcached_return dummy_status = MEMCACHED_SUCCESS; + memcached_result_create(m_obj->memc, &dummy_result); + while (memcached_fetch_result(m_obj->memc, &dummy_result, &dummy_status) != NULL) {} + memcached_result_free(&dummy_result); + } - if (memcached_fetch_result(m_obj->memc, &result, &status) == NULL) { - /* This is for historical reasons */ - if (status == MEMCACHED_END) - status = MEMCACHED_NOTFOUND; - - /* - * If the result wasn't found, and we have the read-through callback, invoke - * it to get the value. The CAS token will be 0, because we cannot generate it - * ourselves. - */ - if (status == MEMCACHED_NOTFOUND && fci.size != 0) { - status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, key_len, - return_value TSRMLS_CC); - ZVAL_DOUBLE(cas_token, 0); - } + } else { + /* Easy - just grab the one key directly */ + if ((payload = memcached_get_by_key(m_obj->memc, server_key, server_key_len, key, key_len, &payload_len, &flags, &status)) != NULL) { + fetch_success = 1; + } + } + + /* This is for historical reasons */ + if (status == MEMCACHED_END) { + status = MEMCACHED_NOTFOUND; + } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { - memcached_result_free(&result); - RETURN_FROM_GET; - } + /* If the result wasn't found, and we have the read-through callback, invoke it to get the value */ + if (!fetch_success && status == MEMCACHED_NOTFOUND && fci.size != 0) { + status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, key_len, return_value TSRMLS_CC); + return_value_set = 1; - /* if we have a callback, all processing is done */ - if (fci.size != 0) { - memcached_result_free(&result); - return; - } + /* The CAS token will be 0, because we cannot generate it ourselves */ + if (with_cas) { + ZVAL_DOUBLE(cas_token, 0); } + } - payload = memcached_result_value(&result); - payload_len = memcached_result_length(&result); - flags = memcached_result_flags(&result); - cas = memcached_result_cas(&result); - - if (php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) { + /* Check for errors */ + if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (with_cas) { memcached_result_free(&result); - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; - RETURN_FROM_GET; + } else if (payload) { + free(payload); } + RETURN_FROM_GET; + } - zval_dtor(cas_token); - ZVAL_DOUBLE(cas_token, (double)cas); - - memcached_result_free(&result); - - } else { + /* No callback, but we may have data */ + if (!return_value_set) { int rc; - zend_bool return_value_set = 0; - status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, keys, key_lens, 1); - payload = memcached_fetch(m_obj->memc, NULL, NULL, &payload_len, &flags, &status); + /* Fetch payload and CAS token if required */ + if (with_cas) { + payload = memcached_result_value(&result); + payload_len = memcached_result_length(&result); + flags = memcached_result_flags(&result); + cas = memcached_result_cas(&result); - /* This is for historical reasons */ - if (status == MEMCACHED_END) - status = MEMCACHED_NOTFOUND; - - /* - * If payload wasn't found and we have a read-through callback, invoke it to get - * the value. The callback will take care of storing the value back into memcache. - * The callback will set the return value. - */ - if (payload == NULL && status == MEMCACHED_NOTFOUND && fci.size != 0) { - size_t dummy_length; - uint32_t dummy_flags; - memcached_return dummy_status; - - status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, key_len, - return_value TSRMLS_CC); - return_value_set = 1; - - (void)memcached_fetch(m_obj->memc, NULL, NULL, &dummy_length, &dummy_flags, &dummy_status); - } - - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { - if (payload) { - free(payload); - } - RETURN_FROM_GET; + ZVAL_DOUBLE(cas_token, (double)cas); } - /* if memcached gave a value and there was no callback, payload may be NULL */ - if (!return_value_set) { - rc = php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC); + /* Fetch/unserialize payload */ + rc = php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC); + if (with_cas) { + memcached_result_free(&result); + } else { free(payload); - if (rc < 0) { - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; - RETURN_FROM_GET; - } } + /* Error out on invalid payload */ + if (rc < 0) { + i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + RETURN_FROM_GET; + } } } /* }}} */ @@ -3017,6 +3001,7 @@ 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_prefix) = NULL; MEMC_G(sess_lock_wait) = 0; MEMC_G(sess_locked) = 0; diff --git a/php_memcached.h b/php_memcached.h index c5e79301..08e64f8d 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -61,6 +61,7 @@ enum memcached_serializer { ZEND_BEGIN_MODULE_GLOBALS(php_memcached) #ifdef HAVE_MEMCACHED_SESSION zend_bool sess_locking_enabled; + zend_bool sess_binary_enabled; long sess_lock_wait; char* sess_prefix; zend_bool sess_locked; diff --git a/php_memcached_session.c b/php_memcached_session.c index e76f7088..8b1d2ecd 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -188,6 +188,14 @@ PS_OPEN_FUNC(memcached) } efree(plist_key); } + + if (MEMC_G(sess_binary_enabled)) { + if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, (uint64_t) 1) == MEMCACHED_FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session binary protocol"); + return FAILURE; + } + } + return SUCCESS; } }