mirror of
https://github.com/php-win-ext/pecl-memcache.git
synced 2026-03-24 00:52:07 +01:00
Hash function transparency, supports CRC32 and FNV-1a
Added INI directive memcache.hash_function = {crc32, fnv}
This commit is contained in:
18
memcache.c
18
memcache.c
@@ -172,6 +172,23 @@ static PHP_INI_MH(OnUpdateHashStrategy) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static PHP_INI_MH(OnUpdateHashFunction) /* {{{ */
|
||||
{
|
||||
if (!strcasecmp(new_value, "crc32")) {
|
||||
MEMCACHE_G(hash_strategy) = MMC_HASH_CRC32;
|
||||
}
|
||||
else if (!strcasecmp(new_value, "fnv")) {
|
||||
MEMCACHE_G(hash_strategy) = MMC_HASH_FNV1A;
|
||||
}
|
||||
else {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.hash_function must be in set {crc32, fnv} ('%s' given)", new_value);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_INI */
|
||||
PHP_INI_BEGIN()
|
||||
STD_PHP_INI_ENTRY("memcache.allow_failover", "1", PHP_INI_ALL, OnUpdateLong, allow_failover, zend_memcache_globals, memcache_globals)
|
||||
@@ -179,6 +196,7 @@ PHP_INI_BEGIN()
|
||||
STD_PHP_INI_ENTRY("memcache.default_port", "11211", PHP_INI_ALL, OnUpdateLong, default_port, zend_memcache_globals, memcache_globals)
|
||||
STD_PHP_INI_ENTRY("memcache.chunk_size", "8192", PHP_INI_ALL, OnUpdateChunkSize, chunk_size, zend_memcache_globals, memcache_globals)
|
||||
STD_PHP_INI_ENTRY("memcache.hash_strategy", "standard", PHP_INI_ALL, OnUpdateHashStrategy, hash_strategy, zend_memcache_globals, memcache_globals)
|
||||
STD_PHP_INI_ENTRY("memcache.hash_function", "crc32", PHP_INI_ALL, OnUpdateHashFunction, hash_function, zend_memcache_globals, memcache_globals)
|
||||
PHP_INI_END()
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "php.h"
|
||||
#include "ext/standard/crc32.h"
|
||||
#include "php_memcache.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(memcache)
|
||||
@@ -42,12 +41,14 @@ typedef struct mmc_consistent_state {
|
||||
int num_points;
|
||||
mmc_t *buckets[MMC_CONSISTENT_BUCKETS];
|
||||
int buckets_populated;
|
||||
mmc_hash_function hash;
|
||||
} mmc_consistent_state_t;
|
||||
|
||||
void *mmc_consistent_create_state() /* {{{ */
|
||||
void *mmc_consistent_create_state(mmc_hash_function hash) /* {{{ */
|
||||
{
|
||||
mmc_consistent_state_t *state = emalloc(sizeof(mmc_consistent_state_t));
|
||||
memset(state, 0, sizeof(mmc_consistent_state_t));
|
||||
state->hash = hash;
|
||||
return state;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -64,19 +65,6 @@ void mmc_consistent_free_state(void *s) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static unsigned int mmc_hash(const char *key, int key_len) /* {{{ */
|
||||
{
|
||||
unsigned int crc = ~0;
|
||||
int i;
|
||||
|
||||
for (i=0; i<key_len; i++) {
|
||||
CRC32(crc, key[i]);
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int mmc_consistent_compare(const void *a, const void *b) /* {{{ */
|
||||
{
|
||||
if (((mmc_consistent_point_t *)a)->point < ((mmc_consistent_point_t *)b)->point) {
|
||||
@@ -139,7 +127,7 @@ mmc_t *mmc_consistent_find_server(void *s, const char *key, int key_len TSRMLS_D
|
||||
if (!state->buckets_populated) {
|
||||
mmc_consistent_pupulate_buckets(state);
|
||||
}
|
||||
return state->buckets[mmc_hash(key, key_len) % MMC_CONSISTENT_BUCKETS];
|
||||
return state->buckets[state->hash(key, key_len) % MMC_CONSISTENT_BUCKETS];
|
||||
}
|
||||
|
||||
return state->points[0].server;
|
||||
@@ -163,7 +151,7 @@ void mmc_consistent_add_server(void *s, mmc_t *mmc, unsigned int weight) /* {{{
|
||||
for (i=0; i<points; i++) {
|
||||
key_len = spprintf(&key, 0, "%s:%d-%d", mmc->host, mmc->tcp.port, i);
|
||||
state->points[state->num_points + i].server = mmc;
|
||||
state->points[state->num_points + i].point = mmc_hash(key, key_len);
|
||||
state->points[state->num_points + i].point = state->hash(key, key_len);
|
||||
efree(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "php.h"
|
||||
#include "php_network.h"
|
||||
#include "ext/standard/crc32.h"
|
||||
#include "ext/standard/php_var.h"
|
||||
#include "ext/standard/php_string.h"
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
@@ -119,6 +120,36 @@ static inline void mmc_queue_remove(mmc_queue_t *queue, void *ptr) {
|
||||
mmc_queue_free(&original);
|
||||
}
|
||||
|
||||
static unsigned int mmc_hash_crc32(const char *key, int key_len) /*
|
||||
new style crc32 hash, compatible with other clients {{{ */
|
||||
{
|
||||
unsigned int crc = ~0;
|
||||
int i;
|
||||
|
||||
for (i=0; i<key_len; i++) {
|
||||
CRC32(crc, key[i]);
|
||||
}
|
||||
|
||||
crc = (~crc >> 16) & 0x7fff;
|
||||
return crc ? crc : 1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static unsigned int mmc_hash_fnv1a(const char *key, int key_len) /*
|
||||
FNV-1a hash {{{ */
|
||||
{
|
||||
unsigned int hval = FNV_32_INIT;
|
||||
int i;
|
||||
|
||||
for (i=0; i<key_len; i++) {
|
||||
hval ^= (unsigned int)key[i];
|
||||
hval *= FNV_32_PRIME;
|
||||
}
|
||||
|
||||
return hval;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static size_t mmc_stream_read_buffered(mmc_stream_t *io, char *buf, size_t count TSRMLS_DC) /*
|
||||
attempts to reads count bytes from the stream buffer {{{ */
|
||||
{
|
||||
@@ -922,6 +953,7 @@ void mmc_server_free(mmc_t *mmc TSRMLS_DC) /* {{{ */
|
||||
|
||||
mmc_pool_t *mmc_pool_new(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
mmc_hash_function hash;
|
||||
mmc_pool_t *pool = emalloc(sizeof(mmc_pool_t));
|
||||
memset(pool, 0, sizeof(*pool));
|
||||
|
||||
@@ -932,8 +964,16 @@ mmc_pool_t *mmc_pool_new(TSRMLS_D) /* {{{ */
|
||||
default:
|
||||
pool->hash = &mmc_standard_hash;
|
||||
}
|
||||
|
||||
switch (MEMCACHE_G(hash_function)) {
|
||||
case MMC_HASH_FNV1A:
|
||||
hash = &mmc_hash_fnv1a;
|
||||
break;
|
||||
default:
|
||||
hash = &mmc_hash_crc32;
|
||||
}
|
||||
|
||||
pool->hash_state = pool->hash->create_state();
|
||||
pool->hash_state = pool->hash->create_state(hash);
|
||||
pool->min_compress_savings = MMC_DEFAULT_SAVINGS;
|
||||
|
||||
pool->sending = &(pool->_sending1);
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
|
||||
#define MMC_STANDARD_HASH 1
|
||||
#define MMC_CONSISTENT_HASH 2
|
||||
#define MMC_HASH_CRC32 1 /* CRC32 hash function */
|
||||
#define MMC_HASH_FNV1A 2 /* FNV-1a hash function */
|
||||
|
||||
#define MMC_CONSISTENT_POINTS 160 /* points per server */
|
||||
#define MMC_CONSISTENT_BUCKETS 1024 /* number of precomputed buckets, should be power of 2 */
|
||||
@@ -190,7 +192,8 @@ struct mmc {
|
||||
};
|
||||
|
||||
/* hashing strategy */
|
||||
typedef void * (*mmc_hash_create_state)();
|
||||
typedef unsigned int (*mmc_hash_function)(const char *, int);
|
||||
typedef void * (*mmc_hash_create_state)(mmc_hash_function);
|
||||
typedef void (*mmc_hash_free_state)(void *);
|
||||
typedef mmc_t * (*mmc_hash_find_server)(void *, const char *, int TSRMLS_DC);
|
||||
typedef void (*mmc_hash_add_server)(void *, mmc_t *, unsigned int);
|
||||
@@ -205,6 +208,10 @@ typedef struct mmc_hash {
|
||||
extern mmc_hash_t mmc_standard_hash;
|
||||
extern mmc_hash_t mmc_consistent_hash;
|
||||
|
||||
/* 32 bit magic FNV-1a prime and init */
|
||||
#define FNV_32_PRIME 0x01000193
|
||||
#define FNV_32_INIT 0x811c9dc5
|
||||
|
||||
/* server pool */
|
||||
struct mmc_pool {
|
||||
mmc_t **servers;
|
||||
@@ -269,6 +276,7 @@ ZEND_BEGIN_MODULE_GLOBALS(memcache)
|
||||
long default_port;
|
||||
long chunk_size;
|
||||
long hash_strategy;
|
||||
long hash_function;
|
||||
long allow_failover;
|
||||
long max_failover_attempts;
|
||||
ZEND_END_MODULE_GLOBALS(memcache)
|
||||
|
||||
@@ -33,12 +33,14 @@ typedef struct mmc_standard_state {
|
||||
int num_servers;
|
||||
mmc_t **buckets;
|
||||
int num_buckets;
|
||||
mmc_hash_function hash;
|
||||
} mmc_standard_state_t;
|
||||
|
||||
void *mmc_standard_create_state() /* {{{ */
|
||||
void *mmc_standard_create_state(mmc_hash_function hash) /* {{{ */
|
||||
{
|
||||
mmc_standard_state_t *state = emalloc(sizeof(mmc_standard_state_t));
|
||||
memset(state, 0, sizeof(mmc_standard_state_t));
|
||||
state->hash = hash;
|
||||
return state;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -55,26 +57,12 @@ void mmc_standard_free_state(void *s) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static unsigned int mmc_hash(const char *key, int key_len) /* {{{ */
|
||||
{
|
||||
unsigned int crc = ~0;
|
||||
int i;
|
||||
|
||||
for (i=0; i<key_len; i++) {
|
||||
CRC32(crc, key[i]);
|
||||
}
|
||||
|
||||
crc = (~crc >> 16) & 0x7fff;
|
||||
return crc ? crc : 1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
mmc_t *mmc_standard_find_server(void *s, const char *key, int key_len TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
mmc_standard_state_t *state = s;
|
||||
|
||||
if (state->num_servers > 1) {
|
||||
return state->buckets[mmc_hash(key, key_len) % state->num_buckets];
|
||||
return state->buckets[state->hash(key, key_len) % state->num_buckets];
|
||||
}
|
||||
|
||||
return state->buckets[0];
|
||||
|
||||
@@ -22,7 +22,7 @@ $result4 = $memcache->get(array($balanceKey1, $balanceKey2));
|
||||
var_dump($result1);
|
||||
var_dump($result2);
|
||||
var_dump($result3);
|
||||
var_dump(array_values($result4));
|
||||
var_dump(is_array($result4) ? array_values($result4) : $result4);
|
||||
|
||||
$memcache = new Memcache();
|
||||
$memcache->addServer($nonExistingHost, $nonExistingPort);
|
||||
|
||||
@@ -27,7 +27,8 @@ var_dump($result3);
|
||||
var_dump($result4);
|
||||
|
||||
$result = $memcache->get(array($balanceKey1, $balanceKey2));
|
||||
sort($result);
|
||||
if (is_array($result))
|
||||
sort($result);
|
||||
var_dump($result);
|
||||
|
||||
ini_set('memcache.allow_failover', 0);
|
||||
@@ -39,7 +40,8 @@ var_dump($result1);
|
||||
var_dump($result2);
|
||||
|
||||
$result = $memcache->get(array($balanceKey1, $balanceKey2));
|
||||
sort($result);
|
||||
if (is_array($result))
|
||||
sort($result);
|
||||
var_dump($result);
|
||||
|
||||
$result = ini_set('memcache.allow_failover', "abc");
|
||||
|
||||
Reference in New Issue
Block a user