diff options
-rw-r--r-- | redis.c | 1 | ||||
-rw-r--r-- | redis_array.c | 14 | ||||
-rw-r--r-- | redis_array.h | 1 | ||||
-rw-r--r-- | redis_array_impl.c | 44 | ||||
-rw-r--r-- | redis_array_impl.h | 2 |
5 files changed, 53 insertions, 9 deletions
@@ -55,6 +55,7 @@ extern zend_function_entry redis_cluster_functions[]; PHP_INI_BEGIN() /* redis arrays */ + PHP_INI_ENTRY("redis.arrays.algorithm", "", PHP_INI_ALL, NULL) PHP_INI_ENTRY("redis.arrays.autorehash", "0", PHP_INI_ALL, NULL) PHP_INI_ENTRY("redis.arrays.connecttimeout", "0", PHP_INI_ALL, NULL) PHP_INI_ENTRY("redis.arrays.distributor", "", PHP_INI_ALL, NULL) diff --git a/redis_array.c b/redis_array.c index e4c62b48..79cf0804 100644 --- a/redis_array.c +++ b/redis_array.c @@ -159,6 +159,9 @@ redis_array_free(RedisArray *ra) /* Distributor */ zval_dtor(&ra->z_dist); + /* Hashing algorithm */ + zval_dtor(&ra->z_algo); + /* Delete pur commands */ zend_hash_destroy(ra->pure_cmds); FREE_HASHTABLE(ra->pure_cmds); @@ -269,7 +272,7 @@ redis_array_get(zval *id TSRMLS_DC) Public constructor */ PHP_METHOD(RedisArray, __construct) { - zval *z0, z_fun, z_dist, *zpData, *z_opts = NULL; + zval *z0, z_fun, z_dist, z_algo, *zpData, *z_opts = NULL; RedisArray *ra = NULL; zend_bool b_index = 0, b_autorehash = 0, b_pconnect = 0, consistent = 0; HashTable *hPrev = NULL, *hOpts = NULL; @@ -284,6 +287,7 @@ PHP_METHOD(RedisArray, __construct) ZVAL_NULL(&z_fun); ZVAL_NULL(&z_dist); + ZVAL_NULL(&z_algo); /* extract options */ if(z_opts) { hOpts = Z_ARRVAL_P(z_opts); @@ -306,6 +310,11 @@ PHP_METHOD(RedisArray, __construct) ZVAL_ZVAL(&z_dist, zpData, 1, 0); } + /* extract function name. */ + if ((zpData = zend_hash_str_find(hOpts, "algorithm", sizeof("algorithm") - 1)) != NULL && Z_TYPE_P(zpData) == IS_STRING) { + ZVAL_ZVAL(&z_algo, zpData, 1, 0); + } + /* extract index option. */ if ((zpData = zend_hash_str_find(hOpts, "index", sizeof("index") - 1)) != NULL) { b_index = zval_is_true(zpData); @@ -370,12 +379,13 @@ PHP_METHOD(RedisArray, __construct) break; case IS_ARRAY: - ra = ra_make_array(Z_ARRVAL_P(z0), &z_fun, &z_dist, hPrev, b_index, b_pconnect, l_retry_interval, b_lazy_connect, d_connect_timeout, read_timeout, consistent TSRMLS_CC); + ra = ra_make_array(Z_ARRVAL_P(z0), &z_fun, &z_dist, &z_algo, hPrev, b_index, b_pconnect, l_retry_interval, b_lazy_connect, d_connect_timeout, read_timeout, consistent TSRMLS_CC); break; default: WRONG_PARAM_COUNT; } + zval_dtor(&z_algo); zval_dtor(&z_dist); zval_dtor(&z_fun); diff --git a/redis_array.h b/redis_array.h index 9ccd6f68..de444654 100644 --- a/redis_array.h +++ b/redis_array.h @@ -59,6 +59,7 @@ typedef struct RedisArray_ { zend_bool pconnect; /* should we use pconnect */ zval z_fun; /* key extractor, callable */ zval z_dist; /* key distributor, callable */ + zval z_algo; /* key hashing algorithm name */ HashTable *pure_cmds; /* hash table */ double connect_timeout; /* socket connect timeout */ double read_timeout; /* socket read timeout */ diff --git a/redis_array_impl.c b/redis_array_impl.c index c5d4796c..85051293 100644 --- a/redis_array_impl.c +++ b/redis_array_impl.c @@ -26,6 +26,8 @@ #include "ext/standard/crc32.h" #include "ext/standard/md5.h" +#include "ext/hash/php_hash.h" + #define PHPREDIS_INDEX_NAME "__phpredis_array_index__" extern zend_class_entry *redis_ce; @@ -162,11 +164,12 @@ ra_find_name(const char *name) { /* laod array from INI settings */ RedisArray *ra_load_array(const char *name TSRMLS_DC) { - zval *z_data, z_fun, z_dist; + zval *z_data, z_fun, z_dist, z_algo; zval z_params_hosts; zval z_params_prev; zval z_params_funs; zval z_params_dist; + zval z_params_algo; zval z_params_index; zval z_params_autorehash; zval z_params_retry_interval; @@ -227,6 +230,16 @@ RedisArray *ra_load_array(const char *name TSRMLS_DC) { ZVAL_ZVAL(&z_dist, z_data, 1, 0); } + /* find hash algorithm */ + array_init(&z_params_algo); + if ((iptr = INI_STR("redis.arrays.algorithm")) != NULL) { + sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_params_algo TSRMLS_CC); + } + ZVAL_NULL(&z_algo); + if ((z_data = zend_hash_str_find(Z_ARRVAL(z_params_algo), name, name_len)) != NULL) { + ZVAL_ZVAL(&z_algo, z_data, 1, 0); + } + /* find index option */ array_init(&z_params_index); if ((iptr = INI_STR("redis.arrays.index")) != NULL) { @@ -327,7 +340,7 @@ RedisArray *ra_load_array(const char *name TSRMLS_DC) { /* create RedisArray object */ - ra = ra_make_array(hHosts, &z_fun, &z_dist, hPrev, b_index, b_pconnect, l_retry_interval, b_lazy_connect, d_connect_timeout, read_timeout, consistent TSRMLS_CC); + ra = ra_make_array(hHosts, &z_fun, &z_dist, &z_algo, hPrev, b_index, b_pconnect, l_retry_interval, b_lazy_connect, d_connect_timeout, read_timeout, consistent TSRMLS_CC); if (ra) { ra->auto_rehash = b_autorehash; if(ra->prev) ra->prev->auto_rehash = b_autorehash; @@ -338,6 +351,7 @@ RedisArray *ra_load_array(const char *name TSRMLS_DC) { zval_dtor(&z_params_prev); zval_dtor(&z_params_funs); zval_dtor(&z_params_dist); + zval_dtor(&z_params_algo); zval_dtor(&z_params_index); zval_dtor(&z_params_autorehash); zval_dtor(&z_params_retry_interval); @@ -346,6 +360,7 @@ RedisArray *ra_load_array(const char *name TSRMLS_DC) { zval_dtor(&z_params_read_timeout); zval_dtor(&z_params_lazy_connect); zval_dtor(&z_params_consistent); + zval_dtor(&z_algo); zval_dtor(&z_dist); zval_dtor(&z_fun); @@ -393,7 +408,7 @@ ra_make_continuum(zend_string **hosts, int nb_hosts) } RedisArray * -ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev, zend_bool b_index, zend_bool b_pconnect, long retry_interval, zend_bool b_lazy_connect, double connect_timeout, double read_timeout, zend_bool consistent TSRMLS_DC) { +ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, zval *z_algo, HashTable *hosts_prev, zend_bool b_index, zend_bool b_pconnect, long retry_interval, zend_bool b_lazy_connect, double connect_timeout, double read_timeout, zend_bool consistent TSRMLS_DC) { int i, count; RedisArray *ra; @@ -423,7 +438,7 @@ ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev efree(ra); return NULL; } - ra->prev = hosts_prev ? ra_make_array(hosts_prev, z_fun, z_dist, NULL, b_index, b_pconnect, retry_interval, b_lazy_connect, connect_timeout, read_timeout, consistent TSRMLS_CC) : NULL; + ra->prev = hosts_prev ? ra_make_array(hosts_prev, z_fun, z_dist, z_algo, NULL, b_index, b_pconnect, retry_interval, b_lazy_connect, connect_timeout, read_timeout, consistent TSRMLS_CC) : NULL; /* init array data structures */ ra_init_function_table(ra); @@ -431,6 +446,7 @@ ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev /* Set hash function and distribtor if provided */ ZVAL_ZVAL(&ra->z_fun, z_fun, 1, 0); ZVAL_ZVAL(&ra->z_dist, z_dist, 1, 0); + ZVAL_ZVAL(&ra->z_algo, z_algo, 1, 0); /* init continuum */ if (consistent) { @@ -533,10 +549,26 @@ ra_find_node(RedisArray *ra, const char *key, int key_len, int *out_pos TSRMLS_D if (Z_TYPE(ra->z_dist) == IS_NULL) { int i; unsigned long ret = 0xffffffff; + const php_hash_ops *ops; /* hash */ - for (i = 0; i < ZSTR_LEN(out); ++i) { - CRC32(ret, ZSTR_VAL(out)[i]); + if (Z_TYPE(ra->z_algo) == IS_STRING && (ops = php_hash_fetch_ops(Z_STRVAL(ra->z_algo), Z_STRLEN(ra->z_algo))) != NULL) { + void *ctx = emalloc(ops->context_size); + unsigned char *digest = emalloc(ops->digest_size); + + ops->hash_init(ctx); + ops->hash_update(ctx, ZSTR_VAL(out), ZSTR_LEN(out)); + ops->hash_final(digest, ctx); + + memcpy(&ret, digest, MIN(sizeof(ret), ops->digest_size)); + ret %= 0xffffffff; + + efree(digest); + efree(ctx); + } else { + for (i = 0; i < ZSTR_LEN(out); ++i) { + CRC32(ret, ZSTR_VAL(out)[i]); + } } /* get position on ring */ diff --git a/redis_array_impl.h b/redis_array_impl.h index fa5fd848..43705ee5 100644 --- a/redis_array_impl.h +++ b/redis_array_impl.h @@ -11,7 +11,7 @@ RedisArray *ra_load_hosts(RedisArray *ra, HashTable *hosts, long retry_interval, zend_bool b_lazy_connect TSRMLS_DC); RedisArray *ra_load_array(const char *name TSRMLS_DC); -RedisArray *ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev, zend_bool b_index, zend_bool b_pconnect, long retry_interval, zend_bool b_lazy_connect, double connect_timeout, double read_timeout, zend_bool consistent TSRMLS_DC); +RedisArray *ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, zval *z_algo, HashTable *hosts_prev, zend_bool b_index, zend_bool b_pconnect, long retry_interval, zend_bool b_lazy_connect, double connect_timeout, double read_timeout, zend_bool consistent TSRMLS_DC); zval *ra_find_node_by_name(RedisArray *ra, const char *host, int host_len TSRMLS_DC); zval *ra_find_node(RedisArray *ra, const char *key, int key_len, int *out_pos TSRMLS_DC); void ra_init_function_table(RedisArray *ra); |