Permalink
Browse files

First work on serializer.

  • Loading branch information...
1 parent 44f048c commit b2afc586547d8a0b52822dcea47038829cda4c78 @nicolasff nicolasff committed Dec 8, 2010
Showing with 193 additions and 13 deletions.
  1. +10 −0 common.h
  2. +72 −2 library.c
  3. +6 −0 library.h
  4. +4 −6 php_redis.h
  5. +88 −3 redis.c
  6. +13 −2 tests/TestRedis.php
View
@@ -26,6 +26,14 @@ static zend_class_entry *spl_ce_RuntimeException = NULL;
#define REDIS_ZSET 4
#define REDIS_HASH 5
+/* options */
+#define REDIS_OPT_SERIALIZER 1
+
+/* serializers */
+#define REDIS_SERIALIZER_NONE 0
+#define REDIS_SERIALIZER_PHP 1
+#define REDIS_SERIALIZER_IGBINARY 2
+
#define IF_MULTI() if(redis_sock->mode == MULTI)
#define IF_MULTI_OR_ATOMIC() if(redis_sock->mode == MULTI || redis_sock->mode == ATOMIC)\
@@ -143,6 +151,8 @@ typedef struct {
int failed;
int status;
+ int serializer;
+
redis_mode mode;
fold_item *head;
fold_item *current;
View
@@ -3,6 +3,8 @@
#include <sys/types.h>
#include <netinet/tcp.h> /* TCP_NODELAY */
#include <sys/socket.h>
+#include <ext/standard/php_smart_str_public.h>
+#include <ext/standard/php_var.h>
PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
{
@@ -672,10 +674,17 @@ PHPAPI void redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis
RETURN_FALSE;
}
IF_MULTI_OR_PIPELINE() {
- add_next_index_stringl(z_tab, response, response_len, 0);
+ zval *z = NULL;
+ if(redis_unserialize(redis_sock, response, response_len, &z TSRMLS_CC) == 1) {
+ add_next_index_zval(z_tab, z);
+ } else {
+ add_next_index_stringl(z_tab, response, response_len, 0);
+ }
}
- RETURN_STRINGL(response, response_len, 0);
+ if(redis_unserialize(redis_sock, response, response_len, &return_value TSRMLS_CC) == 0) {
+ RETURN_STRINGL(response, response_len, 0);
+ }
}
@@ -698,6 +707,7 @@ PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short por
redis_sock->port = port;
redis_sock->timeout = timeout;
+ redis_sock->serializer = REDIS_SERIALIZER_NONE;
redis_sock->mode = ATOMIC;
redis_sock->head = NULL;
redis_sock->current = NULL;
@@ -940,3 +950,63 @@ PHPAPI void redis_free_socket(RedisSock *redis_sock)
efree(redis_sock);
}
+PHPAPI int
+redis_serialize(RedisSock *redis_sock, zval *z, char **val, int *val_len TSRMLS_CC) {
+ HashTable ht;
+ smart_str sstr = {0};
+
+ switch(redis_sock->serializer) {
+ case REDIS_SERIALIZER_NONE:
+ if(Z_TYPE_P(z) == IS_STRING) {
+ *val = Z_STRVAL_P(z);
+ *val_len = Z_STRLEN_P(z);
+ return 0;
+ }
+ /* copy */
+ zval *z_copy;
+ MAKE_STD_ZVAL(z_copy);
+ *z_copy = *z;
+ zval_copy_ctor(z_copy);
+
+ /* return string */
+ convert_to_string(z_copy);
+ *val = Z_STRVAL_P(z_copy);
+ *val_len = Z_STRLEN_P(z_copy);
+ efree(z_copy);
+ return 1;
+
+ case REDIS_SERIALIZER_PHP:
+
+ zend_hash_init(&ht, 10, NULL, NULL, 0);
+ php_var_serialize(&sstr, &z, &ht TSRMLS_CC);
+ *val = sstr.c;
+ *val_len = (int)sstr.len;
+ zend_hash_destroy(&ht);
+
+ return 1;
+ }
+}
+
+PHPAPI int
+redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval **return_value TSRMLS_CC) {
+
+ php_unserialize_data_t var_hash;
+
+ switch(redis_sock->serializer) {
+ case REDIS_SERIALIZER_NONE:
+ return 0;
+
+ case REDIS_SERIALIZER_PHP:
+ if(!*return_value) {
+ MAKE_STD_ZVAL(*return_value);
+ }
+ var_hash.first = 0;
+ var_hash.first_dtor = 0;
+ php_var_unserialize(return_value, (const unsigned char**)&val,
+ (const unsigned char*)val + val_len, &var_hash TSRMLS_CC);
+ var_destroy(&var_hash);
+
+ return 1;
+ }
+}
+
View
@@ -27,3 +27,9 @@ PHPAPI int redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz);
PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC);
//PHPAPI int redis_sock_get(zval *id, RedisSock **redis_sock TSRMLS_DC);
PHPAPI void redis_free_socket(RedisSock *redis_sock);
+
+PHPAPI int
+redis_serialize(RedisSock *redis_sock, zval *z, char **val, int *val_len TSRMLS_CC);
+
+PHPAPI void
+redis_unserialize(RedisSock *redis_sock, char *val, int val_len, zval *return_value TSRMLS_CC);
View
@@ -139,6 +139,10 @@ PHP_METHOD(Redis, publish);
PHP_METHOD(Redis, subscribe);
PHP_METHOD(Redis, unsubscribe);
+PHP_METHOD(Redis, getOption);
+PHP_METHOD(Redis, setOption);
+PHP_METHOD(Redis, setOptions);
+
#ifdef PHP_WIN32
#define PHP_REDIS_API __declspec(dllexport)
#else
@@ -189,12 +193,6 @@ struct redis_queued_item {
struct redis_queued_item *next;
};
-struct redis {
- int fd;
- redis_mode mode;
- struct redis_queued_item *head;
-};
-
extern zend_module_entry redis_module_entry;
#define redis_module_ptr &redis_module_entry
View
91 redis.c
@@ -160,6 +160,11 @@ static zend_function_entry redis_functions[] = {
PHP_ME(Redis, subscribe, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Redis, unsubscribe, NULL, ZEND_ACC_PUBLIC)
+ /* options */
+ PHP_ME(Redis, getOption, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, setOption, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, setOptions, NULL, ZEND_ACC_PUBLIC)
+
/* aliases */
PHP_MALIAS(Redis, open, connect, NULL, ZEND_ACC_PUBLIC)
PHP_MALIAS(Redis, lLen, lSize, NULL, ZEND_ACC_PUBLIC)
@@ -294,6 +299,14 @@ PHP_MINIT_FUNCTION(redis)
add_constant_long(redis_ce, "MULTI", MULTI);
add_constant_long(redis_ce, "PIPELINE", PIPELINE);
+ /* options */
+ add_constant_long(redis_ce, "OPT_SERIALIZER", REDIS_OPT_SERIALIZER);
+
+ /* serializer */
+ add_constant_long(redis_ce, "SERIALIZER_NONE", REDIS_SERIALIZER_NONE);
+ add_constant_long(redis_ce, "SERIALIZER_PHP", REDIS_SERIALIZER_PHP);
+ add_constant_long(redis_ce, "SERIALIZER_IGBINARY", REDIS_SERIALIZER_IGBINARY);
+
zend_declare_class_constant_stringl(redis_ce, "AFTER", 5, "after", 5 TSRMLS_CC);
zend_declare_class_constant_stringl(redis_ce, "BEFORE", 6, "before", 6 TSRMLS_CC);
@@ -422,7 +435,7 @@ PHP_METHOD(Redis, close)
}
/* }}} */
-/* {{{ proto boolean Redis::set(string key, string value)
+/* {{{ proto boolean Redis::set(string key, mixed value)
*/
PHP_METHOD(Redis, set)
{
@@ -431,22 +444,27 @@ PHP_METHOD(Redis, set)
char *key = NULL, *val = NULL, *cmd;
int key_len, val_len, cmd_len;
long expire = -1;
+ int val_free = 0;
+ zval *z_value;
- if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss|l",
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osz|l",
&object, redis_ce, &key, &key_len,
- &val, &val_len, &expire) == FAILURE) {
+ &z_value, &expire) == FAILURE) {
RETURN_FALSE;
}
if (redis_sock_get(object, &redis_sock TSRMLS_CC) < 0) {
RETURN_FALSE;
}
+ val_free = redis_serialize(redis_sock, z_value, &val, &val_len);
+
if(expire > 0) {
cmd_len = redis_cmd_format_static(&cmd, "SETEX", "sds", key, key_len, expire, val, val_len);
} else {
cmd_len = redis_cmd_format_static(&cmd, "SET", "ss", key, key_len, val, val_len);
}
+ if(val_free) efree(val);
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
IF_ATOMIC() {
@@ -4518,5 +4536,72 @@ PHP_METHOD(Redis, slaveof)
}
/* }}} */
+/* {{{ proto string Redis::getOption($option)
+ */
+PHP_METHOD(Redis, getOption) {
+ RedisSock *redis_sock;
+ zval *object;
+ long option;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
+ &object, redis_ce, &option) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (redis_sock_get(object, &redis_sock TSRMLS_CC) < 0) {
+ RETURN_FALSE;
+ }
+
+ switch(option) {
+
+ case REDIS_OPT_SERIALIZER:
+ RETURN_LONG(redis_sock->serializer);
+
+ default:
+ RETURN_FALSE;
+
+ }
+}
+/* }}} */
+
+/* {{{ proto string Redis::setOption(string $option, mixed $value)
+ */
+PHP_METHOD(Redis, setOption) {
+ RedisSock *redis_sock;
+ zval *object;
+ long option, value;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll",
+ &object, redis_ce, &option, &value) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (redis_sock_get(object, &redis_sock TSRMLS_CC) < 0) {
+ RETURN_FALSE;
+ }
+
+ switch(option) {
+ case REDIS_OPT_SERIALIZER:
+ if(value == REDIS_SERIALIZER_NONE || value == REDIS_SERIALIZER_IGBINARY || value == REDIS_SERIALIZER_PHP) {
+ redis_sock->serializer = value;
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+ break;
+
+ default:
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string Redis::setOptions(array $options)
+ */
+PHP_METHOD(Redis, setOptions) {
+
+}
+/* }}} */
+
/* vim: set tabstop=4 expandtab: */
View
@@ -537,7 +537,7 @@ public function testrPop()
public function testblockingPop() {
- /* non blocking blPop, brPop */
+ // non blocking blPop, brPop
$this->redis->delete('list');
$this->redis->lPush('list', 'val1');
$this->redis->lPush('list', 'val2');
@@ -550,7 +550,7 @@ public function testblockingPop() {
$this->assertTrue($this->redis->brPop(array('list'), 2) === array('list', 'val1'));
$this->assertTrue($this->redis->brPop(array('list'), 2) === array('list', 'val2'));
- /* blocking blpop, brpop */
+ // blocking blpop, brpop
$this->redis->delete('list');
$this->assertTrue($this->redis->blPop(array('list'), 2) === array());
$this->assertTrue($this->redis->brPop(array('list'), 2) === array());
@@ -2360,6 +2360,17 @@ protected function sequence($mode) {
$this->assertTrue(count($ret) === $i);
}
+
+ public function testSerializerPHP() {
+
+ $this->redis->delete('key');
+ $this->assertTrue($this->redis->getOption(Redis::OPT_SERIALIZER) === Redis::SERIALIZER_NONE); // default
+
+ $this->assertTrue($this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP) === TRUE); // set ok
+ $this->assertTrue($this->redis->getOption(Redis::OPT_SERIALIZER) === Redis::SERIALIZER_PHP); // get ok
+
+ }
+
}
?>

0 comments on commit b2afc58

Please sign in to comment.