mirror of
https://github.com/php-win-ext/pecl-memcache.git
synced 2026-03-24 00:52:07 +01:00
Supress SIGPIPE when calling send() and connection has died
Improved socket error reporting Improved performance by setting PHP_STREAM_BUFFER_NONE Fixed PECL bug #14642 (3.0.x breaks BC with 2.2.x)
This commit is contained in:
3
README
3
README
@@ -113,6 +113,9 @@ class MemcachePool() {
|
||||
* The new defval (default value) and exptime (expiration time) are used
|
||||
* if the key doesn't already exist. They must be supplied (even if 0) for
|
||||
* this to be enabled.
|
||||
*
|
||||
* Returns an integer with the new value if key is a string
|
||||
* Returns an array of integers if the key is an array
|
||||
*/
|
||||
mixed increment(mixed key, int value = 1, int defval = 0, int exptime = 0)
|
||||
mixed decrement(mixed key, int value = 1, int defval = 0, int exptime = 0)
|
||||
|
||||
120
memcache.c
120
memcache.c
@@ -374,9 +374,11 @@ static int mmc_get_pool(zval *id, mmc_pool_t **pool TSRMLS_DC) /* {{{ */
|
||||
int mmc_stored_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
|
||||
handles SET/ADD/REPLACE response, param is a zval pointer to store result into {{{ */
|
||||
{
|
||||
zval *result = (zval *)param;
|
||||
|
||||
if (response == MMC_OK) {
|
||||
if (param != NULL && Z_TYPE_P((zval *)param) == IS_NULL) {
|
||||
ZVAL_TRUE((zval *)param);
|
||||
if (Z_TYPE_P(result) == IS_NULL) {
|
||||
ZVAL_TRUE(result);
|
||||
}
|
||||
|
||||
return MMC_REQUEST_DONE;
|
||||
@@ -384,11 +386,10 @@ int mmc_stored_handler(mmc_t *mmc, mmc_request_t *request, int response, const c
|
||||
|
||||
/* return FALSE or catch memory errors without failover */
|
||||
if (response == MMC_RESPONSE_EXISTS || response == MMC_RESPONSE_OUT_OF_MEMORY || response == MMC_RESPONSE_TOO_LARGE) {
|
||||
if (param != NULL) {
|
||||
ZVAL_FALSE((zval *)param);
|
||||
}
|
||||
ZVAL_FALSE(result);
|
||||
|
||||
if (response != MMC_RESPONSE_EXISTS) {
|
||||
/* trigger notice but no need for failover */
|
||||
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d, udp %d) failed with: %s (%d)",
|
||||
mmc->host, mmc->tcp.port, mmc->udp.port, message, response);
|
||||
}
|
||||
@@ -455,14 +456,8 @@ static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, int op) /* {{{ */
|
||||
}
|
||||
|
||||
/* allocate request */
|
||||
if (return_value_used) {
|
||||
request = mmc_pool_request(pool, MMC_PROTO_TCP,
|
||||
mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
}
|
||||
else {
|
||||
request = mmc_pool_request(pool, MMC_PROTO_TCP,
|
||||
mmc_stored_handler, NULL, mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
}
|
||||
request = mmc_pool_request(pool, MMC_PROTO_TCP,
|
||||
mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
|
||||
if (mmc_prepare_key_ex(ZSTR_VAL(key), key_len, request->key, &(request->key_len)) != MMC_OK) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
|
||||
@@ -486,7 +481,6 @@ static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, int op) /* {{{ */
|
||||
}
|
||||
}
|
||||
else if (value) {
|
||||
|
||||
/* allocate request */
|
||||
request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
|
||||
@@ -523,17 +517,28 @@ static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, int op) /* {{{ */
|
||||
static int mmc_numeric_response_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
|
||||
handles a mutate response line, param is a zval pointer to store result into {{{ */
|
||||
{
|
||||
zval *result = (zval *)param;
|
||||
|
||||
if (response == MMC_OK) {
|
||||
if (param != NULL && Z_TYPE_P((zval *)param) == IS_NULL) {
|
||||
ZVAL_TRUE((zval *)param);
|
||||
if (Z_TYPE_P(result) == IS_ARRAY) {
|
||||
add_assoc_bool_ex(result, request->key, request->key_len + 1, 1);
|
||||
}
|
||||
else if (Z_TYPE_P(result) == IS_NULL) {
|
||||
/* switch only from null to true, not from false to true */
|
||||
ZVAL_TRUE(result);
|
||||
}
|
||||
|
||||
return MMC_REQUEST_DONE;
|
||||
}
|
||||
|
||||
if (response == MMC_RESPONSE_NOT_FOUND) {
|
||||
if (param != NULL) {
|
||||
ZVAL_FALSE((zval *)param);
|
||||
if (Z_TYPE_P(result) == IS_ARRAY) {
|
||||
add_assoc_bool_ex(result, request->key, request->key_len + 1, 0);
|
||||
}
|
||||
else {
|
||||
ZVAL_FALSE(result);
|
||||
}
|
||||
|
||||
return MMC_REQUEST_DONE;
|
||||
}
|
||||
|
||||
@@ -551,15 +556,34 @@ static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int inver
|
||||
long value = 1, defval = 0, exptime = 0;
|
||||
mmc_request_t *request;
|
||||
void *value_handler_param[3];
|
||||
int defval_used = 0;
|
||||
|
||||
if (mmc_object == NULL) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|lll", &mmc_object, memcache_pool_ce, &keys, &value, &defval, &exptime) == FAILURE) {
|
||||
return;
|
||||
if (deleted) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|l", &mmc_object, memcache_pool_ce, &keys, &value) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|lll", &mmc_object, memcache_pool_ce, &keys, &value, &defval, &exptime) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
defval_used = ZEND_NUM_ARGS() >= 4;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|lll", &keys, &value, &defval, &exptime) == FAILURE) {
|
||||
return;
|
||||
if (deleted) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &keys, &value) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|lll", &keys, &value, &defval, &exptime) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
defval_used = ZEND_NUM_ARGS() >= 3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +591,6 @@ static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int inver
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
ZVAL_NULL(return_value);
|
||||
value_handler_param[0] = return_value;
|
||||
value_handler_param[1] = NULL;
|
||||
value_handler_param[2] = NULL;
|
||||
@@ -575,22 +598,24 @@ static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int inver
|
||||
if (Z_TYPE_P(keys) == IS_ARRAY) {
|
||||
zval **key;
|
||||
HashPosition pos;
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
|
||||
|
||||
if (deleted) {
|
||||
/* changed to true/false by mmc_numeric_response_handler */
|
||||
RETVAL_NULL();
|
||||
}
|
||||
else {
|
||||
/* populated with responses by mmc_numeric_response_handler and mmc_value_handler_multi */
|
||||
array_init(return_value);
|
||||
}
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
|
||||
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
|
||||
|
||||
/* allocate request */
|
||||
if (return_value_used) {
|
||||
request = mmc_pool_request(
|
||||
pool, MMC_PROTO_TCP, mmc_numeric_response_handler, return_value,
|
||||
mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
}
|
||||
else {
|
||||
request = mmc_pool_request(
|
||||
pool, MMC_PROTO_TCP, mmc_numeric_response_handler, NULL,
|
||||
mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
}
|
||||
request = mmc_pool_request(
|
||||
pool, MMC_PROTO_TCP, mmc_numeric_response_handler, return_value,
|
||||
mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
|
||||
request->value_handler = mmc_value_handler_multi;
|
||||
request->value_handler_param = value_handler_param;
|
||||
@@ -605,7 +630,7 @@ static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int inver
|
||||
pool->protocol->delete(request, request->key, request->key_len, value);
|
||||
}
|
||||
else {
|
||||
pool->protocol->mutate(request, *key, request->key, request->key_len, invert ? -value : value, defval, exptime);
|
||||
pool->protocol->mutate(request, *key, request->key, request->key_len, invert ? -value : value, defval, defval_used, exptime);
|
||||
}
|
||||
|
||||
/* schedule request */
|
||||
@@ -618,16 +643,13 @@ static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int inver
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (deleted) {
|
||||
RETVAL_NULL();
|
||||
}
|
||||
else {
|
||||
RETVAL_FALSE;
|
||||
}
|
||||
/* changed to true/false by mmc_numeric_response_handler or set to a value
|
||||
* by mmc_value_handler_single if incr/decr returns one */
|
||||
RETVAL_NULL();
|
||||
|
||||
/* allocate request */
|
||||
request = mmc_pool_request(pool, MMC_PROTO_TCP,
|
||||
mmc_numeric_response_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
mmc_numeric_response_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
|
||||
|
||||
request->value_handler = mmc_value_handler_single;
|
||||
request->value_handler_param = value_handler_param;
|
||||
@@ -642,7 +664,7 @@ static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int inver
|
||||
pool->protocol->delete(request, request->key, request->key_len, value);
|
||||
}
|
||||
else {
|
||||
pool->protocol->mutate(request, keys, request->key, request->key_len, invert ? -value : value, defval, exptime);
|
||||
pool->protocol->mutate(request, keys, request->key, request->key_len, invert ? -value : value, defval, defval_used, exptime);
|
||||
}
|
||||
|
||||
/* schedule request */
|
||||
@@ -1530,7 +1552,6 @@ PHP_FUNCTION(memcache_get)
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
ZVAL_FALSE(return_value);
|
||||
value_handler_param[0] = return_value;
|
||||
value_handler_param[1] = flags;
|
||||
value_handler_param[2] = cas;
|
||||
@@ -1538,12 +1559,14 @@ PHP_FUNCTION(memcache_get)
|
||||
if (Z_TYPE_P(keys) == IS_ARRAY) {
|
||||
zval **key;
|
||||
HashPosition pos;
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
|
||||
|
||||
|
||||
/* return empty array if no keys found */
|
||||
array_init(return_value);
|
||||
|
||||
failover_handler_param[0] = keys;
|
||||
failover_handler_param[1] = value_handler_param;
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
|
||||
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
|
||||
|
||||
@@ -1556,6 +1579,9 @@ PHP_FUNCTION(memcache_get)
|
||||
}
|
||||
else {
|
||||
mmc_request_t *request;
|
||||
|
||||
/* return false if key isn't found */
|
||||
ZVAL_FALSE(return_value);
|
||||
|
||||
/* allocate request */
|
||||
request = mmc_pool_request_get(
|
||||
|
||||
@@ -332,7 +332,7 @@ static void mmc_ascii_delete(mmc_request_t *request, const char *key, unsigned i
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void mmc_ascii_mutate(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, unsigned int exptime) /* {{{ */
|
||||
static void mmc_ascii_mutate(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, int defval_used, unsigned int exptime) /* {{{ */
|
||||
{
|
||||
request->parse = mmc_request_parse_mutate;
|
||||
|
||||
|
||||
@@ -493,7 +493,7 @@ static void mmc_binary_delete(mmc_request_t *request, const char *key, unsigned
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void mmc_binary_mutate(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, unsigned int exptime) /* {{{ */
|
||||
static void mmc_binary_mutate(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, int defval_used, unsigned int exptime) /* {{{ */
|
||||
{
|
||||
mmc_mutate_request_header_t header;
|
||||
mmc_binary_request_t *req = (mmc_binary_request_t *)request;
|
||||
@@ -511,7 +511,15 @@ static void mmc_binary_mutate(mmc_request_t *request, zval *zkey, const char *ke
|
||||
}
|
||||
|
||||
header.defval = htonll(defval);
|
||||
header.exptime = htonl(exptime);
|
||||
|
||||
if (defval_used) {
|
||||
/* server inserts defval if key doesn't exist */
|
||||
header.exptime = htonl(exptime);
|
||||
}
|
||||
else {
|
||||
/* server replies with NOT_FOUND if exptime ~0 and key doesn't exist */
|
||||
header.exptime = ~(uint32_t)0;
|
||||
}
|
||||
|
||||
smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
|
||||
smart_str_appendl(&(request->sendbuf.value), key, key_len);
|
||||
|
||||
101
memcache_pool.c
101
memcache_pool.c
@@ -164,14 +164,15 @@ void mmc_request_free(mmc_request_t *request) /* {{{ */
|
||||
|
||||
static inline int mmc_request_send(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
int count, bytes;
|
||||
|
||||
/* send next chunk of buffer */
|
||||
int count = request->sendbuf.value.len - request->sendbuf.idx;
|
||||
count = request->sendbuf.value.len - request->sendbuf.idx;
|
||||
if (count > request->io->stream->chunk_size) {
|
||||
count = request->io->stream->chunk_size;
|
||||
}
|
||||
|
||||
int bytes = send(request->io->fd, request->sendbuf.value.c + request->sendbuf.idx, count, 0);
|
||||
|
||||
bytes = send(request->io->fd, request->sendbuf.value.c + request->sendbuf.idx, count, MSG_NOSIGNAL);
|
||||
if (bytes >= 0) {
|
||||
request->sendbuf.idx += bytes;
|
||||
|
||||
@@ -182,13 +183,17 @@ static inline int mmc_request_send(mmc_t *mmc, mmc_request_t *request TSRMLS_DC)
|
||||
|
||||
return MMC_REQUEST_MORE;
|
||||
}
|
||||
|
||||
long err = php_socket_errno();
|
||||
if (err == EAGAIN) {
|
||||
return MMC_REQUEST_MORE;
|
||||
else {
|
||||
char *message, buf[1024];
|
||||
long err = php_socket_errno();
|
||||
|
||||
if (err == EAGAIN) {
|
||||
return MMC_REQUEST_MORE;
|
||||
}
|
||||
|
||||
message = php_socket_strerror(err, buf, 1024);
|
||||
return mmc_server_failure(mmc, request->io, message, err TSRMLS_CC);
|
||||
}
|
||||
|
||||
return mmc_server_failure(mmc, request->io, "Write failed (socket unexpectedly closed)", err TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -548,7 +553,9 @@ static void _mmc_server_disconnect(mmc_t *mmc, mmc_stream_t *io, int close_persi
|
||||
else {
|
||||
php_stream_close(io->stream);
|
||||
}
|
||||
|
||||
io->stream = NULL;
|
||||
io->fd = 0;
|
||||
}
|
||||
|
||||
io->status = MMC_STATUS_DISCONNECTED;
|
||||
@@ -645,7 +652,7 @@ int mmc_request_failure(mmc_t *mmc, mmc_stream_t *io, const char *message, unsig
|
||||
checks for a valid server generated error message and calls mmc_server_failure() {{{ */
|
||||
{
|
||||
if (message_len) {
|
||||
return mmc_server_failure(mmc, io, message, errnum TSRMLS_CC);;
|
||||
return mmc_server_failure(mmc, io, message, errnum TSRMLS_CC);
|
||||
}
|
||||
|
||||
return mmc_server_failure(mmc, io, "Malformed server response", errnum TSRMLS_CC);
|
||||
@@ -699,6 +706,7 @@ static int mmc_server_connect(mmc_pool_t *pool, mmc_t *mmc, mmc_stream_t *io, in
|
||||
if (php_stream_eof(io->stream)) {
|
||||
php_stream_pclose(io->stream);
|
||||
io->stream = NULL;
|
||||
io->fd = 0;
|
||||
break;
|
||||
}
|
||||
case PHP_STREAM_PERSISTENT_FAILURE:
|
||||
@@ -742,23 +750,24 @@ static int mmc_server_connect(mmc_pool_t *pool, mmc_t *mmc, mmc_stream_t *io, in
|
||||
io->status = MMC_STATUS_CONNECTED;
|
||||
|
||||
php_stream_auto_cleanup(io->stream);
|
||||
php_stream_set_chunk_size(io->stream, io->chunk_size);
|
||||
php_stream_set_option(io->stream, PHP_STREAM_OPTION_BLOCKING, 0, NULL);
|
||||
php_stream_set_option(io->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
|
||||
|
||||
/* doing our own buffering increases performance */
|
||||
php_stream_set_option(io->stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
|
||||
php_stream_set_option(io->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
|
||||
|
||||
/* php_stream buffering prevent us from detecting datagram boundaries when using udp */
|
||||
if (udp) {
|
||||
io->read = mmc_stream_read_buffered;
|
||||
io->readline = mmc_stream_readline_buffered;
|
||||
php_stream_set_option(io->stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
|
||||
}
|
||||
else {
|
||||
io->read = mmc_stream_read_wrapper;
|
||||
io->readline = mmc_stream_readline_wrapper;
|
||||
}
|
||||
|
||||
php_stream_set_option(io->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
|
||||
php_stream_set_chunk_size(io->stream, io->chunk_size);
|
||||
|
||||
if (mmc->error != NULL) {
|
||||
efree(mmc->error);
|
||||
mmc->error = NULL;
|
||||
@@ -1290,19 +1299,32 @@ static inline void mmc_pool_switch(mmc_pool_t *pool) {
|
||||
mmc_queue_reset(pool->reading);
|
||||
}
|
||||
|
||||
static void mmc_select_failure(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, int result TSRMLS_DC) /* {{{ */
|
||||
static int mmc_select_failure(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, int result TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (result == 0) {
|
||||
/* timeout expired, non-responsive server */
|
||||
if (mmc_server_failure(mmc, request->io, "Network timeout", 0 TSRMLS_CC) != MMC_REQUEST_RETRY) {
|
||||
mmc_server_deactivate(pool, mmc TSRMLS_CC);
|
||||
if (mmc_server_failure(mmc, request->io, "Network timeout", 0 TSRMLS_CC) == MMC_REQUEST_RETRY) {
|
||||
return MMC_REQUEST_RETRY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* hard failure, deactivate connection */
|
||||
mmc_server_seterror(mmc, "Unknown select() error", errno);
|
||||
mmc_server_deactivate(pool, mmc TSRMLS_CC);
|
||||
char buf[1024];
|
||||
const char *message;
|
||||
long err = php_socket_errno();
|
||||
|
||||
if (err) {
|
||||
message = php_socket_strerror(err, buf, 1024);
|
||||
}
|
||||
else {
|
||||
message = "Unknown select() error";
|
||||
}
|
||||
|
||||
mmc_server_seterror(mmc, message, errno);
|
||||
}
|
||||
|
||||
/* hard failure, deactivate connection */
|
||||
mmc_server_deactivate(pool, mmc TSRMLS_CC);
|
||||
return MMC_REQUEST_FAILURE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -1392,15 +1414,27 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
mmc = (mmc_t *)mmc_queue_item(sending, i);
|
||||
if (!FD_ISSET(mmc->sendreq->io->fd, &(pool->wfds))) {
|
||||
mmc_queue_remove(sending, mmc);
|
||||
mmc_select_failure(pool, mmc, mmc->sendreq, result TSRMLS_CC);
|
||||
mmc_queue_remove(reading, mmc);
|
||||
i--;
|
||||
|
||||
if (mmc_select_failure(pool, mmc, mmc->sendreq, result TSRMLS_CC) == MMC_REQUEST_RETRY) {
|
||||
/* allow request to try and send again */
|
||||
mmc_select_retry(pool, mmc, mmc->sendreq TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i < reading->len; i++) {
|
||||
mmc = (mmc_t *)mmc_queue_item(reading, i);
|
||||
if (!FD_ISSET(mmc->readreq->io->fd, &(pool->rfds))) {
|
||||
mmc_queue_remove(sending, mmc);
|
||||
mmc_queue_remove(reading, mmc);
|
||||
mmc_select_failure(pool, mmc, mmc->readreq, result TSRMLS_CC);
|
||||
i--;
|
||||
|
||||
if (mmc_select_failure(pool, mmc, mmc->readreq, result TSRMLS_CC) == MMC_REQUEST_RETRY) {
|
||||
/* allow request to try and read again */
|
||||
mmc_select_retry(pool, mmc, mmc->readreq TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1408,7 +1442,6 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
pool->in_select = 1;
|
||||
}
|
||||
|
||||
/* until stream buffer is empty */
|
||||
for (i=0; i < sending->len; i++) {
|
||||
mmc = mmc_queue_item(sending, i);
|
||||
|
||||
@@ -1419,7 +1452,11 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
|
||||
if (FD_ISSET(mmc->sendreq->io->fd, &(pool->wfds))) {
|
||||
fd = mmc->sendreq->io->fd;
|
||||
|
||||
|
||||
/* clear bit for reentrancy reasons */
|
||||
FD_CLR(fd, &(pool->wfds));
|
||||
|
||||
/* until stream buffer is empty */
|
||||
do {
|
||||
/* delegate to request send handler */
|
||||
result = mmc_request_send(mmc, mmc->sendreq TSRMLS_CC);
|
||||
@@ -1431,11 +1468,11 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
|
||||
switch (result) {
|
||||
case MMC_REQUEST_FAILURE:
|
||||
/* clear readbit for this round */
|
||||
FD_CLR(mmc->sendreq->io->fd, &(pool->rfds));
|
||||
|
||||
/* take server offline and failover requests */
|
||||
mmc_server_deactivate(pool, mmc TSRMLS_CC);
|
||||
|
||||
/* server is failed, remove from read queue */
|
||||
mmc_queue_remove(reading, mmc);
|
||||
break;
|
||||
|
||||
case MMC_REQUEST_RETRY:
|
||||
@@ -1461,9 +1498,6 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
/* add server to read queue once more */
|
||||
mmc_queue_push(pool->sending, mmc);
|
||||
}
|
||||
|
||||
/* clear bit for reentrancy reasons */
|
||||
FD_CLR(fd, &(pool->wfds));
|
||||
}
|
||||
else {
|
||||
/* add server to send queue once more */
|
||||
@@ -1482,6 +1516,9 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
if (FD_ISSET(mmc->readreq->io->fd, &(pool->rfds))) {
|
||||
fd = mmc->readreq->io->fd;
|
||||
|
||||
/* clear bit for reentrancy reasons */
|
||||
FD_CLR(fd, &(pool->rfds));
|
||||
|
||||
/* fill read buffer if needed */
|
||||
if (mmc->readreq->read != NULL) {
|
||||
result = mmc->readreq->read(mmc, mmc->readreq TSRMLS_CC);
|
||||
@@ -1512,6 +1549,7 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
}
|
||||
}
|
||||
|
||||
/* until stream buffer is empty */
|
||||
do {
|
||||
/* delegate to request response handler */
|
||||
result = mmc->readreq->parse(mmc, mmc->readreq TSRMLS_CC);
|
||||
@@ -1578,9 +1616,6 @@ void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
|
||||
/* add server to read queue once more */
|
||||
mmc_queue_push(pool->reading, mmc);
|
||||
}
|
||||
|
||||
/* clear bit for reentrancy reasons */
|
||||
FD_CLR(fd, &(pool->rfds));
|
||||
}
|
||||
else {
|
||||
/* add server to read queue once more */
|
||||
|
||||
@@ -230,7 +230,7 @@ typedef int (*mmc_protocol_store)(
|
||||
mmc_pool_t *pool, mmc_request_t *request, int op, const char *key, unsigned int key_len,
|
||||
unsigned int flags, unsigned int exptime, unsigned long cas, zval *value TSRMLS_DC);
|
||||
typedef void (*mmc_protocol_delete)(mmc_request_t *request, const char *key, unsigned int key_len, unsigned int exptime);
|
||||
typedef void (*mmc_protocol_mutate)(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, unsigned int exptime);
|
||||
typedef void (*mmc_protocol_mutate)(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, int defval_used, unsigned int exptime);
|
||||
|
||||
typedef void (*mmc_protocol_flush)(mmc_request_t *request, unsigned int exptime);
|
||||
typedef void (*mmc_protocol_stats)(mmc_request_t *request, const char *type, long slabid, long limit);
|
||||
|
||||
@@ -36,8 +36,9 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
</stability>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>
|
||||
Improved performance of consistent hash strategy
|
||||
Fixed PECL request #13758 (Failed to extract 'connection' variable from object)
|
||||
- Improved performance of consistent hash strategy
|
||||
- Fixed PECL bug #14642 (3.0.x breaks BC with 2.2.x)
|
||||
- Fixed PECL request #13758 (Failed to extract 'connection' variable from object)
|
||||
</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
|
||||
38
profile.php
38
profile.php
@@ -5,6 +5,8 @@
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('memcache.hash_strategy', 'consistent');
|
||||
//ini_set('memcache.protocol', 'binary');
|
||||
$threshold = 0;
|
||||
|
||||
$count = 50; // Keys per interation (multi-key operations do $count keys at a time)
|
||||
$reps = 1000; // Number of iterations
|
||||
@@ -17,19 +19,19 @@ $hosts = array(
|
||||
$pools = array();
|
||||
|
||||
$tests1 = array(
|
||||
array('test_get_single', 'Single-Get'),
|
||||
array('test_get_multi', 'Multi-Get'),
|
||||
array('test_get_single_obj', 'Get-Object'),
|
||||
array('test_get_multi_obj', 'MulGet-Object'),
|
||||
);
|
||||
|
||||
$tests2 = array(
|
||||
array('test_set_single', 'Single-Set'),
|
||||
array('test_set_single_obj', 'Set-Object'),
|
||||
array('test_incr_single', 'Single-Incr'),
|
||||
array('test_delete_single', 'Single-Del'),
|
||||
);
|
||||
|
||||
$tests2 = array(
|
||||
array('test_get_single', 'Single-Get'),
|
||||
array('test_get_multi', 'Multi-Get'),
|
||||
array('test_get_single_obj', 'Get-Object'),
|
||||
array('test_get_multi_obj', 'MulGet-Object'),
|
||||
);
|
||||
|
||||
$tests3 = array(
|
||||
array('test_set_multi', 'Multi-Set'),
|
||||
array('test_set_multi_obj', 'MulSet-Object'),
|
||||
@@ -83,11 +85,13 @@ function run_tests($pools, $tests) {
|
||||
// Create pools to run all tests against
|
||||
$memcache1 = new Memcache();
|
||||
$memcache1->connect($hosts[0][0], $hosts[0][1]);
|
||||
$memcache1->setCompressThreshold($threshold);
|
||||
$pools[] = array($memcache1, 'TCP (1 server)');
|
||||
|
||||
if (class_exists('MemcachePool')) {
|
||||
$memcache2 = new MemcachePool();
|
||||
$memcache2->connect($hosts[0][0], $hosts[0][1], $hosts[0][2], false);
|
||||
$memcache2->setCompressThreshold($threshold);
|
||||
$pools[] = array($memcache2, 'UDP (1 server)');
|
||||
}
|
||||
|
||||
@@ -95,12 +99,14 @@ if (count($hosts) > 1) {
|
||||
$memcache3 = new Memcache();
|
||||
foreach ($hosts as $h)
|
||||
$memcache3->connect($h[0], $h[1]);
|
||||
$memcache3->setCompressThreshold($threshold);
|
||||
$pools[] = array($memcache3, sprintf('TCP (%d servers)', count($hosts)));
|
||||
|
||||
if (class_exists('MemcachePool')) {
|
||||
$memcache4 = new MemcachePool();
|
||||
foreach ($hosts as $h)
|
||||
$memcache4->connect($h[0], $h[1], $h[2], false);
|
||||
$memcache4->setCompressThreshold($threshold);
|
||||
$pools[] = array($memcache4, sprintf('UDP (%d servers)', count($hosts)));
|
||||
}
|
||||
}
|
||||
@@ -115,19 +121,21 @@ $key2 = 'test_key_int';
|
||||
$key3 = 'test_key_obj';
|
||||
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
$values[$key.$i] = $key.'_value_'.$i;
|
||||
$values[$key.$i] = $key.'_value_'.$i.str_repeat('a', $i*1000);
|
||||
$ints[$key2.$i] = $i;
|
||||
$objects[$key3.$i] = new TestClass(new TestClass(new TestClass()));
|
||||
$objects[$key3.$i] = new TestClass(new TestClass(new TestClass(str_repeat('a', $i*100))));
|
||||
}
|
||||
|
||||
print "Measures are in keys-per-second (higher is better) with number of seconds\nspent in test within parentheses (lower is better).\n\n";
|
||||
|
||||
// Configuration
|
||||
printf("memcache.hash_strategy: %s\n", ini_get('memcache.hash_strategy'));
|
||||
printf("memcache.chunk_size: %u\n", ini_get('memcache.chunk_size'));
|
||||
printf("servers: %d\n", count($hosts));
|
||||
printf("iterations: %d\n", $reps);
|
||||
printf("keys per iteration: %d\n", $count);
|
||||
printf("memcache.hash_strategy: %s\n", ini_get('memcache.hash_strategy'));
|
||||
printf("memcache.chunk_size: %u\n", ini_get('memcache.chunk_size'));
|
||||
printf("memcache.protocol: %s\n", ini_get('memcache.protocol'));
|
||||
printf("memcache.compress_threshold: %s\n", $threshold);
|
||||
printf("servers: %d\n", count($hosts));
|
||||
printf("iterations: %d\n", $reps);
|
||||
printf("keys per iteration: %d\n", $count);
|
||||
print "\n";
|
||||
|
||||
$ts = time();
|
||||
@@ -146,7 +154,7 @@ printf("total time: %d minutes, %d seconds\n", floor(($ts2 - $ts)/60), ($ts2 - $
|
||||
// Tests
|
||||
class TestClass {
|
||||
function __construct($obj = null) {
|
||||
$this->v1 = str_repeat('abc', 250);
|
||||
$this->v1 = str_repeat('abc', 25);
|
||||
$this->v2 = 123;
|
||||
$this->v3 = 123.123;
|
||||
$this->v4 = array('abc', 123);
|
||||
|
||||
@@ -20,7 +20,10 @@ var_dump($result);
|
||||
$result = memcache_get($memcache, 'test_key');
|
||||
var_dump($result);
|
||||
|
||||
$result = memcache_get($memcache, Array('test_key', 'test_key1'));
|
||||
$result = memcache_get($memcache, array('test_key', 'test_key1'));
|
||||
var_dump($result);
|
||||
|
||||
$result = memcache_get($memcache, array('unset_test_key', 'unset_test_key1'));
|
||||
var_dump($result);
|
||||
|
||||
?>
|
||||
@@ -64,3 +67,5 @@ array(2) {
|
||||
}
|
||||
}
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
@@ -117,7 +117,7 @@ var_dump($result);
|
||||
$keys = array_keys($values);
|
||||
$result = $memcache->get($keys);
|
||||
var_dump($keys);
|
||||
var_dump($result);
|
||||
var_dump(array_values($result));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
@@ -192,8 +192,8 @@ array(2) {
|
||||
string(9) "test test"
|
||||
}
|
||||
array(2) {
|
||||
["_"]=>
|
||||
[0]=>
|
||||
string(5) "value"
|
||||
["test_test"]=>
|
||||
[1]=>
|
||||
string(6) "value2"
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ $var = new stdClass;
|
||||
$var->plain_attribute = 'value';
|
||||
$var->array_attribute = Array('test1', 'test2');
|
||||
|
||||
$memcache->get('test_key');
|
||||
|
||||
$result = $memcache->get('test_key');
|
||||
var_dump($result);
|
||||
|
||||
$result = $memcache->get(array('unset_test_key', 'unset_test_key1'));
|
||||
var_dump($result);
|
||||
|
||||
?>
|
||||
@@ -30,3 +30,5 @@ object(stdClass)%s2) {
|
||||
string(5) "test2"
|
||||
}
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
|
||||
@@ -35,12 +35,6 @@ $largeval = str_repeat('a', 1024*2048);
|
||||
$_SESSION['_test_key']= $largeval;
|
||||
session_write_close();
|
||||
|
||||
ini_set('memcache.compress_threshold', 0);
|
||||
session_start();
|
||||
$largeval = str_repeat('a', 1024*2048);
|
||||
$_SESSION['_test_key']= $largeval;
|
||||
session_write_close();
|
||||
|
||||
var_dump($result1);
|
||||
var_dump($id);
|
||||
var_dump($result2);
|
||||
@@ -51,10 +45,6 @@ var_dump($result6);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
%s: SERVER_ERROR object too large for cache
|
||||
(3) in %s
|
||||
|
||||
Warning: session_write_close(): Failed to write session data (memcache). %s
|
||||
bool(true)
|
||||
string(%d) "%s"
|
||||
bool(false)
|
||||
|
||||
@@ -28,6 +28,12 @@ var_dump($result);
|
||||
$result = memcache_decrement($memcache, array($balanceKey1, $balanceKey2), 1);
|
||||
var_dump($result);
|
||||
|
||||
$result = $memcache->increment(array());
|
||||
var_dump($result);
|
||||
|
||||
$result = $memcache->increment(array('unset_test_key', 'unset_test_key1'));
|
||||
var_dump($result);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(2) {
|
||||
@@ -56,3 +62,11 @@ array(2) {
|
||||
["%s"]=>
|
||||
int(2)
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
array(2) {
|
||||
["%s"]=>
|
||||
bool(false)
|
||||
["%s"]=>
|
||||
bool(false)
|
||||
}
|
||||
|
||||
@@ -52,4 +52,5 @@ bool(false)
|
||||
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
array(0) {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user