Skip to content
This repository has been archived by the owner on May 27, 2022. It is now read-only.

Commit

Permalink
Refactor and add JSON serializer support.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Andrei Zmievski committed Jun 4, 2009
1 parent b57ea9d commit 32b9868
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 71 deletions.
191 changes: 120 additions & 71 deletions php_memcached.c
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -117,6 +127,7 @@
enum memcached_serializer {
SERIALIZER_PHP = 1,
SERIALIZER_IGBINARY = 2,
SERIALIZER_JSON = 3,
};

static int le_memc;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand All @@ -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:
Expand All @@ -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 */
Expand Down Expand Up @@ -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;

Expand All @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions php_memcached.h
Expand Up @@ -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 */


Expand Down

0 comments on commit 32b9868

Please sign in to comment.