From 32b98689fd09ec74ada7294e933f3733fa837366 Mon Sep 17 00:00:00 2001 From: Andrei Zmievski Date: Thu, 4 Jun 2009 15:39:17 -0700 Subject: [PATCH 1/3] Refactor and add JSON serializer support. JSON API is available only in PHP 5.2.10+, so need compile-time checks for that. Also, had to refactor the way value types are stored in flags to allow for better structure and future expansion, but this necessitates clearing of the cache on upgrading to this version. --- php_memcached.c | 191 ++++++++++++++++++++++++++++++------------------ php_memcached.h | 5 ++ 2 files changed, 125 insertions(+), 71 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 9addda78..794f1129 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -48,6 +48,9 @@ #ifdef HAVE_MEMCACHED_IGBINARY #include "ext/igbinary/igbinary.h" #endif +#ifdef HAVE_MEMCACHED_IGBINARY +#include "ext/json/php_json.h" +#endif /**************************************** Custom options @@ -64,12 +67,19 @@ /**************************************** Payload value flags ****************************************/ -#define MEMC_VAL_SERIALIZED (1<<0) -#define MEMC_VAL_COMPRESSED (1<<1) -#define MEMC_VAL_IS_LONG (1<<2) -#define MEMC_VAL_IS_DOUBLE (1<<3) -#define MEMC_VAL_IGBINARY (1<<4) -#define MEMC_VAL_IS_BOOL (1<<5) +#define MEMC_VAL_TYPE_MASK 0xf +#define MEMC_VAL_GET_TYPE(flags) ((flags) & MEMC_VAL_TYPE_MASK) +#define MEMC_VAL_SET_TYPE(flags, type) ((flags) |= ((type) & MEMC_VAL_TYPE_MASK)) + +#define MEMC_VAL_IS_STRING 0 +#define MEMC_VAL_IS_LONG 1 +#define MEMC_VAL_IS_DOUBLE 2 +#define MEMC_VAL_IS_BOOL 3 +#define MEMC_VAL_IS_SERIALIZED 4 +#define MEMC_VAL_IS_IGBINARY 5 +#define MEMC_VAL_IS_JSON 6 + +#define MEMC_VAL_COMPRESSED (1<<4) /**************************************** "get" operation flags @@ -117,6 +127,7 @@ enum memcached_serializer { SERIALIZER_PHP = 1, SERIALIZER_IGBINARY = 2, + SERIALIZER_JSON = 3, }; static int le_memc; @@ -167,7 +178,7 @@ ZEND_GET_MODULE(memcached) ****************************************/ static int php_memc_list_entry(void); static int php_memc_handle_error(memcached_return status TSRMLS_DC); -static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags TSRMLS_DC); +static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer TSRMLS_DC); static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload_len, uint32_t flags TSRMLS_DC); static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); @@ -945,7 +956,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke flags |= MEMC_VAL_COMPRESSED; } - payload = php_memc_zval_to_payload(*entry, &payload_len, &flags TSRMLS_CC); + payload = php_memc_zval_to_payload(*entry, &payload_len, &flags, i_obj->serializer TSRMLS_CC); if (payload == NULL) { MEMC_G(rescode) = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; @@ -1102,11 +1113,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool flags |= MEMC_VAL_COMPRESSED; } - if (i_obj->serializer == SERIALIZER_IGBINARY) { - flags |= MEMC_VAL_IGBINARY; - } - - payload = php_memc_zval_to_payload(value, &payload_len, &flags TSRMLS_CC); + payload = php_memc_zval_to_payload(value, &payload_len, &flags, i_obj->serializer TSRMLS_CC); if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { zval_ptr_dtor(&value); } @@ -1217,11 +1224,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) flags |= MEMC_VAL_COMPRESSED; } - if (i_obj->serializer == SERIALIZER_IGBINARY) { - flags |= MEMC_VAL_IGBINARY; - } - - payload = php_memc_zval_to_payload(value, &payload_len, &flags TSRMLS_CC); + payload = php_memc_zval_to_payload(value, &payload_len, &flags, i_obj->serializer TSRMLS_CC); if (payload == NULL) { MEMC_G(rescode) = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; @@ -1791,6 +1794,12 @@ static PHP_METHOD(Memcached, setOption) i_obj->serializer = SERIALIZER_IGBINARY; } else #endif +#if HAVE_JSON_API + if (Z_LVAL_P(value) == SERIALIZER_JSON) { + i_obj->serializer = SERIALIZER_JSON; + } else +#endif + /* php serializer */ if (Z_LVAL_P(value) == SERIALIZER_PHP) { i_obj->serializer = SERIALIZER_PHP; @@ -1912,7 +1921,7 @@ static int php_memc_handle_error(memcached_return status TSRMLS_DC) return result; } -static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags TSRMLS_DC) +static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer TSRMLS_DC) { char *payload; smart_str buf = {0}; @@ -1921,7 +1930,7 @@ static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t case IS_STRING: smart_str_appendl(&buf, Z_STRVAL_P(value), Z_STRLEN_P(value)); - *flags &= ~MEMC_VAL_IGBINARY; + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING); break; case IS_LONG: @@ -1937,42 +1946,53 @@ static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t zval_dtor(&value_copy); *flags &= ~MEMC_VAL_COMPRESSED; - *flags &= ~MEMC_VAL_IGBINARY; if (Z_TYPE_P(value) == IS_LONG) { - *flags |= MEMC_VAL_IS_LONG; + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG); } else if (Z_TYPE_P(value) == IS_DOUBLE) { - *flags |= MEMC_VAL_IS_DOUBLE; + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); } else if (Z_TYPE_P(value) == IS_BOOL) { - *flags |= MEMC_VAL_IS_BOOL; + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); } break; } default: - { + switch (serializer) { #if HAVE_MEMCACHED_IGBINARY - if (*flags & MEMC_VAL_IGBINARY) { - igbinary_serialize((uint8_t **) &buf.c, &buf.len, value); + case SERIALIZER_IGBINARY: + igbinary_serialize((uint8_t **) &buf.c, &buf.len, value); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY); + break; +#endif - } else { +#if HAVE_JSON_API + case SERIALIZER_JSON: + { + php_json_encode(&buf, value TSRMLS_CC); + buf.c[buf.len] = 0; + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON); + break; + } #endif - php_serialize_data_t var_hash; - PHP_VAR_SERIALIZE_INIT(var_hash); - php_var_serialize(&buf, &value, &var_hash TSRMLS_CC); - PHP_VAR_SERIALIZE_DESTROY(var_hash); - - if (!buf.c) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value"); - smart_str_free(&buf); - return NULL; + default: + { + php_serialize_data_t var_hash; + PHP_VAR_SERIALIZE_INIT(var_hash); + php_var_serialize(&buf, &value, &var_hash TSRMLS_CC); + PHP_VAR_SERIALIZE_DESTROY(var_hash); + + if (!buf.c) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value"); + smart_str_free(&buf); + return NULL; + } + + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED); + break; } -#if HAVE_MEMCACHED_IGBINARY } -#endif - *flags |= MEMC_VAL_SERIALIZED; break; - } } /* turn off compression for values below the threshold */ @@ -2051,25 +2071,31 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload } } - if (flags & MEMC_VAL_SERIALIZED) { + payload[payload_len] = 0; - if (flags & MEMC_VAL_IGBINARY) { -#if HAVE_MEMCACHED_IGBINARY - if (igbinary_unserialize((uint8_t *)payload, payload_len, &value)) { - ZVAL_FALSE(value); + switch (MEMC_VAL_GET_TYPE(flags)) { - if (flags & MEMC_VAL_COMPRESSED) { - efree(payload); - } + case MEMC_VAL_IS_STRING: + ZVAL_STRINGL(value, payload, payload_len, 1); + break; + case MEMC_VAL_IS_LONG: + { + long lval = strtol(payload, NULL, 10); + ZVAL_LONG(value, lval); + break; + } + case MEMC_VAL_IS_DOUBLE: + { + double dval = zend_strtod(payload, NULL); + ZVAL_DOUBLE(value, dval); + break; + } + case MEMC_VAL_IS_BOOL: + ZVAL_BOOL(value, payload_len > 0 && payload[0] == '1'); + break; - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value with igbinary"); - return -1; - } -#else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support"); - return -1; -#endif - } else { + case MEMC_VAL_IS_SERIALIZED: + { const char *payload_tmp = payload; php_unserialize_data_t var_hash; @@ -2084,20 +2110,42 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload return -1; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + break; } - } else { - payload[payload_len] = 0; - if (flags & MEMC_VAL_IS_LONG) { - long lval = strtol(payload, NULL, 10); - ZVAL_LONG(value, lval); - } else if (flags & MEMC_VAL_IS_DOUBLE) { - double dval = zend_strtod(payload, NULL); - ZVAL_DOUBLE(value, dval); - } else if (flags & MEMC_VAL_IS_BOOL) { - ZVAL_BOOL(value, payload_len > 0 && payload[0] == '1'); - } else { - ZVAL_STRINGL(value, payload, payload_len, 1); - } + + case MEMC_VAL_IS_IGBINARY: +#if HAVE_MEMCACHED_IGBINARY + if (igbinary_unserialize((uint8_t *)payload, payload_len, &value)) { + ZVAL_FALSE(value); + + if (flags & MEMC_VAL_COMPRESSED) { + efree(payload); + } + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value with igbinary"); + return -1; + } +#else + php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support"); + return -1; +#endif + break; + + case MEMC_VAL_IS_JSON: +#if HAVE_JSON_API + php_json_decode(value, payload, payload_len, 0 TSRMLS_CC); +#else + php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no json support"); + return -1; +#endif + break; + + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown payload type"); + if (flags & MEMC_VAL_COMPRESSED) { + efree(payload); + } + return -1; } if (flags & MEMC_VAL_COMPRESSED) { @@ -2199,7 +2247,7 @@ static memcached_return php_memc_do_cache_callback(zval *memc_obj, zend_fcall_in convert_to_boolean(retval); if (Z_BVAL_P(retval) == 1) { - payload = php_memc_zval_to_payload(value, &payload_len, &flags TSRMLS_CC); + payload = php_memc_zval_to_payload(value, &payload_len, &flags, i_obj->serializer TSRMLS_CC); if (payload == NULL) { status = MEMC_RES_PAYLOAD_FAILURE; } else { @@ -2827,6 +2875,7 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) */ REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP); REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY); + REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON); /* * Flags. diff --git a/php_memcached.h b/php_memcached.h index 276e989c..5567a692 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -66,6 +66,11 @@ extern ps_module ps_mod_memcached; PS_FUNCS(memcached); #endif +/* json serializer */ +#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION ==5 && PHP_MINOR_VERSION == 2 && PHP_RELEASE_VERSION > 9) +#define HAVE_JSON_API 1 +#endif + #endif /* PHP_MEMCACHED_H */ From 0b8182c5f6444c9ba8b86442d0fb8520032c964b Mon Sep 17 00:00:00 2001 From: Andrei Zmievski Date: Thu, 4 Jun 2009 15:50:48 -0700 Subject: [PATCH 2/3] Add HAVE_JSON constant. --- php_memcached.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 794f1129..471e23fe 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2802,9 +2802,18 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) * Indicate whether igbinary serializer is available */ #ifdef HAVE_MEMCACHED_IGBINARY - REGISTER_MEMC_CLASS_CONST_LONG(IGBINARY_SUPPORT, 1); + REGISTER_MEMC_CLASS_CONST_LONG(HAVE_IGBINARY, 1); #else - REGISTER_MEMC_CLASS_CONST_LONG(IGBINARY_SUPPORT, 0); + REGISTER_MEMC_CLASS_CONST_LONG(HAVE_IGBINARY, 0); +#endif + + /* + * Indicate whether json serializer is available + */ +#ifdef HAVE_JSON_API + REGISTER_MEMC_CLASS_CONST_LONG(HAVE_JSON, 1); +#else + REGISTER_MEMC_CLASS_CONST_LONG(HAVE_JSON, 0); #endif /* From da40d574f9499c5353bfd4bfa30dfa0a404de5bc Mon Sep 17 00:00:00 2001 From: Andrei Zmievski Date: Thu, 4 Jun 2009 16:15:36 -0700 Subject: [PATCH 3/3] Release 0.2.0. --- ChangeLog | 15 +++++++++++++++ package.xml | 41 +++++++++++++++++++++++++++++++++-------- php_memcached.h | 2 +- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c345056..867e838d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ memcached extension changelog +Version 0.2.0 +------------- + * Add JSON serializer support, requires PHP 5.2.10+. + * Add HAVE_JSON and HAVE_IGBINARY class constants that indicate + whether the respective serializers are available. + * Add 'flags' parameter to getMulti() and getMultiByKey(). + * Add GET_PRESERVE_ORDER class constant that can be used with + abovementioned flags parameter to make the order of the keys in the + response match the request. + * Fix an issue with retrieving 0-length payloads (FALSE boolean value). + * Refactor the way payload types are stored in memcached flags to optimize + the structure and allow for future expansion. WARNING! You have to flush + the cache when upgrading to this version. + * Add several tests. + Version 0.1.5 ------------- * Implement getVersion(). diff --git a/package.xml b/package.xml index cc1066a1..4481884b 100644 --- a/package.xml +++ b/package.xml @@ -15,10 +15,10 @@ http://pear.php.net/dtd/package-2.0.xsd"> andrei@php.net yes - 2009-03-31 + 2009-06-04 - 0.1.5 - 0.1.5 + 0.2.0 + 0.2.0 beta @@ -26,11 +26,17 @@ http://pear.php.net/dtd/package-2.0.xsd"> PHP -- Implement getVersion(). -- Add support for preserving boolean value types. -- Fix crash when child class does not call constructor. -- Fix bug #16084 (Crash when addServers is called with an associative array). -- ZTS compilation fixes. +- Refactor the way payload types are stored in memcached flags to optimize the structure + and allow for future expansion. WARNING! You have to flush the cache when upgrading from + an older version. +- Add JSON serializer support, requires PHP 5.2.10+. +- Add HAVE_JSON and HAVE_IGBINARY class constants that indicate whether the respective + serializers are available. +- Add 'flags' parameter to getMulti() and getMultiByKey(). +- Add GET_PRESERVE_ORDER class constant that can be used with abovementioned flags + parameter to make the order of the keys in the response match the request. +- Fix an issue with retrieving 0-length payloads (FALSE boolean value). +- Add several tests. @@ -61,6 +67,25 @@ http://pear.php.net/dtd/package-2.0.xsd"> memcached + + betabeta + 0.2.00.2.0 + 2009-06-04 + +- Refactor the way payload types are stored in memcached flags to optimize the structure + and allow for future expansion. WARNING! You have to flush the cache when upgrading from + an older version. +- Add JSON serializer support, requires PHP 5.2.10+. +- Add HAVE_JSON and HAVE_IGBINARY class constants that indicate whether the respective + serializers are available. +- Add 'flags' parameter to getMulti() and getMultiByKey(). +- Add GET_PRESERVE_ORDER class constant that can be used with abovementioned flags + parameter to make the order of the keys in the response match the request. +- Fix an issue with retrieving 0-length payloads (FALSE boolean value). +- Add several tests. + + + betabeta 0.1.50.1.5 diff --git a/php_memcached.h b/php_memcached.h index 5567a692..616c13c8 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -48,7 +48,7 @@ PHP_MINIT_FUNCTION(memcached); PHP_MSHUTDOWN_FUNCTION(memcached); PHP_MINFO_FUNCTION(memcached); -#define PHP_MEMCACHED_VERSION "0.1.5" +#define PHP_MEMCACHED_VERSION "0.2.0" #ifdef ZTS #define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, v)