Changes of Revision 9
[-] | Changed | php5-pecl-memcache.changes |
x 1
2 ------------------------------------------------------------------- 3 +Fri Apr 12 17:28:07 UTC 2013 - cs@linux-administrator.com 4 + 5 +- version 2.0.7 6 +- PHP 5.4 compatibility 7 +- Fixed return value error get_host_port_from_server(). 8 +- Fixed PECL Bug #16672 (memcache.php doesn't support unix socket) 9 +- Fixed pecl bug #19374 (memcache.php throws Notice: Undefined index: VALUE when viewing expired items) 10 + 11 +------------------------------------------------------------------- 12 Mon Oct 4 09:04:38 UTC 2010 - cs@linux-administrator.com 13 14 - Fixed pecl bug #16536 (Weight of 0 causes SegFault on memcache_add_server) 15 |
||
[-] | Changed | php5-pecl-memcache.spec ^ |
10 1
2 %define php_version %(php-config --version 2>/dev/null) 3 4 Name: php5-pecl-memcache 5 -Version: 2.2.6 6 +Version: 2.2.7 7 Release: 1 8 # 9 Group: Productivity/Networking/Web/Servers 10 |
||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/config.m4 ^ |
@@ -1,4 +0,0 @@ -dnl $Id: config.m4,v 1.11 2006/11/15 21:05:03 tony2001 Exp $ -dnl this file is required by phpize - -sinclude(config9.m4) | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/config.w32 ^ |
@@ -1,14 +0,0 @@ -// $Id: config.w32,v 1.7 2007/11/26 20:12:00 mikl Exp $ -// vim:ft=javascript - -ARG_ENABLE("memcache", "memcache support", "no"); - -if (PHP_MEMCACHE != "no") { - if (!PHP_ZLIB_SHARED || CHECK_LIB("zlib.lib", "memcache", PHP_MEMCACHE)) { - EXTENSION("memcache", "memcache.c memcache_queue.c memcache_standard_hash.c memcache_consistent_hash.c memcache_session.c"); - AC_DEFINE('HAVE_MEMCACHE', 1, 'Have memcache support'); - ADD_FLAG("CFLAGS_MEMCACHE", "/D HAVE_MEMCACHE_SESSION=1"); - } else { - WARNING("memcache not enabled; libraries and headers not found"); - } -} | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/config9.m4 ^ |
@@ -1,112 +0,0 @@ -dnl -dnl $Id: config9.m4,v 1.9 2007/11/01 14:30:16 mikl Exp $ -dnl - -PHP_ARG_ENABLE(memcache, whether to enable memcache support, -[ --enable-memcache Enable memcache support]) - -PHP_ARG_ENABLE(memcache-session, whether to enable memcache session handler support, -[ --disable-memcache-session Disable memcache session handler support], yes, no) - -if test -z "$PHP_ZLIB_DIR"; then -PHP_ARG_WITH(zlib-dir, for the location of ZLIB, -[ --with-zlib-dir[=DIR] memcache: Set the path to ZLIB install prefix.], no, no) -fi - -if test -z "$PHP_DEBUG"; then - AC_ARG_ENABLE(debug, - [ --enable-debug compile with debugging symbols],[ - PHP_DEBUG=$enableval - ],[ - PHP_DEBUG=no - ]) -fi - -if test "$PHP_MEMCACHE" != "no"; then - - if test "$PHP_ZLIB_DIR" != "no" && test "$PHP_ZLIB_DIR" != "yes"; then - if test -f "$PHP_ZLIB_DIR/include/zlib/zlib.h"; then - PHP_ZLIB_DIR="$PHP_ZLIB_DIR" - PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include/zlib" - elif test -f "$PHP_ZLIB_DIR/include/zlib.h"; then - PHP_ZLIB_DIR="$PHP_ZLIB_DIR" - PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include" - else - AC_MSG_ERROR([Can't find ZLIB headers under "$PHP_ZLIB_DIR"]) - fi - else - for i in /usr/local /usr; do - if test -f "$i/include/zlib/zlib.h"; then - PHP_ZLIB_DIR="$i" - PHP_ZLIB_INCDIR="$i/include/zlib" - elif test -f "$i/include/zlib.h"; then - PHP_ZLIB_DIR="$i" - PHP_ZLIB_INCDIR="$i/include" - fi - done - fi - - dnl # zlib - AC_MSG_CHECKING([for the location of zlib]) - if test "$PHP_ZLIB_DIR" = "no"; then - AC_MSG_ERROR([memcache support requires ZLIB. Use --with-zlib-dir=<DIR> to specify prefix where ZLIB include and library are located]) - else - AC_MSG_RESULT([$PHP_ZLIB_DIR]) - if test "z$PHP_LIBDIR" != "z"; then - dnl PHP5+ - PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR/$PHP_LIBDIR, MEMCACHE_SHARED_LIBADD) - else - dnl PHP4 - PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR/lib, MEMCACHE_SHARED_LIBADD) - fi - PHP_ADD_INCLUDE($PHP_ZLIB_INCDIR) - fi - - if test "$PHP_MEMCACHE_SESSION" != "no"; then - AC_MSG_CHECKING([for session includes]) - session_inc_path="" - - if test -f "$abs_srcdir/include/php/ext/session/php_session.h"; then - session_inc_path="$abs_srcdir/include/php" - elif test -f "$abs_srcdir/ext/session/php_session.h"; then - session_inc_path="$abs_srcdir" - elif test -f "$phpincludedir/ext/session/php_session.h"; then - session_inc_path="$phpincludedir" - else - for i in php php4 php5 php6; do - if test -f "$prefix/include/$i/ext/session/php_session.h"; then - session_inc_path="$prefix/include/$i" - fi - done - fi - - if test "$session_inc_path" = ""; then - AC_MSG_ERROR([Cannot find php_session.h]) - else - AC_MSG_RESULT([$session_inc_path]) - fi - fi - - AC_MSG_CHECKING([for memcache session support]) - if test "$PHP_MEMCACHE_SESSION" != "no"; then - AC_MSG_RESULT([enabled]) - AC_DEFINE(HAVE_MEMCACHE_SESSION,1,[Whether memcache session handler is enabled]) - AC_DEFINE(HAVE_MEMCACHE,1,[Whether you want memcache support]) - PHP_NEW_EXTENSION(memcache, memcache.c memcache_queue.c memcache_standard_hash.c memcache_consistent_hash.c memcache_session.c, $ext_shared,,-I$session_inc_path) - ifdef([PHP_ADD_EXTENSION_DEP], - [ - PHP_ADD_EXTENSION_DEP(memcache, session) - ]) - else - AC_MSG_RESULT([disabled]) - AC_DEFINE(HAVE_MEMCACHE,1,[Whether you want memcache support]) - PHP_NEW_EXTENSION(memcache, memcache.c memcache_queue.c memcache_standard_hash.c memcache_consistent_hash.c, $ext_shared) - fi - -dnl this is needed to build the extension with phpize and -Wall - - if test "$PHP_DEBUG" = "yes"; then - CFLAGS="$CFLAGS -Wall" - fi - -fi | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/memcache.c ^ |
@@ -1,2704 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2007 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Antony Dovgal <tony@daylessday.org> | - | Mikael Johansson <mikael AT synd DOT info> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: memcache.c,v 1.111 2009/01/15 18:15:50 mikl Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#include "php_ini.h" -#include <stdio.h> -#include <fcntl.h> -#ifdef HAVE_SYS_FILE_H -#include <sys/file.h> -#endif - -#include <zlib.h> -#include <time.h> -#include "ext/standard/crc32.h" -#include "ext/standard/info.h" -#include "ext/standard/php_string.h" -#include "ext/standard/php_var.h" -#include "ext/standard/php_smart_str.h" -#include "php_network.h" -#include "php_memcache.h" -#include "memcache_queue.h" - -#ifndef ZEND_ENGINE_2 -#define OnUpdateLong OnUpdateInt -#endif - -/* True global resources - no need for thread safety here */ -static int le_memcache_pool, le_pmemcache; -static zend_class_entry *memcache_class_entry_ptr; - -ZEND_DECLARE_MODULE_GLOBALS(memcache) - -/* {{{ memcache_functions[] - */ -zend_function_entry memcache_functions[] = { - PHP_FE(memcache_connect, NULL) - PHP_FE(memcache_pconnect, NULL) - PHP_FE(memcache_add_server, NULL) - PHP_FE(memcache_set_server_params, NULL) - PHP_FE(memcache_get_server_status, NULL) - PHP_FE(memcache_get_version, NULL) - PHP_FE(memcache_add, NULL) - PHP_FE(memcache_set, NULL) - PHP_FE(memcache_replace, NULL) - PHP_FE(memcache_get, NULL) - PHP_FE(memcache_delete, NULL) - PHP_FE(memcache_debug, NULL) - PHP_FE(memcache_get_stats, NULL) - PHP_FE(memcache_get_extended_stats, NULL) - PHP_FE(memcache_set_compress_threshold, NULL) - PHP_FE(memcache_increment, NULL) - PHP_FE(memcache_decrement, NULL) - PHP_FE(memcache_close, NULL) - PHP_FE(memcache_flush, NULL) - PHP_FE(memcache_setoptimeout, NULL) - {NULL, NULL, NULL} -}; - -static zend_function_entry php_memcache_class_functions[] = { - PHP_FALIAS(connect, memcache_connect, NULL) - PHP_FALIAS(pconnect, memcache_pconnect, NULL) - PHP_FALIAS(addserver, memcache_add_server, NULL) - PHP_FALIAS(setserverparams, memcache_set_server_params, NULL) - PHP_FALIAS(getserverstatus, memcache_get_server_status, NULL) - PHP_FALIAS(getversion, memcache_get_version, NULL) - PHP_FALIAS(add, memcache_add, NULL) - PHP_FALIAS(set, memcache_set, NULL) - PHP_FALIAS(replace, memcache_replace, NULL) - PHP_FALIAS(get, memcache_get, NULL) - PHP_FALIAS(delete, memcache_delete, NULL) - PHP_FALIAS(getstats, memcache_get_stats, NULL) - PHP_FALIAS(getextendedstats, memcache_get_extended_stats, NULL) - PHP_FALIAS(setcompressthreshold, memcache_set_compress_threshold, NULL) - PHP_FALIAS(increment, memcache_increment, NULL) - PHP_FALIAS(decrement, memcache_decrement, NULL) - PHP_FALIAS(close, memcache_close, NULL) - PHP_FALIAS(flush, memcache_flush, NULL) - PHP_FALIAS(setoptimeout, memcache_setoptimeout, NULL) - {NULL, NULL, NULL} -}; - -/* }}} */ - -/* {{{ memcache_module_entry - */ -zend_module_entry memcache_module_entry = { -#if ZEND_MODULE_API_NO >= 20010901 - STANDARD_MODULE_HEADER, -#endif - "memcache", - memcache_functions, - PHP_MINIT(memcache), - PHP_MSHUTDOWN(memcache), - PHP_RINIT(memcache), - NULL, - PHP_MINFO(memcache), -#if ZEND_MODULE_API_NO >= 20010901 - PHP_MEMCACHE_VERSION, -#endif - STANDARD_MODULE_PROPERTIES -}; -/* }}} */ - -#ifdef COMPILE_DL_MEMCACHE -ZEND_GET_MODULE(memcache) -#endif - -static PHP_INI_MH(OnUpdateChunkSize) /* {{{ */ -{ - long int lval; - - lval = strtol(new_value, NULL, 10); - if (lval <= 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.chunk_size must be a positive integer ('%s' given)", new_value); - return FAILURE; - } - - return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); -} -/* }}} */ - -static PHP_INI_MH(OnUpdateFailoverAttempts) /* {{{ */ -{ - long int lval; - - lval = strtol(new_value, NULL, 10); - if (lval <= 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.max_failover_attempts must be a positive integer ('%s' given)", new_value); - return FAILURE; - } - - return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); -} -/* }}} */ - -static PHP_INI_MH(OnUpdateHashStrategy) /* {{{ */ -{ - if (!strcasecmp(new_value, "standard")) { - MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH; - } - else if (!strcasecmp(new_value, "consistent")) { - MEMCACHE_G(hash_strategy) = MMC_CONSISTENT_HASH; - } - else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.hash_strategy must be in set {standard, consistent} ('%s' given)", new_value); - return FAILURE; - } - - return SUCCESS; -} -/* }}} */ - -static PHP_INI_MH(OnUpdateHashFunction) /* {{{ */ -{ - if (!strcasecmp(new_value, "crc32")) { - MEMCACHE_G(hash_function) = MMC_HASH_CRC32; - } - else if (!strcasecmp(new_value, "fnv")) { - MEMCACHE_G(hash_function) = 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; -} -/* }}} */ - -static PHP_INI_MH(OnUpdateDefaultTimeout) /* {{{ */ -{ - long int lval; - - lval = strtol(new_value, NULL, 10); - if (lval <= 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.default_timeout must be a positive number greater than or equal to 1 ('%s' given)", new_value); - return FAILURE; - } - MEMCACHE_G(default_timeout_ms) = lval; - 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) - STD_PHP_INI_ENTRY("memcache.max_failover_attempts", "20", PHP_INI_ALL, OnUpdateFailoverAttempts, max_failover_attempts, zend_memcache_globals, memcache_globals) - 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) - STD_PHP_INI_ENTRY("memcache.default_timeout_ms", "1000", PHP_INI_ALL, OnUpdateDefaultTimeout, default_timeout_ms, zend_memcache_globals, memcache_globals) -PHP_INI_END() -/* }}} */ - -/* {{{ internal function protos */ -static void _mmc_pool_list_dtor(zend_rsrc_list_entry * TSRMLS_DC); -static void _mmc_pserver_list_dtor(zend_rsrc_list_entry * TSRMLS_DC); - -static void mmc_server_free(mmc_t * TSRMLS_DC); -static void mmc_server_disconnect(mmc_t * TSRMLS_DC); -static int mmc_server_store(mmc_t *, const char *, int TSRMLS_DC); - -static int mmc_compress(char **, unsigned long *, const char *, int TSRMLS_DC); -static int mmc_uncompress(char **, unsigned long *, const char *, int); -static int mmc_get_pool(zval *, mmc_pool_t ** TSRMLS_DC); -static int mmc_readline(mmc_t * TSRMLS_DC); -static char * mmc_get_version(mmc_t * TSRMLS_DC); -static int mmc_str_left(char *, char *, int, int); -static int mmc_sendcmd(mmc_t *, const char *, int TSRMLS_DC); -static int mmc_parse_response(mmc_t *mmc, char *, int, char **, int *, int *, int *); -static int mmc_exec_retrieval_cmd_multi(mmc_pool_t *, zval *, zval **, zval * TSRMLS_DC); -static int mmc_read_value(mmc_t *, char **, int *, char **, int *, int * TSRMLS_DC); -static int mmc_flush(mmc_t *, int TSRMLS_DC); -static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, char *, int); -static int mmc_get_stats(mmc_t *, char *, int, int, zval * TSRMLS_DC); -static int mmc_incr_decr(mmc_t *, int, char *, int, int, long * TSRMLS_DC); -static void php_mmc_incr_decr(INTERNAL_FUNCTION_PARAMETERS, int); -static void php_mmc_connect(INTERNAL_FUNCTION_PARAMETERS, int); -/* }}} */ - -/* {{{ hash strategies */ -extern mmc_hash_t mmc_standard_hash; -extern mmc_hash_t mmc_consistent_hash; -/* }}} */ - -/* {{{ php_memcache_init_globals() -*/ -static void php_memcache_init_globals(zend_memcache_globals *memcache_globals_p TSRMLS_DC) -{ - MEMCACHE_G(debug_mode) = 0; - MEMCACHE_G(num_persistent) = 0; - MEMCACHE_G(compression_level) = Z_DEFAULT_COMPRESSION; - MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH; - MEMCACHE_G(hash_function) = MMC_HASH_CRC32; - MEMCACHE_G(default_timeout_ms)= (MMC_DEFAULT_TIMEOUT) * 1000; -} -/* }}} */ - -/* {{{ PHP_MINIT_FUNCTION - */ -PHP_MINIT_FUNCTION(memcache) -{ - zend_class_entry memcache_class_entry; - INIT_CLASS_ENTRY(memcache_class_entry, "Memcache", php_memcache_class_functions); - memcache_class_entry_ptr = zend_register_internal_class(&memcache_class_entry TSRMLS_CC); - - le_memcache_pool = zend_register_list_destructors_ex(_mmc_pool_list_dtor, NULL, "memcache connection", module_number); - le_pmemcache = zend_register_list_destructors_ex(NULL, _mmc_pserver_list_dtor, "persistent memcache connection", module_number); - -#ifdef ZTS - ts_allocate_id(&memcache_globals_id, sizeof(zend_memcache_globals), (ts_allocate_ctor) php_memcache_init_globals, NULL); -#else - php_memcache_init_globals(&memcache_globals TSRMLS_CC); -#endif - - REGISTER_LONG_CONSTANT("MEMCACHE_COMPRESSED", MMC_COMPRESSED, CONST_CS | CONST_PERSISTENT); - REGISTER_INI_ENTRIES(); - -#if HAVE_MEMCACHE_SESSION - REGISTER_LONG_CONSTANT("MEMCACHE_HAVE_SESSION", 1, CONST_CS | CONST_PERSISTENT); - php_session_register_module(ps_memcache_ptr); -#else - REGISTER_LONG_CONSTANT("MEMCACHE_HAVE_SESSION", 0, CONST_CS | CONST_PERSISTENT); -#endif - - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_MSHUTDOWN_FUNCTION - */ -PHP_MSHUTDOWN_FUNCTION(memcache) -{ - UNREGISTER_INI_ENTRIES(); - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_RINIT_FUNCTION - */ -PHP_RINIT_FUNCTION(memcache) -{ - MEMCACHE_G(debug_mode) = 0; - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_MINFO_FUNCTION - */ -PHP_MINFO_FUNCTION(memcache) -{ - char buf[MAX_LENGTH_OF_LONG + 1]; - - sprintf(buf, "%ld", MEMCACHE_G(num_persistent)); - - php_info_print_table_start(); - php_info_print_table_header(2, "memcache support", "enabled"); - php_info_print_table_row(2, "Active persistent connections", buf); - php_info_print_table_row(2, "Version", PHP_MEMCACHE_VERSION); - php_info_print_table_row(2, "Revision", "$Revision: 1.111 $"); - php_info_print_table_end(); - - DISPLAY_INI_ENTRIES(); -} -/* }}} */ - -/* ------------------ - internal functions - ------------------ */ - -#if ZEND_DEBUG -void mmc_debug(const char *format, ...) /* {{{ */ -{ - TSRMLS_FETCH(); - - if (MEMCACHE_G(debug_mode)) { - char buffer[1024]; - va_list args; - - va_start(args, format); - vsnprintf(buffer, sizeof(buffer)-1, format, args); - va_end(args); - buffer[sizeof(buffer)-1] = '\0'; - php_printf("%s<br />\n", buffer); - } -} -/* }}} */ -#endif - -static struct timeval _convert_timeoutms_to_ts(long msecs) /* {{{ */ -{ - struct timeval tv; - int secs = 0; - - secs = msecs / 1000; - tv.tv_sec = secs; - tv.tv_usec = ((msecs - (secs * 1000)) * 1000) % 1000000; - return tv; -} -/* }}} */ - -static void _mmc_pool_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ -{ - mmc_pool_free((mmc_pool_t *)rsrc->ptr TSRMLS_CC); -} -/* }}} */ - -static void _mmc_pserver_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ -{ - mmc_server_free((mmc_t *)rsrc->ptr TSRMLS_CC); -} -/* }}} */ - -mmc_t *mmc_server_new(char *host, int host_len, unsigned short port, int persistent, int timeout, int retry_interval TSRMLS_DC) /* {{{ */ -{ - mmc_t *mmc = pemalloc(sizeof(mmc_t), persistent); - memset(mmc, 0, sizeof(*mmc)); - - mmc->host = pemalloc(host_len + 1, persistent); - memcpy(mmc->host, host, host_len); - mmc->host[host_len] = '\0'; - - mmc->port = port; - mmc->status = MMC_STATUS_DISCONNECTED; - - mmc->persistent = persistent; - if (persistent) { - MEMCACHE_G(num_persistent)++; - } - - mmc->timeout = timeout; - mmc->retry_interval = retry_interval; - - return mmc; -} -/* }}} */ - -static void mmc_server_callback_dtor(zval **callback TSRMLS_DC) /* {{{ */ -{ - zval **this_obj; - - if (!callback || !*callback) return; - - if (Z_TYPE_PP(callback) == IS_ARRAY && - zend_hash_index_find(Z_ARRVAL_PP(callback), 0, (void **)&this_obj) == SUCCESS && - Z_TYPE_PP(this_obj) == IS_OBJECT) { - zval_ptr_dtor(this_obj); - } - zval_ptr_dtor(callback); -} -/* }}} */ - -static void mmc_server_callback_ctor(zval **callback TSRMLS_DC) /* {{{ */ -{ - zval **this_obj; - - if (!callback || !*callback) return; - - if (Z_TYPE_PP(callback) == IS_ARRAY && - zend_hash_index_find(Z_ARRVAL_PP(callback), 0, (void **)&this_obj) == SUCCESS && - Z_TYPE_PP(this_obj) == IS_OBJECT) { - zval_add_ref(this_obj); - } - zval_add_ref(callback); -} -/* }}} */ - -static void mmc_server_sleep(mmc_t *mmc TSRMLS_DC) /* - prepare server struct for persistent sleep {{{ */ -{ - mmc_server_callback_dtor(&mmc->failure_callback TSRMLS_CC); - mmc->failure_callback = NULL; - - if (mmc->error != NULL) { - pefree(mmc->error, mmc->persistent); - mmc->error = NULL; - } -} -/* }}} */ - -static void mmc_server_free(mmc_t *mmc TSRMLS_DC) /* {{{ */ -{ - if (mmc->in_free) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "Recursive reference detected, bailing out"); - return; - } - mmc->in_free = 1; - - mmc_server_sleep(mmc TSRMLS_CC); - - if (mmc->persistent) { - free(mmc->host); - free(mmc); - MEMCACHE_G(num_persistent)--; - } - else { - if (mmc->stream != NULL) { - php_stream_close(mmc->stream); - } - efree(mmc->host); - efree(mmc); - } -} -/* }}} */ - -static void mmc_server_seterror(mmc_t *mmc, const char *error, int errnum) /* {{{ */ -{ - if (error != NULL) { - if (mmc->error != NULL) { - pefree(mmc->error, mmc->persistent); - } - - mmc->error = pestrdup(error, mmc->persistent); - mmc->errnum = errnum; - } -} -/* }}} */ - -static void mmc_server_received_error(mmc_t *mmc, int response_len) /* {{{ */ -{ - if (mmc_str_left(mmc->inbuf, "ERROR", response_len, sizeof("ERROR") - 1) || - mmc_str_left(mmc->inbuf, "CLIENT_ERROR", response_len, sizeof("CLIENT_ERROR") - 1) || - mmc_str_left(mmc->inbuf, "SERVER_ERROR", response_len, sizeof("SERVER_ERROR") - 1)) - { - mmc->inbuf[response_len < MMC_BUF_SIZE - 1 ? response_len : MMC_BUF_SIZE - 1] = '\0'; - mmc_server_seterror(mmc, mmc->inbuf, 0); - } - else { - mmc_server_seterror(mmc, "Received malformed response", 0); - } -} -/* }}} */ - -int mmc_server_failure(mmc_t *mmc TSRMLS_DC) /*determines if a request should be retried or is a hard network failure {{{ */ -{ - switch (mmc->status) { - case MMC_STATUS_DISCONNECTED: - return 0; - - /* attempt reconnect of sockets in unknown state */ - case MMC_STATUS_UNKNOWN: - mmc->status = MMC_STATUS_DISCONNECTED; - return 0; - } - - mmc_server_deactivate(mmc TSRMLS_CC); - return 1; -} -/* }}} */ - -static int mmc_server_store(mmc_t *mmc, const char *request, int request_len TSRMLS_DC) /* {{{ */ -{ - int response_len; - php_netstream_data_t *sock = (php_netstream_data_t*)mmc->stream->abstract; - - if (mmc->timeoutms > 1) { - sock->timeout = _convert_timeoutms_to_ts(mmc->timeoutms); - } - - if (php_stream_write(mmc->stream, request, request_len) != request_len) { - mmc_server_seterror(mmc, "Failed sending command and value to stream", 0); - return -1; - } - - if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { - return -1; - } - - if(mmc_str_left(mmc->inbuf, "STORED", response_len, sizeof("STORED") - 1)) { - return 1; - } - - /* return FALSE */ - if(mmc_str_left(mmc->inbuf, "NOT_STORED", response_len, sizeof("NOT_STORED") - 1)) { - return 0; - } - - /* return FALSE without failover */ - if (mmc_str_left(mmc->inbuf, "SERVER_ERROR out of memory", response_len, sizeof("SERVER_ERROR out of memory") - 1) || - mmc_str_left(mmc->inbuf, "SERVER_ERROR object too large", response_len, sizeof("SERVER_ERROR object too large")-1)) { - return 0; - } - - mmc_server_received_error(mmc, response_len); - return -1; -} -/* }}} */ - -int mmc_prepare_key_ex(const char *key, unsigned int key_len, char *result, unsigned int *result_len TSRMLS_DC) /* {{{ */ -{ - unsigned int i; - if (key_len == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key cannot be empty"); - return MMC_REQUEST_FAILURE; - } - - *result_len = key_len < MMC_KEY_MAX_SIZE ? key_len : MMC_KEY_MAX_SIZE; - result[*result_len] = '\0'; - - for (i=0; i<*result_len; i++) { - result[i] = ((unsigned char)key[i]) > ' ' ? key[i] : '_'; - } - - return MMC_OK; -} -/* }}} */ - -int mmc_prepare_key(zval *key, char *result, unsigned int *result_len TSRMLS_DC) /* {{{ */ -{ - if (Z_TYPE_P(key) == IS_STRING) { - return mmc_prepare_key_ex(Z_STRVAL_P(key), Z_STRLEN_P(key), result, result_len TSRMLS_CC); - } else { - int res; - zval *keytmp; - ALLOC_ZVAL(keytmp); - - *keytmp = *key; - zval_copy_ctor(keytmp); - convert_to_string(keytmp); - - res = mmc_prepare_key_ex(Z_STRVAL_P(keytmp), Z_STRLEN_P(keytmp), result, result_len TSRMLS_CC); - - zval_dtor(keytmp); - FREE_ZVAL(keytmp); - - return res; - } -} -/* }}} */ - -static unsigned int mmc_hash_crc32(const char *key, int key_len) /* CRC32 hash {{{ */ -{ - unsigned int crc = ~0; - int i; - - for (i=0; i<key_len; i++) { - CRC32(crc, key[i]); - } - - return ~crc; -} -/* }}} */ - -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 void mmc_pool_init_hash(mmc_pool_t *pool TSRMLS_DC) /* {{{ */ -{ - mmc_hash_function hash; - - switch (MEMCACHE_G(hash_strategy)) { - case MMC_CONSISTENT_HASH: - pool->hash = &mmc_consistent_hash; - break; - 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(hash); -} -/* }}} */ - -mmc_pool_t *mmc_pool_new(TSRMLS_D) /* {{{ */ -{ - mmc_pool_t *pool = emalloc(sizeof(mmc_pool_t)); - pool->num_servers = 0; - pool->compress_threshold = 0; - pool->in_free = 0; - pool->min_compress_savings = MMC_DEFAULT_SAVINGS; - - mmc_pool_init_hash(pool TSRMLS_CC); - - return pool; -} -/* }}} */ - -void mmc_pool_free(mmc_pool_t *pool TSRMLS_DC) /* {{{ */ -{ - int i; - - if (pool->in_free) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "Recursive reference detected, bailing out"); - return; - } - pool->in_free = 1; - - for (i=0; i<pool->num_servers; i++) { - if (!pool->servers[i]) { - continue; - } - if (pool->servers[i]->persistent == 0 && pool->servers[i]->host != NULL) { - mmc_server_free(pool->servers[i] TSRMLS_CC); - } else { - mmc_server_sleep(pool->servers[i] TSRMLS_CC); - } - pool->servers[i] = NULL; - } - - if (pool->num_servers) { - efree(pool->servers); - efree(pool->requests); - } - - pool->hash->free_state(pool->hash_state); - efree(pool); -} -/* }}} */ - -void mmc_pool_add(mmc_pool_t *pool, mmc_t *mmc, unsigned int weight) /* {{{ */ -{ - /* add server and a preallocated request pointer */ - if (pool->num_servers) { - pool->servers = erealloc(pool->servers, sizeof(mmc_t *) * (pool->num_servers + 1)); - pool->requests = erealloc(pool->requests, sizeof(mmc_t *) * (pool->num_servers + 1)); - } - else { - pool->servers = emalloc(sizeof(mmc_t *)); - pool->requests = emalloc(sizeof(mmc_t *)); - } - - pool->servers[pool->num_servers] = mmc; - pool->num_servers++; - - pool->hash->add_server(pool->hash_state, mmc, weight); -} -/* }}} */ - -static int mmc_pool_close(mmc_pool_t *pool TSRMLS_DC) /* disconnects and removes all servers in the pool {{{ */ -{ - if (pool->num_servers) { - int i; - - for (i=0; i<pool->num_servers; i++) { - if (pool->servers[i]->persistent == 0 && pool->servers[i]->host != NULL) { - mmc_server_free(pool->servers[i] TSRMLS_CC); - } else { - mmc_server_sleep(pool->servers[i] TSRMLS_CC); - } - } - - efree(pool->servers); - pool->servers = NULL; - pool->num_servers = 0; - - efree(pool->requests); - pool->requests = NULL; - - /* reallocate the hash strategy state */ - pool->hash->free_state(pool->hash_state); - mmc_pool_init_hash(pool TSRMLS_CC); - } - - return 1; -} -/* }}} */ - -int mmc_pool_store(mmc_pool_t *pool, const char *command, int command_len, const char *key, int key_len, int flags, int expire, const char *value, int value_len TSRMLS_DC) /* {{{ */ -{ - mmc_t *mmc; - char *request; - int request_len, result = -1; - char *key_copy = NULL, *data = NULL; - - if (key_len > MMC_KEY_MAX_SIZE) { - key = key_copy = estrndup(key, MMC_KEY_MAX_SIZE); - key_len = MMC_KEY_MAX_SIZE; - } - - /* autocompress large values */ - if (pool->compress_threshold && value_len >= pool->compress_threshold) { - flags |= MMC_COMPRESSED; - } - - if (flags & MMC_COMPRESSED) { - unsigned long data_len; - - if (!mmc_compress(&data, &data_len, value, value_len TSRMLS_CC)) { - /* mmc_server_seterror(mmc, "Failed to compress data", 0); */ - return -1; - } - - /* was enough space saved to motivate uncompress processing on get */ - if (data_len < value_len * (1 - pool->min_compress_savings)) { - value = data; - value_len = data_len; - } - else { - flags &= ~MMC_COMPRESSED; - efree(data); - data = NULL; - } - } - - request = emalloc( - command_len - + 1 /* space */ - + key_len - + 1 /* space */ - + MAX_LENGTH_OF_LONG - + 1 /* space */ - + MAX_LENGTH_OF_LONG - + 1 /* space */ - + MAX_LENGTH_OF_LONG - + sizeof("\r\n") - 1 - + value_len - + sizeof("\r\n") - 1 - + 1 - ); - - request_len = sprintf(request, "%s %s %d %d %d\r\n", command, key, flags, expire, value_len); - - memcpy(request + request_len, value, value_len); - request_len += value_len; - - memcpy(request + request_len, "\r\n", sizeof("\r\n") - 1); - request_len += sizeof("\r\n") - 1; - - request[request_len] = '\0'; - - while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { - if ((result = mmc_server_store(mmc, request, request_len TSRMLS_CC)) < 0) { - mmc_server_failure(mmc TSRMLS_CC); - } - } - - if (key_copy != NULL) { - efree(key_copy); - } - - if (data != NULL) { - efree(data); - } - - efree(request); - - return result; -} -/* }}} */ - -static int mmc_compress(char **result, unsigned long *result_len, const char *data, int data_len TSRMLS_DC) /* {{{ */ -{ - int status, level = MEMCACHE_G(compression_level); - - *result_len = data_len + (data_len / 1000) + 25 + 1; /* some magic from zlib.c */ - *result = (char *) emalloc(*result_len); - - if (!*result) { - return 0; - } - - if (level >= 0) { - status = compress2((unsigned char *) *result, result_len, (unsigned const char *) data, data_len, level); - } else { - status = compress((unsigned char *) *result, result_len, (unsigned const char *) data, data_len); - } - - if (status == Z_OK) { - *result = erealloc(*result, *result_len + 1); - (*result)[*result_len] = '\0'; - return 1; - } - - switch (status) { - case Z_MEM_ERROR: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough memory to perform compression"); - break; - case Z_BUF_ERROR: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough room in the output buffer to perform compression"); - break; - case Z_STREAM_ERROR: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level"); - break; - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error during compression"); - break; - } - - efree(*result); - return 0; -} -/* }}}*/ - -static int mmc_uncompress(char **result, unsigned long *result_len, const char *data, int data_len) /* {{{ */ -{ - int status; - unsigned int factor = 1, maxfactor = 16; - char *tmp1 = NULL; - - do { - *result_len = (unsigned long)data_len * (1 << factor++); - *result = (char *) erealloc(tmp1, *result_len); - status = uncompress((unsigned char *) *result, result_len, (unsigned const char *) data, data_len); - tmp1 = *result; - } while (status == Z_BUF_ERROR && factor < maxfactor); - - if (status == Z_OK) { - *result = erealloc(*result, *result_len + 1); - (*result)[*result_len] = '\0'; - return 1; - } - - efree(*result); - return 0; -} -/* }}}*/ - -static int mmc_get_pool(zval *id, mmc_pool_t **pool TSRMLS_DC) /* {{{ */ -{ - zval **connection; - int resource_type; - - if (Z_TYPE_P(id) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(id), "connection", sizeof("connection"), (void **) &connection) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "No servers added to memcache connection"); - return 0; - } - - *pool = (mmc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type); - - if (!*pool || resource_type != le_memcache_pool) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Memcache->connection member variable"); - return 0; - } - - return Z_LVAL_PP(connection); -} -/* }}} */ - -static int _mmc_open(mmc_t *mmc, char **error_string, int *errnum TSRMLS_DC) /* {{{ */ -{ - struct timeval tv; - char *hostname = NULL, *hash_key = NULL, *errstr = NULL; - int hostname_len, err = 0; - - /* close open stream */ - if (mmc->stream != NULL) { - mmc_server_disconnect(mmc TSRMLS_CC); - } - - if (mmc->connect_timeoutms > 0) { - tv = _convert_timeoutms_to_ts(mmc->connect_timeoutms); - } else { - tv.tv_sec = mmc->timeout; - } - - if (mmc->port) { - hostname_len = spprintf(&hostname, 0, "%s:%d", mmc->host, mmc->port); - } - else { - hostname_len = spprintf(&hostname, 0, "%s", mmc->host); - } - - if (mmc->persistent) { - spprintf(&hash_key, 0, "memcache:%s", hostname); - } - -#if PHP_API_VERSION > 20020918 - mmc->stream = php_stream_xport_create( hostname, hostname_len, - ENFORCE_SAFE_MODE | REPORT_ERRORS, - STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, - hash_key, &tv, NULL, &errstr, &err); -#else - if (mmc->persistent) { - switch(php_stream_from_persistent_id(hash_key, &(mmc->stream) TSRMLS_CC)) { - case PHP_STREAM_PERSISTENT_SUCCESS: - if (php_stream_eof(mmc->stream)) { - php_stream_pclose(mmc->stream); - mmc->stream = NULL; - break; - } - case PHP_STREAM_PERSISTENT_FAILURE: - break; - } - } - - if (!mmc->stream) { - int socktype = SOCK_STREAM; - mmc->stream = php_stream_sock_open_host(mmc->host, mmc->port, socktype, &tv, hash_key); - } - -#endif - - efree(hostname); - if (mmc->persistent) { - efree(hash_key); - } - - if (!mmc->stream) { - MMC_DEBUG(("_mmc_open: can't open socket to host")); - mmc_server_seterror(mmc, errstr != NULL ? errstr : "Connection failed", err); - mmc_server_deactivate(mmc TSRMLS_CC); - - if (errstr) { - if (error_string) { - *error_string = errstr; - } - else { - efree(errstr); - } - } - if (errnum) { - *errnum = err; - } - - return 0; - } - - php_stream_auto_cleanup(mmc->stream); - php_stream_set_option(mmc->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv); - php_stream_set_option(mmc->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL); - php_stream_set_chunk_size(mmc->stream, MEMCACHE_G(chunk_size)); - - mmc->status = MMC_STATUS_CONNECTED; - - if (mmc->error != NULL) { - pefree(mmc->error, mmc->persistent); - mmc->error = NULL; - } - - return 1; -} -/* }}} */ - -int mmc_open(mmc_t *mmc, int force_connect, char **error_string, int *errnum TSRMLS_DC) /* {{{ */ -{ - switch (mmc->status) { - case MMC_STATUS_DISCONNECTED: - return _mmc_open(mmc, error_string, errnum TSRMLS_CC); - - case MMC_STATUS_CONNECTED: - return 1; - - case MMC_STATUS_UNKNOWN: - /* check connection if needed */ - if (force_connect) { - char *version; - if ((version = mmc_get_version(mmc TSRMLS_CC)) == NULL && !_mmc_open(mmc, error_string, errnum TSRMLS_CC)) { - break; - } - if (version) { - efree(version); - } - mmc->status = MMC_STATUS_CONNECTED; - } - return 1; - - case MMC_STATUS_FAILED: - if (mmc->retry_interval >= 0 && (long)time(NULL) >= mmc->failed + mmc->retry_interval) { - if (_mmc_open(mmc, error_string, errnum TSRMLS_CC) /*&& mmc_flush(mmc, 0 TSRMLS_CC) > 0*/) { - return 1; - } - } - break; - } - return 0; -} -/* }}} */ - -static void mmc_server_disconnect(mmc_t *mmc TSRMLS_DC) /* {{{ */ -{ - if (mmc->stream != NULL) { - if (mmc->persistent) { - php_stream_pclose(mmc->stream); - } - else { - php_stream_close(mmc->stream); - } - mmc->stream = NULL; - } - mmc->status = MMC_STATUS_DISCONNECTED; -} -/* }}} */ - -void mmc_server_deactivate(mmc_t *mmc TSRMLS_DC) /* disconnect and marks the server as down {{{ */ -{ - mmc_server_disconnect(mmc TSRMLS_CC); - mmc->status = MMC_STATUS_FAILED; - mmc->failed = (long)time(NULL); - - if (mmc->failure_callback != NULL) { - zval *retval = NULL; - zval *host, *tcp_port, *udp_port, *error, *errnum; - zval **params[5]; - - params[0] = &host; - params[1] = &tcp_port; - params[2] = &udp_port; - params[3] = &error; - params[4] = &errnum; - - MAKE_STD_ZVAL(host); - MAKE_STD_ZVAL(tcp_port); MAKE_STD_ZVAL(udp_port); - MAKE_STD_ZVAL(error); MAKE_STD_ZVAL(errnum); - - ZVAL_STRING(host, mmc->host, 1); - ZVAL_LONG(tcp_port, mmc->port); ZVAL_LONG(udp_port, 0); - - if (mmc->error != NULL) { - ZVAL_STRING(error, mmc->error, 1); - } - else { - ZVAL_NULL(error); - } - ZVAL_LONG(errnum, mmc->errnum); - - call_user_function_ex(EG(function_table), NULL, mmc->failure_callback, &retval, 5, params, 0, NULL TSRMLS_CC); - - zval_ptr_dtor(&host); - zval_ptr_dtor(&tcp_port); zval_ptr_dtor(&udp_port); - zval_ptr_dtor(&error); zval_ptr_dtor(&errnum); - - if (retval != NULL) { - zval_ptr_dtor(&retval); - } - } - else { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d) failed with: %s (%d)", - mmc->host, mmc->port, mmc->error, mmc->errnum); - } -} -/* }}} */ - -static int mmc_readline(mmc_t *mmc TSRMLS_DC) /* {{{ */ -{ - char *response; - size_t response_len; - - if (mmc->stream == NULL) { - mmc_server_seterror(mmc, "Socket is closed", 0); - return -1; - } - - response = php_stream_get_line(mmc->stream, ZSTR(mmc->inbuf), MMC_BUF_SIZE, &response_len); - if (response) { - MMC_DEBUG(("mmc_readline: read data:")); - MMC_DEBUG(("mmc_readline:---")); - MMC_DEBUG(("%s", response)); - MMC_DEBUG(("mmc_readline:---")); - return response_len; - } - - mmc_server_seterror(mmc, "Failed reading line from stream", 0); - return -1; -} -/* }}} */ - -static char *mmc_get_version(mmc_t *mmc TSRMLS_DC) /* {{{ */ -{ - char *version_str; - int response_len; - - if (mmc_sendcmd(mmc, "version", sizeof("version") - 1 TSRMLS_CC) < 0) { - return NULL; - } - - if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { - return NULL; - } - - if (mmc_str_left(mmc->inbuf, "VERSION ", response_len, sizeof("VERSION ") - 1)) { - version_str = estrndup(mmc->inbuf + sizeof("VERSION ") - 1, response_len - (sizeof("VERSION ") - 1) - (sizeof("\r\n") - 1) ); - return version_str; - } - - mmc_server_seterror(mmc, "Malformed version string", 0); - return NULL; -} -/* }}} */ - -static int mmc_str_left(char *haystack, char *needle, int haystack_len, int needle_len) /* {{{ */ -{ - char *found; - - found = php_memnstr(haystack, needle, needle_len, haystack + haystack_len); - if ((found - haystack) == 0) { - return 1; - } - return 0; -} -/* }}} */ - -static int mmc_sendcmd(mmc_t *mmc, const char *cmd, int cmdlen TSRMLS_DC) /* {{{ */ -{ - char *command; - int command_len; - php_netstream_data_t *sock = (php_netstream_data_t*)mmc->stream->abstract; - - if (!mmc || !cmd) { - return -1; - } - - MMC_DEBUG(("mmc_sendcmd: sending command '%s'", cmd)); - - command = emalloc(cmdlen + sizeof("\r\n")); - memcpy(command, cmd, cmdlen); - memcpy(command + cmdlen, "\r\n", sizeof("\r\n") - 1); - command_len = cmdlen + sizeof("\r\n") - 1; - command[command_len] = '\0'; - - if (mmc->timeoutms > 1) { - sock->timeout = _convert_timeoutms_to_ts(mmc->timeoutms); - } - - if (php_stream_write(mmc->stream, command, command_len) != command_len) { - mmc_server_seterror(mmc, "Failed writing command to stream", 0); - efree(command); - return -1; - } - efree(command); - - return 1; -} -/* }}}*/ - -static int mmc_parse_response(mmc_t *mmc, char *response, int response_len, char **key, int *key_len, int *flags, int *value_len) /* {{{ */ -{ - int i=0, n=0; - int spaces[3]; - - if (!response || response_len <= 0) { - mmc_server_seterror(mmc, "Empty response", 0); - return -1; - } - - MMC_DEBUG(("mmc_parse_response: got response '%s'", response)); - - for (i=0, n=0; i < response_len && n < 3; i++) { - if (response[i] == ' ') { - spaces[n++] = i; - } - } - - MMC_DEBUG(("mmc_parse_response: found %d spaces", n)); - - if (n < 3) { - mmc_server_seterror(mmc, "Malformed VALUE header", 0); - return -1; - } - - if (key != NULL) { - int len = spaces[1] - spaces[0] - 1; - - *key = emalloc(len + 1); - *key_len = len; - - memcpy(*key, response + spaces[0] + 1, len); - (*key)[len] = '\0'; - } - - *flags = atoi(response + spaces[1]); - *value_len = atoi(response + spaces[2]); - - if (*flags < 0 || *value_len < 0) { - mmc_server_seterror(mmc, "Malformed VALUE header", 0); - return -1; - } - - MMC_DEBUG(("mmc_parse_response: 1st space is at %d position", spaces[1])); - MMC_DEBUG(("mmc_parse_response: 2nd space is at %d position", spaces[2])); - MMC_DEBUG(("mmc_parse_response: flags = %d", *flags)); - MMC_DEBUG(("mmc_parse_response: value_len = %d ", *value_len)); - - return 1; -} -/* }}} */ - -static int mmc_postprocess_value(zval **return_value, char *value, int value_len TSRMLS_DC) /* - post-process a value into a result zval struct, value will be free()'ed during process {{{ */ -{ - const char *value_tmp = value; - php_unserialize_data_t var_hash; - PHP_VAR_UNSERIALIZE_INIT(var_hash); - - if (!php_var_unserialize(return_value, (const unsigned char **)&value_tmp, (const unsigned char *)(value_tmp + value_len), &var_hash TSRMLS_CC)) { - ZVAL_FALSE(*return_value); - PHP_VAR_UNSERIALIZE_DESTROY(var_hash); - efree(value); - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "unable to unserialize data"); - return 0; - } - - PHP_VAR_UNSERIALIZE_DESTROY(var_hash); - efree(value); - return 1; -} -/* }}} */ - -int mmc_exec_retrieval_cmd(mmc_pool_t *pool, const char *key, int key_len, zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */ -{ - mmc_t *mmc; - char *command, *value; - int result = -1, command_len, response_len, value_len, flags = 0; - - MMC_DEBUG(("mmc_exec_retrieval_cmd: key '%s'", key)); - - command_len = spprintf(&command, 0, "get %s", key); - - while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { - MMC_DEBUG(("mmc_exec_retrieval_cmd: found server '%s:%d' for key '%s'", mmc->host, mmc->port, key)); - - /* send command and read value */ - if ((result = mmc_sendcmd(mmc, command, command_len TSRMLS_CC)) > 0 && - (result = mmc_read_value(mmc, NULL, NULL, &value, &value_len, &flags TSRMLS_CC)) >= 0) { - - /* not found */ - if (result == 0) { - ZVAL_FALSE(*return_value); - } - /* read "END" */ - else if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0 || !mmc_str_left(mmc->inbuf, "END", response_len, sizeof("END")-1)) { - mmc_server_seterror(mmc, "Malformed END line", 0); - result = -1; - } - else if (flags & MMC_SERIALIZED ) { - result = mmc_postprocess_value(return_value, value, value_len TSRMLS_CC); - } - else { - ZVAL_STRINGL(*return_value, value, value_len, 0); - } - } - - if (result < 0) { - mmc_server_failure(mmc TSRMLS_CC); - } - } - - if (return_flags != NULL) { - zval_dtor(return_flags); - ZVAL_LONG(return_flags, flags); - } - - efree(command); - return result; -} -/* }}} */ - -static int mmc_exec_retrieval_cmd_multi(mmc_pool_t *pool, zval *keys, zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */ -{ - mmc_t *mmc; - HashPosition pos; - zval **zkey; - char *result_key, *value; - char key[MMC_KEY_MAX_SIZE]; - unsigned int key_len; - - int i = 0, j, num_requests, result, result_status, result_key_len, value_len, flags; - mmc_queue_t serialized = {0}; /* mmc_queue_t<zval *>, pointers to zvals which need unserializing */ - - array_init(*return_value); - - if (return_flags != NULL) { - zval_dtor(return_flags); - array_init(return_flags); - } - - /* until no retrival errors or all servers have failed */ - do { - result_status = num_requests = 0; - zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos); - - /* first pass to build requests for each server */ - while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&zkey, &pos) == SUCCESS) { - if (mmc_prepare_key(*zkey, key, &key_len TSRMLS_CC) == MMC_OK) { - /* schedule key if first round or if missing from result */ - if ((!i || !zend_hash_exists(Z_ARRVAL_PP(return_value), key, key_len)) && - (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { - if (!(mmc->outbuf.len)) { - smart_str_appendl(&(mmc->outbuf), "get", sizeof("get")-1); - pool->requests[num_requests++] = mmc; - } - - smart_str_appendl(&(mmc->outbuf), " ", 1); - smart_str_appendl(&(mmc->outbuf), key, key_len); - MMC_DEBUG(("mmc_exec_retrieval_cmd_multi: scheduled key '%s' for '%s:%d' request length '%d'", key, mmc->host, mmc->port, mmc->outbuf.len)); - } - } - - zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos); - } - - /* second pass to send requests in parallel */ - for (j=0; j<num_requests; j++) { - smart_str_0(&(pool->requests[j]->outbuf)); - - if ((result = mmc_sendcmd(pool->requests[j], pool->requests[j]->outbuf.c, pool->requests[j]->outbuf.len TSRMLS_CC)) < 0) { - mmc_server_failure(pool->requests[j] TSRMLS_CC); - result_status = result; - } - } - - /* third pass to read responses */ - for (j=0; j<num_requests; j++) { - if (pool->requests[j]->status != MMC_STATUS_FAILED) { - for (value = NULL; (result = mmc_read_value(pool->requests[j], &result_key, &result_key_len, &value, &value_len, &flags TSRMLS_CC)) > 0; value = NULL) { - if (flags & MMC_SERIALIZED) { - zval *result; - MAKE_STD_ZVAL(result); - ZVAL_STRINGL(result, value, value_len, 0); - - /* don't store duplicate values */ - if (zend_hash_add(Z_ARRVAL_PP(return_value), result_key, result_key_len + 1, &result, sizeof(result), NULL) == SUCCESS) { - mmc_queue_push(&serialized, result); - } - else { - zval_ptr_dtor(&result); - } - } - else { - add_assoc_stringl_ex(*return_value, result_key, result_key_len + 1, value, value_len, 0); - } - - if (return_flags != NULL) { - add_assoc_long_ex(return_flags, result_key, result_key_len + 1, flags); - } - - efree(result_key); - } - - /* check for server failure */ - if (result < 0) { - mmc_server_failure(pool->requests[j] TSRMLS_CC); - result_status = result; - } - } - - smart_str_free(&(pool->requests[j]->outbuf)); - } - } while (result_status < 0 && MEMCACHE_G(allow_failover) && i++ < MEMCACHE_G(max_failover_attempts)); - - /* post-process serialized values */ - if (serialized.len) { - zval *value; - - while ((value = (zval *)mmc_queue_pop(&serialized)) != NULL) { - mmc_postprocess_value(&value, Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC); - } - - mmc_queue_free(&serialized); - } - - return result_status; -} -/* }}} */ - -static int mmc_read_value(mmc_t *mmc, char **key, int *key_len, char **value, int *value_len, int *flags TSRMLS_DC) /* {{{ */ -{ - char *data; - int response_len, data_len, i, size; - - /* read "VALUE <key> <flags> <bytes>\r\n" header line */ - if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { - MMC_DEBUG(("failed to read the server's response")); - return -1; - } - - /* reached the end of the data */ - if (mmc_str_left(mmc->inbuf, "END", response_len, sizeof("END") - 1)) { - return 0; - } - - if (mmc_parse_response(mmc, mmc->inbuf, response_len, key, key_len, flags, &data_len) < 0) { - return -1; - } - - MMC_DEBUG(("mmc_read_value: data len is %d bytes", data_len)); - - /* data_len + \r\n + \0 */ - data = emalloc(data_len + 3); - - for (i=0; i<data_len+2; i+=size) { - if ((size = php_stream_read(mmc->stream, data + i, data_len + 2 - i)) == 0) { - mmc_server_seterror(mmc, "Failed reading value response body", 0); - if (key) { - efree(*key); - } - efree(data); - return -1; - } - } - - data[data_len] = '\0'; - - if ((*flags & MMC_COMPRESSED) && data_len > 0) { - char *result_data; - unsigned long result_len = 0; - - if (!mmc_uncompress(&result_data, &result_len, data, data_len)) { - mmc_server_seterror(mmc, "Failed to uncompress data", 0); - if (key) { - efree(*key); - } - efree(data); - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "unable to uncompress data"); - return 0; - } - - efree(data); - data = result_data; - data_len = result_len; - } - - *value = data; - *value_len = data_len; - return 1; -} -/* }}} */ - -int mmc_delete(mmc_t *mmc, const char *key, int key_len, int time TSRMLS_DC) /* {{{ */ -{ - char *command; - int command_len, response_len; - - command_len = spprintf(&command, 0, "delete %s %d", key, time); - - MMC_DEBUG(("mmc_delete: trying to delete '%s'", key)); - - if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { - efree(command); - return -1; - } - efree(command); - - if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0){ - MMC_DEBUG(("failed to read the server's response")); - return -1; - } - - MMC_DEBUG(("mmc_delete: server's response is '%s'", mmc->inbuf)); - - if(mmc_str_left(mmc->inbuf,"DELETED", response_len, sizeof("DELETED") - 1)) { - return 1; - } - - if(mmc_str_left(mmc->inbuf,"NOT_FOUND", response_len, sizeof("NOT_FOUND") - 1)) { - return 0; - } - - mmc_server_received_error(mmc, response_len); - return -1; -} -/* }}} */ - -static int mmc_flush(mmc_t *mmc, int timestamp TSRMLS_DC) /* {{{ */ -{ - char *command; - int command_len, response_len; - - MMC_DEBUG(("mmc_flush: flushing the cache")); - - if (timestamp) { - command_len = spprintf(&command, 0, "flush_all %d", timestamp); - } - else { - command_len = spprintf(&command, 0, "flush_all"); - } - - if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { - efree(command); - return -1; - } - efree(command); - - /* get server's response */ - if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0){ - return -1; - } - - MMC_DEBUG(("mmc_flush: server's response is '%s'", mmc->inbuf)); - - if(mmc_str_left(mmc->inbuf, "OK", response_len, sizeof("OK") - 1)) { - return 1; - } - - mmc_server_received_error(mmc, response_len); - return -1; -} -/* }}} */ - -/* - * STAT 6:chunk_size 64 - */ -static int mmc_stats_parse_stat(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */ -{ - char *space, *colon, *key; - long index = 0; - - /* find space delimiting key and value */ - if ((space = php_memnstr(start, " ", 1, end)) == NULL) { - return 0; - } - - /* find colon delimiting subkeys */ - if ((colon = php_memnstr(start, ":", 1, space - 1)) != NULL) { - zval *element, **elem; - key = estrndup(start, colon - start); - - /* find existing or create subkey array in result */ - if ((is_numeric_string(key, colon - start, &index, NULL, 0) && - zend_hash_index_find(Z_ARRVAL_P(result), index, (void **) &elem) != FAILURE) || - zend_hash_find(Z_ARRVAL_P(result), key, colon - start + 1, (void **) &elem) != FAILURE) { - element = *elem; - } - else { - MAKE_STD_ZVAL(element); - array_init(element); - add_assoc_zval_ex(result, key, colon - start + 1, element); - } - - efree(key); - return mmc_stats_parse_stat(colon + 1, end, element TSRMLS_CC); - } - - /* no more subkeys, add value under last subkey */ - key = estrndup(start, space - start); - add_assoc_stringl_ex(result, key, space - start + 1, space + 1, end - space, 1); - efree(key); - - return 1; -} -/* }}} */ - -/* - * ITEM test_key [3 b; 1157099416 s] - */ -static int mmc_stats_parse_item(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */ -{ - char *space, *value, *value_end, *key; - zval *element; - - /* find space delimiting key and value */ - if ((space = php_memnstr(start, " ", 1, end)) == NULL) { - return 0; - } - - MAKE_STD_ZVAL(element); - array_init(element); - - /* parse each contained value */ - for (value = php_memnstr(space, "[", 1, end); value != NULL && value <= end; value = php_memnstr(value + 1, ";", 1, end)) { - do { - value++; - } while (*value == ' ' && value <= end); - - if (value <= end && (value_end = php_memnstr(value, " ", 1, end)) != NULL && value_end <= end) { - add_next_index_stringl(element, value, value_end - value, 1); - } - } - - /* add parsed values under key */ - key = estrndup(start, space - start); - add_assoc_zval_ex(result, key, space - start + 1, element); - efree(key); - - return 1; -} -/* }}} */ - -static int mmc_stats_parse_generic(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */ -{ - char *space, *key; - - /* "stats maps" returns "\n" delimited lines, other commands uses "\r\n" */ - if (*end == '\r') { - end--; - } - - if (start <= end) { - if ((space = php_memnstr(start, " ", 1, end)) != NULL) { - key = estrndup(start, space - start); - add_assoc_stringl_ex(result, key, space - start + 1, space + 1, end - space, 1); - efree(key); - } - else { - add_next_index_stringl(result, start, end - start, 1); - } - } - - return 1; -} -/* }}} */ - -static int mmc_get_stats(mmc_t *mmc, char *type, int slabid, int limit, zval *result TSRMLS_DC) /* {{{ */ -{ - char *command; - int command_len, response_len; - - if (slabid) { - command_len = spprintf(&command, 0, "stats %s %d %d", type, slabid, limit); - } - else if (type) { - command_len = spprintf(&command, 0, "stats %s", type); - } - else { - command_len = spprintf(&command, 0, "stats"); - } - - if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { - efree(command); - return -1; - } - - efree(command); - array_init(result); - - while ((response_len = mmc_readline(mmc TSRMLS_CC)) >= 0) { - if (mmc_str_left(mmc->inbuf, "ERROR", response_len, sizeof("ERROR") - 1) || - mmc_str_left(mmc->inbuf, "CLIENT_ERROR", response_len, sizeof("CLIENT_ERROR") - 1) || - mmc_str_left(mmc->inbuf, "SERVER_ERROR", response_len, sizeof("SERVER_ERROR") - 1)) { - - zend_hash_destroy(Z_ARRVAL_P(result)); - FREE_HASHTABLE(Z_ARRVAL_P(result)); - - ZVAL_FALSE(result); - return 0; - } - else if (mmc_str_left(mmc->inbuf, "RESET", response_len, sizeof("RESET") - 1)) { - zend_hash_destroy(Z_ARRVAL_P(result)); - FREE_HASHTABLE(Z_ARRVAL_P(result)); - - ZVAL_TRUE(result); - return 1; - } - else if (mmc_str_left(mmc->inbuf, "ITEM ", response_len, sizeof("ITEM ") - 1)) { - if (!mmc_stats_parse_item(mmc->inbuf + (sizeof("ITEM ") - 1), mmc->inbuf + response_len - sizeof("\r\n"), result TSRMLS_CC)) { - zend_hash_destroy(Z_ARRVAL_P(result)); - FREE_HASHTABLE(Z_ARRVAL_P(result)); - return -1; - } - } - else if (mmc_str_left(mmc->inbuf, "STAT ", response_len, sizeof("STAT ") - 1)) { - if (!mmc_stats_parse_stat(mmc->inbuf + (sizeof("STAT ") - 1), mmc->inbuf + response_len - sizeof("\r\n"), result TSRMLS_CC)) { - zend_hash_destroy(Z_ARRVAL_P(result)); - FREE_HASHTABLE(Z_ARRVAL_P(result)); - return -1; - } - } - else if (mmc_str_left(mmc->inbuf, "END", response_len, sizeof("END") - 1)) { - break; - } - else if (!mmc_stats_parse_generic(mmc->inbuf, mmc->inbuf + response_len - sizeof("\n"), result TSRMLS_CC)) { - zend_hash_destroy(Z_ARRVAL_P(result)); - FREE_HASHTABLE(Z_ARRVAL_P(result)); - return -1; - } - } - - if (response_len < 0) { - zend_hash_destroy(Z_ARRVAL_P(result)); - FREE_HASHTABLE(Z_ARRVAL_P(result)); - return -1; - } - - return 1; -} -/* }}} */ - -static int mmc_incr_decr(mmc_t *mmc, int cmd, char *key, int key_len, int value, long *number TSRMLS_DC) /* {{{ */ -{ - char *command; - int command_len, response_len; - - if (cmd > 0) { - command_len = spprintf(&command, 0, "incr %s %d", key, value); - } - else { - command_len = spprintf(&command, 0, "decr %s %d", key, value); - } - - if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { - efree(command); - return -1; - } - efree(command); - - if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { - MMC_DEBUG(("failed to read the server's response")); - return -1; - } - - MMC_DEBUG(("mmc_incr_decr: server's answer is: '%s'", mmc->inbuf)); - if (mmc_str_left(mmc->inbuf, "NOT_FOUND", response_len, sizeof("NOT_FOUND") - 1)) { - MMC_DEBUG(("failed to %sement variable - item with such key not found", cmd > 0 ? "incr" : "decr")); - return 0; - } - else if (mmc_str_left(mmc->inbuf, "ERROR", response_len, sizeof("ERROR") - 1) || - mmc_str_left(mmc->inbuf, "CLIENT_ERROR", response_len, sizeof("CLIENT_ERROR") - 1) || - mmc_str_left(mmc->inbuf, "SERVER_ERROR", response_len, sizeof("SERVER_ERROR") - 1)) { - mmc_server_received_error(mmc, response_len); - return -1; - } - - *number = (long)atol(mmc->inbuf); - return 1; -} -/* }}} */ - -static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, char *command, int command_len) /* {{{ */ -{ - mmc_pool_t *pool; - zval *value, *mmc_object = getThis(); - - int result, key_len; - char *key; - long flags = 0, expire = 0; - char key_tmp[MMC_KEY_MAX_SIZE]; - unsigned int key_tmp_len; - - php_serialize_data_t value_hash; - smart_str buf = {0}; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osz|ll", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &value, &flags, &expire) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|ll", &key, &key_len, &value, &flags, &expire) == FAILURE) { - return; - } - } - - if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { - RETURN_FALSE; - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { - RETURN_FALSE; - } - - switch (Z_TYPE_P(value)) { - case IS_STRING: - result = mmc_pool_store( - pool, command, command_len, key_tmp, key_tmp_len, flags, expire, - Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC); - break; - - case IS_LONG: - case IS_DOUBLE: - case IS_BOOL: { - zval value_copy; - - /* FIXME: we should be using 'Z' instead of this, but unfortunately it's PHP5-only */ - value_copy = *value; - zval_copy_ctor(&value_copy); - convert_to_string(&value_copy); - - result = mmc_pool_store( - pool, command, command_len, key_tmp, key_tmp_len, flags, expire, - Z_STRVAL(value_copy), Z_STRLEN(value_copy) TSRMLS_CC); - - zval_dtor(&value_copy); - break; - } - - default: { - zval value_copy, *value_copy_ptr; - - /* FIXME: we should be using 'Z' instead of this, but unfortunately it's PHP5-only */ - value_copy = *value; - zval_copy_ctor(&value_copy); - value_copy_ptr = &value_copy; - - PHP_VAR_SERIALIZE_INIT(value_hash); - php_var_serialize(&buf, &value_copy_ptr, &value_hash TSRMLS_CC); - PHP_VAR_SERIALIZE_DESTROY(value_hash); - - if (!buf.c) { - /* something went really wrong */ - zval_dtor(&value_copy); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to serialize value"); - RETURN_FALSE; - } - - flags |= MMC_SERIALIZED; - zval_dtor(&value_copy); - - result = mmc_pool_store( - pool, command, command_len, key_tmp, key_tmp_len, flags, expire, - buf.c, buf.len TSRMLS_CC); - } - } - - if (flags & MMC_SERIALIZED) { - smart_str_free(&buf); - } - - if (result > 0) { - RETURN_TRUE; - } - - RETURN_FALSE; -} -/* }}} */ - -static void php_mmc_incr_decr(INTERNAL_FUNCTION_PARAMETERS, int cmd) /* {{{ */ -{ - mmc_t *mmc; - mmc_pool_t *pool; - int result = -1, key_len; - long value = 1, number; - char *key; - zval *mmc_object = getThis(); - char key_tmp[MMC_KEY_MAX_SIZE]; - unsigned int key_tmp_len; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &value) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len, &value) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { - RETURN_FALSE; - } - - if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { - RETURN_FALSE; - } - - while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) { - if ((result = mmc_incr_decr(mmc, cmd, key_tmp, key_tmp_len, value, &number TSRMLS_CC)) < 0) { - mmc_server_failure(mmc TSRMLS_CC); - } - } - - if (result > 0) { - RETURN_LONG(number); - } - RETURN_FALSE; -} -/* }}} */ - -static void php_mmc_connect (INTERNAL_FUNCTION_PARAMETERS, int persistent) /* {{{ */ -{ - zval **connection, *mmc_object = getThis(); - mmc_t *mmc = NULL; - mmc_pool_t *pool; - int resource_type, host_len, errnum = 0, list_id; - char *host, *error_string = NULL; - long port = MEMCACHE_G(default_port), timeout = MMC_DEFAULT_TIMEOUT, timeoutms = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lll", &host, &host_len, &port, &timeout, &timeoutms) == FAILURE) { - return; - } - - if (timeoutms < 1) { - timeoutms = MEMCACHE_G(default_timeout_ms); - } - - /* initialize and connect server struct */ - if (persistent) { - mmc = mmc_find_persistent(host, host_len, port, timeout, MMC_DEFAULT_RETRY TSRMLS_CC); - } - else { - MMC_DEBUG(("php_mmc_connect: creating regular connection")); - mmc = mmc_server_new(host, host_len, port, 0, timeout, MMC_DEFAULT_RETRY TSRMLS_CC); - } - - mmc->timeout = timeout; - mmc->connect_timeoutms = timeoutms; - - if (!mmc_open(mmc, 1, &error_string, &errnum TSRMLS_CC)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%ld, %s (%d)", host, port, error_string ? error_string : "Unknown error", errnum); - if (!persistent) { - mmc_server_free(mmc TSRMLS_CC); - } - if (error_string) { - efree(error_string); - } - RETURN_FALSE; - } - - /* initialize pool and object if need be */ - if (!mmc_object) { - pool = mmc_pool_new(TSRMLS_C); - mmc_pool_add(pool, mmc, 1); - - object_init_ex(return_value, memcache_class_entry_ptr); - list_id = zend_list_insert(pool, le_memcache_pool); - add_property_resource(return_value, "connection", list_id); - } - else if (zend_hash_find(Z_OBJPROP_P(mmc_object), "connection", sizeof("connection"), (void **) &connection) != FAILURE) { - pool = (mmc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type); - if (!pool || resource_type != le_memcache_pool) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown connection identifier"); - RETURN_FALSE; - } - - mmc_pool_add(pool, mmc, 1); - RETURN_TRUE; - } - else { - pool = mmc_pool_new(TSRMLS_C); - mmc_pool_add(pool, mmc, 1); - - list_id = zend_list_insert(pool, le_memcache_pool); - add_property_resource(mmc_object, "connection", list_id); - RETURN_TRUE; - } -} -/* }}} */ - -/* ---------------- - module functions - ---------------- */ - -/* {{{ proto object memcache_connect( string host [, int port [, int timeout ] ]) - Connects to server and returns a Memcache object */ -PHP_FUNCTION(memcache_connect) -{ - php_mmc_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); -} -/* }}} */ - -/* {{{ proto object memcache_pconnect( string host [, int port [, int timeout ] ]) - Connects to server and returns a Memcache object */ -PHP_FUNCTION(memcache_pconnect) -{ - php_mmc_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); -} -/* }}} */ - -/* {{{ proto bool memcache_add_server( string host [, int port [, bool persistent [, int weight [, int timeout [, int retry_interval [, bool status [, callback failure_callback ] ] ] ] ] ] ]) - Adds a connection to the pool. The order in which this function is called is significant */ -PHP_FUNCTION(memcache_add_server) -{ - zval **connection, *mmc_object = getThis(), *failure_callback = NULL; - mmc_pool_t *pool; - mmc_t *mmc; - long port = MEMCACHE_G(default_port), weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY, timeoutms = 0; - zend_bool persistent = 1, status = 1; - int resource_type, host_len, list_id; - char *host; - - if (mmc_object) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lblllbzl", &host, &host_len, &port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback, &timeoutms) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lblllbzl", &mmc_object, memcache_class_entry_ptr, &host, &host_len, &port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback, &timeoutms) == FAILURE) { - return; - } - } - - if (timeoutms < 1) { - timeoutms = MEMCACHE_G(default_timeout_ms); - } - - if (weight < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "weight must be a positive integer"); - RETURN_FALSE; - } - - if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { - if (!IS_CALLABLE(failure_callback, 0, NULL)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback"); - RETURN_FALSE; - } - } - - /* lazy initialization of server struct */ - if (persistent) { - mmc = mmc_find_persistent(host, host_len, port, timeout, retry_interval TSRMLS_CC); - } - else { - MMC_DEBUG(("memcache_add_server: initializing regular struct")); - mmc = mmc_server_new(host, host_len, port, 0, timeout, retry_interval TSRMLS_CC); - } - - mmc->connect_timeoutms = timeoutms; - - /* add server in failed mode */ - if (!status) { - mmc->status = MMC_STATUS_FAILED; - } - - if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { - mmc->failure_callback = failure_callback; - mmc_server_callback_ctor(&mmc->failure_callback TSRMLS_CC); - } - - /* initialize pool if need be */ - if (zend_hash_find(Z_OBJPROP_P(mmc_object), "connection", sizeof("connection"), (void **) &connection) == FAILURE) { - pool = mmc_pool_new(TSRMLS_C); - list_id = zend_list_insert(pool, le_memcache_pool); - add_property_resource(mmc_object, "connection", list_id); - } - else { - pool = (mmc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type); - if (!pool || resource_type != le_memcache_pool) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to extract 'connection' variable from object"); - RETURN_FALSE; - } - } - - mmc_pool_add(pool, mmc, weight); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool memcache_set_server_params( string host [, int port [, int timeout [, int retry_interval [, bool status [, callback failure_callback ] ] ] ] ]) - Changes server parameters at runtime */ -PHP_FUNCTION(memcache_set_server_params) -{ - zval *mmc_object = getThis(), *failure_callback = NULL; - mmc_pool_t *pool; - mmc_t *mmc = NULL; - long port = MEMCACHE_G(default_port), timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY; - zend_bool status = 1; - int host_len, i; - char *host; - - if (mmc_object) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lllbz", &host, &host_len, &port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lllbz", &mmc_object, memcache_class_entry_ptr, &host, &host_len, &port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - for (i=0; i<pool->num_servers; i++) { - if (!strcmp(pool->servers[i]->host, host) && pool->servers[i]->port == port) { - mmc = pool->servers[i]; - break; - } - } - - if (!mmc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server not found in pool"); - RETURN_FALSE; - } - - if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { - if (!IS_CALLABLE(failure_callback, 0, NULL)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback"); - RETURN_FALSE; - } - } - - mmc->timeout = timeout; - mmc->retry_interval = retry_interval; - - if (!status) { - mmc->status = MMC_STATUS_FAILED; - } - else if (mmc->status == MMC_STATUS_FAILED) { - mmc->status = MMC_STATUS_DISCONNECTED; - } - - if (failure_callback != NULL) { - if (mmc->failure_callback != NULL) { - mmc_server_callback_dtor(&mmc->failure_callback TSRMLS_CC); - } - - if (Z_TYPE_P(failure_callback) != IS_NULL) { - mmc->failure_callback = failure_callback; - mmc_server_callback_ctor(&mmc->failure_callback TSRMLS_CC); - } - else { - mmc->failure_callback = NULL; - } - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto int memcache_get_server_status( string host [, int port ]) - Returns server status (0 if server is failed, otherwise non-zero) */ -PHP_FUNCTION(memcache_get_server_status) -{ - zval *mmc_object = getThis(); - mmc_pool_t *pool; - mmc_t *mmc = NULL; - long port = MEMCACHE_G(default_port); - int host_len, i; - char *host; - - if (mmc_object) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &host, &host_len, &port) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &host, &host_len, &port) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - for (i=0; i<pool->num_servers; i++) { - if (!strcmp(pool->servers[i]->host, host) && pool->servers[i]->port == port) { - mmc = pool->servers[i]; - break; - } - } - - if (!mmc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server not found in pool"); - RETURN_FALSE; - } - - RETURN_LONG(mmc->status); -} -/* }}} */ - -mmc_t *mmc_find_persistent(char *host, int host_len, int port, int timeout, int retry_interval TSRMLS_DC) /* {{{ */ -{ - mmc_t *mmc; - zend_rsrc_list_entry *le; - char *hash_key; - int hash_key_len; - - MMC_DEBUG(("mmc_find_persistent: seeking for persistent connection")); - hash_key_len = spprintf(&hash_key, 0, "mmc_connect___%s:%d", host, port); - - if (zend_hash_find(&EG(persistent_list), hash_key, hash_key_len+1, (void **) &le) == FAILURE) { - zend_rsrc_list_entry new_le; - MMC_DEBUG(("mmc_find_persistent: connection wasn't found in the hash")); - - mmc = mmc_server_new(host, host_len, port, 1, timeout, retry_interval TSRMLS_CC); - new_le.type = le_pmemcache; - new_le.ptr = mmc; - - /* register new persistent connection */ - if (zend_hash_update(&EG(persistent_list), hash_key, hash_key_len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) { - mmc_server_free(mmc TSRMLS_CC); - mmc = NULL; - } else { - zend_list_insert(mmc, le_pmemcache); - } - } - else if (le->type != le_pmemcache || le->ptr == NULL) { - zend_rsrc_list_entry new_le; - MMC_DEBUG(("mmc_find_persistent: something was wrong, reconnecting..")); - zend_hash_del(&EG(persistent_list), hash_key, hash_key_len+1); - - mmc = mmc_server_new(host, host_len, port, 1, timeout, retry_interval TSRMLS_CC); - new_le.type = le_pmemcache; - new_le.ptr = mmc; - - /* register new persistent connection */ - if (zend_hash_update(&EG(persistent_list), hash_key, hash_key_len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) { - mmc_server_free(mmc TSRMLS_CC); - mmc = NULL; - } - else { - zend_list_insert(mmc, le_pmemcache); - } - } - else { - MMC_DEBUG(("mmc_find_persistent: connection found in the hash")); - mmc = (mmc_t *)le->ptr; - mmc->timeout = timeout; - mmc->retry_interval = retry_interval; - - /* attempt to reconnect this node before failover in case connection has gone away */ - if (mmc->status == MMC_STATUS_CONNECTED) { - mmc->status = MMC_STATUS_UNKNOWN; - } - } - - efree(hash_key); - return mmc; -} -/* }}} */ - -/* {{{ proto string memcache_get_version( object memcache ) - Returns server's version */ -PHP_FUNCTION(memcache_get_version) -{ - mmc_pool_t *pool; - char *version; - int i; - zval *mmc_object = getThis(); - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_class_entry_ptr) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - for (i=0; i<pool->num_servers; i++) { - if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { - if ((version = mmc_get_version(pool->servers[i] TSRMLS_CC)) != NULL) { - RETURN_STRING(version, 0); - } - else { - mmc_server_failure(pool->servers[i] TSRMLS_CC); - } - } - } - - RETURN_FALSE; -} -/* }}} */ - -/* {{{ proto bool memcache_add( object memcache, string key, mixed var [, int flag [, int expire ] ] ) - Adds new item. Item with such key should not exist. */ -PHP_FUNCTION(memcache_add) -{ - php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "add", sizeof("add") - 1); -} -/* }}} */ - -/* {{{ proto bool memcache_set( object memcache, string key, mixed var [, int flag [, int expire ] ] ) - Sets the value of an item. Item may exist or not */ -PHP_FUNCTION(memcache_set) -{ - php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "set", sizeof("set") - 1); -} -/* }}} */ - -/* {{{ proto bool memcache_replace( object memcache, string key, mixed var [, int flag [, int expire ] ] ) - Replaces existing item. Returns false if item doesn't exist */ -PHP_FUNCTION(memcache_replace) -{ - php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "replace", sizeof("replace") - 1); -} -/* }}} */ - -/* {{{ proto mixed memcache_get( object memcache, mixed key [, mixed &flags ] ) - Returns value of existing item or false */ -PHP_FUNCTION(memcache_get) -{ - mmc_pool_t *pool; - zval *zkey, *mmc_object = getThis(), *flags = NULL; - char key[MMC_KEY_MAX_SIZE]; - unsigned int key_len; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|z", &mmc_object, memcache_class_entry_ptr, &zkey, &flags) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &zkey, &flags) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { - RETURN_FALSE; - } - - if (Z_TYPE_P(zkey) != IS_ARRAY) { - if (mmc_prepare_key(zkey, key, &key_len TSRMLS_CC) == MMC_OK) { - if (mmc_exec_retrieval_cmd(pool, key, key_len, &return_value, flags TSRMLS_CC) < 0) { - zval_dtor(return_value); - RETVAL_FALSE; - } - } - else { - RETVAL_FALSE; - } - } else if (zend_hash_num_elements(Z_ARRVAL_P(zkey))){ - if (mmc_exec_retrieval_cmd_multi(pool, zkey, &return_value, flags TSRMLS_CC) < 0) { - zval_dtor(return_value); - RETVAL_FALSE; - } - } else { - RETVAL_FALSE; - } -} -/* }}} */ - -/* {{{ proto bool memcache_delete( object memcache, string key [, int expire ]) - Deletes existing item */ -PHP_FUNCTION(memcache_delete) -{ - mmc_t *mmc; - mmc_pool_t *pool; - int result = -1, key_len; - zval *mmc_object = getThis(); - char *key; - long time = 0; - char key_tmp[MMC_KEY_MAX_SIZE]; - unsigned int key_tmp_len; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &time) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len, &time) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { - RETURN_FALSE; - } - - if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { - RETURN_FALSE; - } - - while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) { - if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, time TSRMLS_CC)) < 0) { - mmc_server_failure(mmc TSRMLS_CC); - } - } - - if (result > 0) { - RETURN_TRUE; - } - RETURN_FALSE; -} -/* }}} */ - -/* {{{ proto bool memcache_debug( bool onoff ) - Turns on/off internal debugging */ -PHP_FUNCTION(memcache_debug) -{ -#if ZEND_DEBUG - zend_bool onoff; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &onoff) == FAILURE) { - return; - } - - MEMCACHE_G(debug_mode) = onoff ? 1 : 0; - - RETURN_TRUE; -#else - RETURN_FALSE; -#endif - -} -/* }}} */ - -/* {{{ proto array memcache_get_stats( object memcache [, string type [, int slabid [, int limit ] ] ]) - Returns server's statistics */ -PHP_FUNCTION(memcache_get_stats) -{ - mmc_pool_t *pool; - int i, failures = 0; - zval *mmc_object = getThis(); - - char *type = NULL; - int type_len = 0; - long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_class_entry_ptr, &type, &type_len, &slabid, &limit) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sll", &type, &type_len, &slabid, &limit) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - for (i=0; i<pool->num_servers; i++) { - if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { - if (mmc_get_stats(pool->servers[i], type, slabid, limit, return_value TSRMLS_CC) < 0) { - mmc_server_failure(pool->servers[i] TSRMLS_CC); - failures++; - } - else { - break; - } - } - else { - failures++; - } - } - - if (failures >= pool->num_servers) { - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto array memcache_get_extended_stats( object memcache [, string type [, int slabid [, int limit ] ] ]) - Returns statistics for each server in the pool */ -PHP_FUNCTION(memcache_get_extended_stats) -{ - mmc_pool_t *pool; - char *hostname; - int i, hostname_len; - zval *mmc_object = getThis(), *stats; - - char *type = NULL; - int type_len = 0; - long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_class_entry_ptr, &type, &type_len, &slabid, &limit) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sll", &type, &type_len, &slabid, &limit) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - array_init(return_value); - for (i=0; i<pool->num_servers; i++) { - MAKE_STD_ZVAL(stats); - - hostname_len = spprintf(&hostname, 0, "%s:%d", pool->servers[i]->host, pool->servers[i]->port); - - if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { - if (mmc_get_stats(pool->servers[i], type, slabid, limit, stats TSRMLS_CC) < 0) { - mmc_server_failure(pool->servers[i] TSRMLS_CC); - ZVAL_FALSE(stats); - } - } - else { - ZVAL_FALSE(stats); - } - - add_assoc_zval_ex(return_value, hostname, hostname_len + 1, stats); - efree(hostname); - } -} -/* }}} */ - -/* {{{ proto array memcache_set_compress_threshold( object memcache, int threshold [, float min_savings ] ) - Set automatic compress threshold */ -PHP_FUNCTION(memcache_set_compress_threshold) -{ - mmc_pool_t *pool; - zval *mmc_object = getThis(); - long threshold; - double min_savings = MMC_DEFAULT_SAVINGS; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|d", &mmc_object, memcache_class_entry_ptr, &threshold, &min_savings) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|d", &threshold, &min_savings) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - if (threshold < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "threshold must be a positive integer"); - RETURN_FALSE; - } - pool->compress_threshold = threshold; - - if (min_savings != MMC_DEFAULT_SAVINGS) { - if (min_savings < 0 || min_savings > 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "min_savings must be a float in the 0..1 range"); - RETURN_FALSE; - } - pool->min_compress_savings = min_savings; - } - else { - pool->min_compress_savings = MMC_DEFAULT_SAVINGS; - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto int memcache_increment( object memcache, string key [, int value ] ) - Increments existing variable */ -PHP_FUNCTION(memcache_increment) -{ - php_mmc_incr_decr(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); -} -/* }}} */ - -/* {{{ proto int memcache_decrement( object memcache, string key [, int value ] ) - Decrements existing variable */ -PHP_FUNCTION(memcache_decrement) -{ - php_mmc_incr_decr(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); -} -/* }}} */ - -/* {{{ proto bool memcache_close( object memcache ) - Closes connection to memcached */ -PHP_FUNCTION(memcache_close) -{ - mmc_pool_t *pool; - zval *mmc_object = getThis(); - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_class_entry_ptr) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - if (!mmc_pool_close(pool TSRMLS_CC)) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool memcache_flush( object memcache [, int timestamp ] ) - Flushes cache, optionally at the specified time */ -PHP_FUNCTION(memcache_flush) -{ - mmc_pool_t *pool; - int i, failures = 0; - zval *mmc_object = getThis(); - long timestamp = 0; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &mmc_object, memcache_class_entry_ptr, ×tamp) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", ×tamp) == FAILURE) { - return; - } - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - for (i=0; i<pool->num_servers; i++) { - if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { - if (mmc_flush(pool->servers[i], timestamp TSRMLS_CC) < 0) { - mmc_server_failure(pool->servers[i] TSRMLS_CC); - failures++; - } - } - else { - failures++; - } - } - - if (failures && failures >= pool->num_servers) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool memcache_setoptimeout( object memcache , int timeoutms ) - Set the timeout, in milliseconds, for subsequent operations on all open connections */ -PHP_FUNCTION(memcache_setoptimeout) -{ - mmc_pool_t *pool; - mmc_t *mmc; - int i; - zval *mmc_object = getThis(); - long timeoutms = 0; - - if (mmc_object == NULL) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &mmc_object, memcache_class_entry_ptr, &timeoutms) == FAILURE) { - return; - } - } - else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &timeoutms) == FAILURE) { - return; - } - } - - if (timeoutms < 1) { - timeoutms = MEMCACHE_G(default_timeout_ms); - } - - if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { - RETURN_FALSE; - } - - for (i = 0; i < pool->num_servers; i++) { - mmc = pool->servers[i]; - mmc->timeoutms = timeoutms; - } - RETURN_TRUE; -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/memcache.php ^ |
@@ -1,881 +0,0 @@ -<?php -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2004 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Harun Yayli <harunyayli at gmail.com> | - +----------------------------------------------------------------------+ -*/ - -$VERSION='$Id: memcache.php,v 1.2 2008/09/11 19:21:06 mikl Exp $'; - -define('ADMIN_USERNAME','memcache'); // Admin Username -define('ADMIN_PASSWORD','password'); // Admin Password -define('DATE_FORMAT','Y/m/d H:i:s'); -define('GRAPH_SIZE',200); -define('MAX_ITEM_DUMP',50); - -$MEMCACHE_SERVERS[] = 'mymemcache-server1:11211'; // add more as an array -$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array - - -////////// END OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////// - -///////////////// Password protect //////////////////////////////////////////////////////////////// -if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || - $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||$_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) { - Header("WWW-Authenticate: Basic realm=\"Memcache Login\""); - Header("HTTP/1.0 401 Unauthorized"); - - echo <<<EOB - <html><body> - <h1>Rejected!</h1> - <big>Wrong Username or Password!</big> - </body></html> -EOB; - exit; -} - -///////////MEMCACHE FUNCTIONS ///////////////////////////////////////////////////////////////////// - -function sendMemcacheCommands($command){ - global $MEMCACHE_SERVERS; - $result = array(); - - foreach($MEMCACHE_SERVERS as $server){ - $strs = explode(':',$server); - $host = $strs[0]; - $port = $strs[1]; - $result[$server] = sendMemcacheCommand($host,$port,$command); - } - return $result; -} -function sendMemcacheCommand($server,$port,$command){ - - $s = @fsockopen($server,$port); - if (!$s){ - die("Cant connect to:".$server.':'.$port); - } - - fwrite($s, $command."\r\n"); - - $buf=''; - while ((!feof($s))) { - $buf .= fgets($s, 256); - if (strpos($buf,"END\r\n")!==false){ // stat says end - break; - } - if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these - break; - } - if (strpos($buf,"OK\r\n")!==false){ // flush_all says ok - break; - } - } - fclose($s); - return parseMemcacheResults($buf); -} -function parseMemcacheResults($str){ - - $res = array(); - $lines = explode("\r\n",$str); - $cnt = count($lines); - for($i=0; $i< $cnt; $i++){ - $line = $lines[$i]; - $l = explode(' ',$line,3); - if (count($l)==3){ - $res[$l[0]][$l[1]]=$l[2]; - if ($l[0]=='VALUE'){ // next line is the value - $res[$l[0]][$l[1]] = array(); - list ($flag,$size)=explode(' ',$l[2]); - $res[$l[0]][$l[1]]['stat']=array('flag'=>$flag,'size'=>$size); - $res[$l[0]][$l[1]]['value']=$lines[++$i]; - } - }elseif($line=='DELETED' || $line=='NOT_FOUND' || $line=='OK'){ - return $line; - } - } - return $res; - -} - -function dumpCacheSlab($server,$slabId,$limit){ - list($host,$port) = explode(':',$server); - $resp = sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit); - - return $resp; - -} - -function flushServer($server){ - list($host,$port) = explode(':',$server); - $resp = sendMemcacheCommand($host,$port,'flush_all'); - return $resp; -} -function getCacheItems(){ - $items = sendMemcacheCommands('stats items'); - $serverItems = array(); - $totalItems = array(); - foreach ($items as $server=>$itemlist){ - $serverItems[$server] = array(); - $totalItems[$server]=0; - if (!isset($itemlist['STAT'])){ - continue; - } - - $iteminfo = $itemlist['STAT']; - - foreach($iteminfo as $keyinfo=>$value){ - if (preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){ - $serverItems[$server][$matches[1]][$matches[2]] = $value; - if ($matches[2]=='number'){ - $totalItems[$server] +=$value; - } - } - } - } - return array('items'=>$serverItems,'counts'=>$totalItems); -} -function getMemcacheStats($total=true){ - $resp = sendMemcacheCommands('stats'); - if ($total){ - $res = array(); - foreach($resp as $server=>$r){ - foreach($r['STAT'] as $key=>$row){ - if (!isset($res[$key])){ - $res[$key]=null; - } - switch ($key){ - case 'pid': - $res['pid'][$server]=$row; - break; - case 'uptime': - $res['uptime'][$server]=$row; - break; - case 'time': - $res['time'][$server]=$row; - break; - case 'version': - $res['version'][$server]=$row; - break; - case 'pointer_size': - $res['pointer_size'][$server]=$row; - break; - case 'rusage_user': - $res['rusage_user'][$server]=$row; - break; - case 'rusage_system': - $res['rusage_system'][$server]=$row; - break; - case 'curr_items': - $res['curr_items']+=$row; - break; - case 'total_items': - $res['total_items']+=$row; - break; - case 'bytes': - $res['bytes']+=$row; - break; - case 'curr_connections': - $res['curr_connections']+=$row; - break; - case 'total_connections': - $res['total_connections']+=$row; - break; - case 'connection_structures': - $res['connection_structures']+=$row; - break; - case 'cmd_get': - $res['cmd_get']+=$row; - break; - case 'cmd_set': - $res['cmd_set']+=$row; - break; - case 'get_hits': - $res['get_hits']+=$row; - break; - case 'get_misses': - $res['get_misses']+=$row; - break; - case 'evictions': - $res['evictions']+=$row; - break; - case 'bytes_read': - $res['bytes_read']+=$row; - break; - case 'bytes_written': - $res['bytes_written']+=$row; - break; - case 'limit_maxbytes': - $res['limit_maxbytes']+=$row; - break; - case 'threads': - $res['rusage_system'][$server]=$row; - break; - } - } - } - return $res; - } - return $resp; -} - -////////////////////////////////////////////////////// - -// -// don't cache this page -// -header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); // HTTP/1.0 - -function duration($ts) { - global $time; - $years = (int)((($time - $ts)/(7*86400))/52.177457); - $rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400)); - $weeks = (int)(($rem)/(7*86400)); - $days = (int)(($rem)/86400) - $weeks*7; - $hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24; - $mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60; - $str = ''; - if($years==1) $str .= "$years year, "; - if($years>1) $str .= "$years years, "; - if($weeks==1) $str .= "$weeks week, "; - if($weeks>1) $str .= "$weeks weeks, "; - if($days==1) $str .= "$days day,"; - if($days>1) $str .= "$days days,"; - if($hours == 1) $str .= " $hours hour and"; - if($hours>1) $str .= " $hours hours and"; - if($mins == 1) $str .= " 1 minute"; - else $str .= " $mins minutes"; - return $str; -} - -// create graphics -// -function graphics_avail() { - return extension_loaded('gd'); -} - -function bsize($s) { - foreach (array('','K','M','G') as $i => $k) { - if ($s < 1024) break; - $s/=1024; - } - return sprintf("%5.1f %sBytes",$s,$k); -} - -// create menu entry -function menu_entry($ob,$title) { - global $PHP_SELF; - if ($ob==$_GET['op']){ - return "<li><a class=\"child_active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>"; - } - return "<li><a class=\"active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>"; -} - -function getHeader(){ - $header = <<<EOB -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head><title>MEMCACHE INFO</title> -<style type="text/css"><!-- -body { background:white; font-size:100.01%; margin:0; padding:0; } -body,p,td,th,input,submit { font-size:0.8em;font-family:arial,helvetica,sans-serif; } -* html body {font-size:0.8em} -* html p {font-size:0.8em} -* html td {font-size:0.8em} -* html th {font-size:0.8em} -* html input {font-size:0.8em} -* html submit {font-size:0.8em} -td { vertical-align:top } -a { color:black; font-weight:none; text-decoration:none; } -a:hover { text-decoration:underline; } -div.content { padding:1em 1em 1em 1em; position:absolute; width:97%; z-index:100; } - -h1.memcache { background:rgb(153,153,204); margin:0; padding:0.5em 1em 0.5em 1em; } -* html h1.memcache { margin-bottom:-7px; } -h1.memcache a:hover { text-decoration:none; color:rgb(90,90,90); } -h1.memcache span.logo { - background:rgb(119,123,180); - color:black; - border-right: solid black 1px; - border-bottom: solid black 1px; - font-style:italic; - font-size:1em; - padding-left:1.2em; - padding-right:1.2em; - text-align:right; - display:block; - width:130px; - } -h1.memcache span.logo span.name { color:white; font-size:0.7em; padding:0 0.8em 0 2em; } -h1.memcache span.nameinfo { color:white; display:inline; font-size:0.4em; margin-left: 3em; } -h1.memcache div.copy { color:black; font-size:0.4em; position:absolute; right:1em; } -hr.memcache { - background:white; - border-bottom:solid rgb(102,102,153) 1px; - border-style:none; - border-top:solid rgb(102,102,153) 10px; - height:12px; - margin:0; - margin-top:1px; - padding:0; -} - -ol,menu { margin:1em 0 0 0; padding:0.2em; margin-left:1em;} -ol.menu li { display:inline; margin-right:0.7em; list-style:none; font-size:85%} -ol.menu a { - background:rgb(153,153,204); - border:solid rgb(102,102,153) 2px; - color:white; - font-weight:bold; - margin-right:0em; - padding:0.1em 0.5em 0.1em 0.5em; - text-decoration:none; - margin-left: 5px; - } -ol.menu a.child_active { - background:rgb(153,153,204); - border:solid rgb(102,102,153) 2px; - color:white; - font-weight:bold; - margin-right:0em; - padding:0.1em 0.5em 0.1em 0.5em; - text-decoration:none; - border-left: solid black 5px; - margin-left: 0px; - } -ol.menu span.active { - background:rgb(153,153,204); - border:solid rgb(102,102,153) 2px; - color:black; - font-weight:bold; - margin-right:0em; - padding:0.1em 0.5em 0.1em 0.5em; - text-decoration:none; - border-left: solid black 5px; - } -ol.menu span.inactive { - background:rgb(193,193,244); - border:solid rgb(182,182,233) 2px; - color:white; - font-weight:bold; - margin-right:0em; - padding:0.1em 0.5em 0.1em 0.5em; - text-decoration:none; - margin-left: 5px; - } -ol.menu a:hover { - background:rgb(193,193,244); - text-decoration:none; - } - - -div.info { - background:rgb(204,204,204); - border:solid rgb(204,204,204) 1px; - margin-bottom:1em; - } -div.info h2 { - background:rgb(204,204,204); - color:black; - font-size:1em; - margin:0; - padding:0.1em 1em 0.1em 1em; - } -div.info table { - border:solid rgb(204,204,204) 1px; - border-spacing:0; - width:100%; - } -div.info table th { - background:rgb(204,204,204); - color:white; - margin:0; - padding:0.1em 1em 0.1em 1em; - } -div.info table th a.sortable { color:black; } -div.info table tr.tr-0 { background:rgb(238,238,238); } -div.info table tr.tr-1 { background:rgb(221,221,221); } -div.info table td { padding:0.3em 1em 0.3em 1em; } -div.info table td.td-0 { border-right:solid rgb(102,102,153) 1px; white-space:nowrap; } -div.info table td.td-n { border-right:solid rgb(102,102,153) 1px; } -div.info table td h3 { - color:black; - font-size:1.1em; - margin-left:-0.3em; - } -.td-0 a , .td-n a, .tr-0 a , tr-1 a { - text-decoration:underline; -} -div.graph { margin-bottom:1em } -div.graph h2 { background:rgb(204,204,204);; color:black; font-size:1em; margin:0; padding:0.1em 1em 0.1em 1em; } -div.graph table { border:solid rgb(204,204,204) 1px; color:black; font-weight:normal; width:100%; } -div.graph table td.td-0 { background:rgb(238,238,238); } -div.graph table td.td-1 { background:rgb(221,221,221); } -div.graph table td { padding:0.2em 1em 0.4em 1em; } - -div.div1,div.div2 { margin-bottom:1em; width:35em; } -div.div3 { position:absolute; left:40em; top:1em; width:580px; } -//div.div3 { position:absolute; left:37em; top:1em; right:1em; } - -div.sorting { margin:1.5em 0em 1.5em 2em } -.center { text-align:center } -.aright { position:absolute;right:1em } -.right { text-align:right } -.ok { color:rgb(0,200,0); font-weight:bold} -.failed { color:rgb(200,0,0); font-weight:bold} - -span.box { - border: black solid 1px; - border-right:solid black 2px; - border-bottom:solid black 2px; - padding:0 0.5em 0 0.5em; - margin-right:1em; -} -span.green { background:#60F060; padding:0 0.5em 0 0.5em} -span.red { background:#D06030; padding:0 0.5em 0 0.5em } - -div.authneeded { - background:rgb(238,238,238); - border:solid rgb(204,204,204) 1px; - color:rgb(200,0,0); - font-size:1.2em; - font-weight:bold; - padding:2em; - text-align:center; - } - -input { - background:rgb(153,153,204); - border:solid rgb(102,102,153) 2px; - color:white; - font-weight:bold; - margin-right:1em; - padding:0.1em 0.5em 0.1em 0.5em; - } -//--> -</style> -</head> -<body> -<div class="head"> - <h1 class="memcache"> - <span class="logo"><a href="http://pecl.php.net/package/memcache">memcache</a></span> - <span class="nameinfo">memcache.php by <a href="http://livebookmark.net">Harun Yayli</a></span> - </h1> - <hr class="memcache"> -</div> -<div class=content> -EOB; - - return $header; -} -function getFooter(){ - global $VERSION; - $footer = '</div><!-- Based on apc.php '.$VERSION.'--></body> -</html> -'; - - return $footer; - -} -function getMenu(){ - global $PHP_SELF; -echo "<ol class=menu>"; -if ($_GET['op']!=4){ -echo <<<EOB - <li><a href="$PHP_SELF&op={$_GET['op']}">Refresh Data</a></li> -EOB; -} -else { -echo <<<EOB - <li><a href="$PHP_SELF&op=2}">Back</a></li> -EOB; -} -echo - menu_entry(1,'View Host Stats'), - menu_entry(2,'Variables'); - -echo <<<EOB - </ol> - <br/> -EOB; -} - -// TODO, AUTH - -$_GET['op'] = !isset($_GET['op'])? '1':$_GET['op']; -$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : ''; - -$PHP_SELF=$PHP_SELF.'?'; -$time = time(); -// sanitize _GET - -foreach($_GET as $key=>$g){ - $_GET[$key]=htmlentities($g); -} - - -// singleout -// when singleout is set, it only gives details for that server. -if (isset($_GET['singleout']) && $_GET['singleout']>=0 && $_GET['singleout'] <count($MEMCACHE_SERVERS)){ - $MEMCACHE_SERVERS = array($MEMCACHE_SERVERS[$_GET['singleout']]); -} - -// display images -if (isset($_GET['IMG'])){ - $memcacheStats = getMemcacheStats(); - $memcacheStatsSingle = getMemcacheStats(false); - - if (!graphics_avail()) { - exit(0); - } - - function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') { - global $col_black; - $x1=$x+$w-1; - $y1=$y+$h-1; - - imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black); - if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2); - else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2); - imagerectangle($im, $x, $y1, $x1, $y, $color1); - if ($text) { - if ($placeindex>0) { - - if ($placeindex<16) - { - $px=5; - $py=$placeindex*12+6; - imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2); - imageline($im,$x,$y+$h/2,$px+90,$py,$color2); - imagestring($im,2,$px,$py-6,$text,$color1); - - } else { - if ($placeindex<31) { - $px=$x+40*2; - $py=($placeindex-15)*12+6; - } else { - $px=$x+40*2+100*intval(($placeindex-15)/15); - $py=($placeindex%15)*12+6; - } - imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2); - imageline($im,$x+$w,$y+$h/2,$px,$py,$color2); - imagestring($im,2,$px+2,$py-6,$text,$color1); - } - } else { - imagestring($im,4,$x+5,$y1-16,$text,$color1); - } - } - } - - - function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) { - $r=$diameter/2; - $w=deg2rad((360+$start+($end-$start)/2)%360); - - - if (function_exists("imagefilledarc")) { - // exists only if GD 2.0.1 is avaliable - imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE); - imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE); - imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); - } else { - imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2); - imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); - imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); - imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); - imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); - imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2); - } - if ($text) { - if ($placeindex>0) { - imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); - imagestring($im,4,$diameter, $placeindex*12,$text,$color1); - - } else { - imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); - } - } - } - $size = GRAPH_SIZE; // image size - $image = imagecreate($size+50, $size+10); - - $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF); - $col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30); - $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60); - $col_black = imagecolorallocate($image, 0, 0, 0); - - imagecolortransparent($image,$col_white); - - switch ($_GET['IMG']){ - case 1: // pie chart - $tsize=$memcacheStats['limit_maxbytes']; - $avail=$tsize-$memcacheStats['bytes']; - $x=$y=$size/2; - $angle_from = 0; - $fuzz = 0.000001; - - foreach($memcacheStatsSingle as $serv=>$mcs) { - $free = $mcs['STAT']['limit_maxbytes']-$mcs['STAT']['bytes']; - $used = $mcs['STAT']['bytes']; - - - if ($free>0){ - // draw free - $angle_to = ($free*360)/$tsize; - $perc =sprintf("%.2f%%", ($free *100) / $tsize) ; - - fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_green,$perc); - $angle_from = $angle_from + $angle_to ; - } - if ($used>0){ - // draw used - $angle_to = ($used*360)/$tsize; - $perc =sprintf("%.2f%%", ($used *100) / $tsize) ; - fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_red, '('.$perc.')' ); - $angle_from = $angle_from+ $angle_to ; - } - } - - break; - - case 2: // hit miss - - $hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits']; - $misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses']; - $total = $hits + $misses ; - - fill_box($image, 30,$size,50,-$hits*($size-21)/$total,$col_black,$col_green,sprintf("%.1f%%",$hits*100/$total)); - fill_box($image,130,$size,50,-max(4,($total-$hits)*($size-21)/$total),$col_black,$col_red,sprintf("%.1f%%",$misses*100/$total)); - break; - - } - header("Content-type: image/png"); - imagepng($image); - exit; -} - -echo getHeader(); -echo getMenu(); - -switch ($_GET['op']) { - - case 1: // host stats - $phpversion = phpversion(); - $memcacheStats = getMemcacheStats(); - $memcacheStatsSingle = getMemcacheStats(false); - - $mem_size = $memcacheStats['limit_maxbytes']; - $mem_used = $memcacheStats['bytes']; - $mem_avail= $mem_size-$mem_used; - $startTime = time()-array_sum($memcacheStats['uptime']); - - $curr_items = $memcacheStats['curr_items']; - $total_items = $memcacheStats['total_items']; - $hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits']; - $misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses']; - $sets = $memcacheStats['cmd_set']; - - $req_rate = sprintf("%.2f",($hits+$misses)/($time-$startTime)); - $hit_rate = sprintf("%.2f",($hits)/($time-$startTime)); - $miss_rate = sprintf("%.2f",($misses)/($time-$startTime)); - $set_rate = sprintf("%.2f",($sets)/($time-$startTime)); - - echo <<< EOB - <div class="info div1"><h2>General Cache Information</h2> - <table cellspacing=0><tbody> - <tr class=tr-1><td class=td-0>PHP Version</td><td>$phpversion</td></tr> -EOB; - echo "<tr class=tr-0><td class=td-0>Memcached Host". ((count($MEMCACHE_SERVERS)>1) ? 's':'')."</td><td>"; - $i=0; - if (!isset($_GET['singleout']) && count($MEMCACHE_SERVERS)>1){ - foreach($MEMCACHE_SERVERS as $server){ - echo ($i+1).'. <a href="'.$PHP_SELF.'&singleout='.$i++.'">'.$server.'</a><br/>'; - } - } - else{ - echo '1.'.$MEMCACHE_SERVERS[0]; - } - if (isset($_GET['singleout'])){ - echo '<a href="'.$PHP_SELF.'">(all servers)</a><br/>'; - } - echo "</td></tr>\n"; - echo "<tr class=tr-1><td class=td-0>Total Memcache Cache</td><td>".bsize($memcacheStats['limit_maxbytes'])."</td></tr>\n"; - - echo <<<EOB - </tbody></table> - </div> - - <div class="info div1"><h2>Memcache Server Information</h2> -EOB; - foreach($MEMCACHE_SERVERS as $server){ - echo '<table cellspacing=0><tbody>'; - echo '<tr class=tr-1><td class=td-1>'.$server.'</td><td><a href="'.$PHP_SELF.'&server='.array_search($server,$MEMCACHE_SERVERS).'&op=6">[<b>Flush this server</b>]</a></td></tr>'; - echo '<tr class=tr-0><td class=td-0>Start Time</td><td>',date(DATE_FORMAT,$memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>'; - echo '<tr class=tr-1><td class=td-0>Uptime</td><td>',duration($memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>'; - echo '<tr class=tr-0><td class=td-0>Memcached Server Version</td><td>'.$memcacheStatsSingle[$server]['STAT']['version'].'</td></tr>'; - echo '<tr class=tr-1><td class=td-0>Used Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['bytes']),'</td></tr>'; - echo '<tr class=tr-0><td class=td-0>Total Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['limit_maxbytes']),'</td></tr>'; - echo '</tbody></table>'; - } - echo <<<EOB - - </div> - <div class="graph div3"><h2>Host Status Diagrams</h2> - <table cellspacing=0><tbody> -EOB; - - $size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10); - echo <<<EOB - <tr> - <td class=td-0>Cache Usage</td> - <td class=td-1>Hits & Misses</td> - </tr> -EOB; - - echo - graphics_avail() ? - '<tr>'. - "<td class=td-0><img alt=\"\" $size src=\"$PHP_SELF&IMG=1&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td>". - "<td class=td-1><img alt=\"\" $size src=\"$PHP_SELF&IMG=2&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td></tr>\n" - : "", - '<tr>', - '<td class=td-0><span class="green box"> </span>Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size),"</td>\n", - '<td class=td-1><span class="green box"> </span>Hits: ',$hits.sprintf(" (%.1f%%)",$hits*100/($hits+$misses)),"</td>\n", - '</tr>', - '<tr>', - '<td class=td-0><span class="red box"> </span>Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size),"</td>\n", - '<td class=td-1><span class="red box"> </span>Misses: ',$misses.sprintf(" (%.1f%%)",$misses*100/($hits+$misses)),"</td>\n"; - echo <<< EOB - </tr> - </tbody></table> -<br/> - <div class="info"><h2>Cache Information</h2> - <table cellspacing=0><tbody> - <tr class=tr-0><td class=td-0>Current Items(total)</td><td>$curr_items ($total_items)</td></tr> - <tr class=tr-1><td class=td-0>Hits</td><td>{$hits}</td></tr> - <tr class=tr-0><td class=td-0>Misses</td><td>{$misses}</td></tr> - <tr class=tr-1><td class=td-0>Request Rate (hits, misses)</td><td>$req_rate cache requests/second</td></tr> - <tr class=tr-0><td class=td-0>Hit Rate</td><td>$hit_rate cache requests/second</td></tr> - <tr class=tr-1><td class=td-0>Miss Rate</td><td>$miss_rate cache requests/second</td></tr> - <tr class=tr-0><td class=td-0>Set Rate</td><td>$set_rate cache requests/second</td></tr> - </tbody></table> - </div> - -EOB; - - break; - - case 2: // variables - - $m=0; - $cacheItems= getCacheItems(); - $items = $cacheItems['items']; - $totals = $cacheItems['counts']; - $maxDump = MAX_ITEM_DUMP; - foreach($items as $server => $entries) { - - echo <<< EOB - - <div class="info"><table cellspacing=0><tbody> - <tr><th colspan="2">$server</th></tr> - <tr><th>Slab Id</th><th>Info</th></tr> -EOB; - - foreach($entries as $slabId => $slab) { - $dumpUrl = $PHP_SELF.'&op=2&server='.(array_search($server,$MEMCACHE_SERVERS)).'&dumpslab='.$slabId; - echo - "<tr class=tr-$m>", - "<td class=td-0><center>",'<a href="',$dumpUrl,'">',$slabId,'</a>',"</center></td>", - "<td class=td-last><b>Item count:</b> ",$slab['number'],'<br/><b>Age:</b>',duration($time-$slab['age']),'<br/> <b>Evicted:</b>',((isset($slab['evicted']) && $slab['evicted']==1)? 'Yes':'No'); - if ((isset($_GET['dumpslab']) && $_GET['dumpslab']==$slabId) && (isset($_GET['server']) && $_GET['server']==array_search($server,$MEMCACHE_SERVERS))){ - echo "<br/><b>Items: item</b><br/>"; - $items = dumpCacheSlab($server,$slabId,$slab['number']); - // maybe someone likes to do a pagination here :) - $i=1; - foreach($items['ITEM'] as $itemKey=>$itemInfo){ - $itemInfo = trim($itemInfo,'[ ]'); - - - echo '<a href="',$PHP_SELF,'&op=4&server=',(array_search($server,$MEMCACHE_SERVERS)),'&key=',base64_encode($itemKey).'">',$itemKey,'</a>'; - if ($i++ % 10 == 0) { - echo '<br/>'; - } - elseif ($i!=$slab['number']+1){ - echo ','; - } - } - } - - echo "</td></tr>"; - $m=1-$m; - } - echo <<<EOB - </tbody></table> - </div><hr/> -EOB; -} - break; - - break; - - case 4: //item dump - if (!isset($_GET['key']) || !isset($_GET['server'])){ - echo "No key set!"; - break; - } - // I'm not doing anything to check the validity of the key string. - // probably an exploit can be written to delete all the files in key=base64_encode("\n\r delete all"). - // somebody has to do a fix to this. - $theKey = htmlentities(base64_decode($_GET['key'])); - - $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; - list($h,$p) = explode(':',$theserver); - $r = sendMemcacheCommand($h,$p,'get '.$theKey); - echo <<<EOB - <div class="info"><table cellspacing=0><tbody> - <tr><th>Server<th>Key</th><th>Value</th><th>Delete</th></tr> -EOB; - echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey, - " <br/>flag:",$r['VALUE'][$theKey]['stat']['flag'], - " <br/>Size:",bsize($r['VALUE'][$theKey]['stat']['size']), - "</td><td>",chunk_split($r['VALUE'][$theKey]['value'],40),"</td>", - '<td><a href="',$PHP_SELF,'&op=5&server=',(int)$_GET['server'],'&key=',base64_encode($theKey),"\">Delete</a></td>","</tr>"; - echo <<<EOB - </tbody></table> - </div><hr/> -EOB; - break; - case 5: // item delete - if (!isset($_GET['key']) || !isset($_GET['server'])){ - echo "No key set!"; - break; - } - $theKey = htmlentities(base64_decode($_GET['key'])); - $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; - list($h,$p) = explode(':',$theserver); - $r = sendMemcacheCommand($h,$p,'delete '.$theKey); - echo 'Deleting '.$theKey.':'.$r; - break; - - case 6: // flush server - $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; - $r = flushServer($theserver); - echo 'Flush '.$theserver.":".$r; - break; -} -echo getFooter(); - -?> \ No newline at end of file | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/memcache_consistent_hash.c ^ |
@@ -1,198 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2007 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Antony Dovgal <tony@daylessday.org> | - | Mikael Johansson <mikael AT synd DOT info> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: memcache_consistent_hash.c,v 1.7 2009/01/15 18:11:41 mikl Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> - -#include "php.h" -#include "php_memcache.h" - -ZEND_EXTERN_MODULE_GLOBALS(memcache) - -typedef struct mmc_consistent_point { - mmc_t *server; - unsigned int point; -} mmc_consistent_point_t; - -typedef struct mmc_consistent_state { - int num_servers; - mmc_consistent_point_t *points; - 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(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; -} -/* }}} */ - -void mmc_consistent_free_state(void *s) /* {{{ */ -{ - mmc_consistent_state_t *state = s; - if (state != NULL) { - if (state->points != NULL) { - efree(state->points); - } - efree(state); - } -} -/* }}} */ - -static int mmc_consistent_compare(const void *a, const void *b) /* {{{ */ -{ - if (((mmc_consistent_point_t *)a)->point < ((mmc_consistent_point_t *)b)->point) { - return -1; - } - if (((mmc_consistent_point_t *)a)->point > ((mmc_consistent_point_t *)b)->point) { - return 1; - } - return 0; -} -/* }}} */ - -static mmc_t *mmc_consistent_find(mmc_consistent_state_t *state, unsigned int point) /* {{{ */ -{ - int lo = 0, hi = state->num_points - 1, mid; - - while (1) { - /* point is outside interval or lo >= hi, wrap-around */ - if (point <= state->points[lo].point || point > state->points[hi].point) { - return state->points[lo].server; - } - - /* test middle point */ - mid = lo + (hi - lo) / 2; - MMC_DEBUG(("mmc_consistent_find: lo %d, hi %d, mid %d, point %u, midpoint %u", lo, hi, mid, point, state->points[mid].point)); - - /* perfect match */ - if (point <= state->points[mid].point && point > (mid ? state->points[mid-1].point : 0)) { - return state->points[mid].server; - } - - /* too low, go up */ - if (state->points[mid].point < point) { - lo = mid + 1; - } - else { - hi = mid - 1; - } - } -} -/* }}} */ - -static void mmc_consistent_populate_buckets(mmc_consistent_state_t *state) /* {{{ */ -{ - unsigned int i, step = 0xffffffff / MMC_CONSISTENT_BUCKETS; - - qsort((void *)state->points, state->num_points, sizeof(mmc_consistent_point_t), mmc_consistent_compare); - for (i=0; i<MMC_CONSISTENT_BUCKETS; i++) { - state->buckets[i] = mmc_consistent_find(state, step * i); - } - - state->buckets_populated = 1; -} -/* }}} */ - -mmc_t *mmc_consistent_find_server(void *s, const char *key, int key_len TSRMLS_DC) /* {{{ */ -{ - mmc_consistent_state_t *state = s; - mmc_t *mmc; - - if (state->num_servers > 1) { - unsigned int i, hash = state->hash(key, key_len); - - if (!state->buckets_populated) { - mmc_consistent_populate_buckets(state); - } - - mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS]; - - /* perform failover if needed */ - for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i<MEMCACHE_G(max_failover_attempts); i++) { - char *next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1); - int next_len = sprintf(next_key, "%s-%d", key, i); - MMC_DEBUG(("mmc_consistent_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status)); - - hash = state->hash(next_key, next_len); - mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS]; - - efree(next_key); - } - } - else { - mmc = state->points[0].server; - mmc_open(mmc, 0, NULL, NULL TSRMLS_CC); - } - - return mmc->status != MMC_STATUS_FAILED ? mmc : NULL; -} -/* }}} */ - -void mmc_consistent_add_server(void *s, mmc_t *mmc, unsigned int weight) /* {{{ */ -{ - mmc_consistent_state_t *state = s; - int i, key_len, points = weight * MMC_CONSISTENT_POINTS; - - /* buffer for "host:port-i\0" */ - char *key = emalloc(strlen(mmc->host) + MAX_LENGTH_OF_LONG * 2 + 3); - - /* add weight * MMC_CONSISTENT_POINTS number of points for this server */ - state->points = erealloc(state->points, sizeof(mmc_consistent_point_t) * (state->num_points + points)); - - for (i=0; i<points; i++) { - key_len = sprintf(key, "%s:%d-%d", mmc->host, mmc->port, i); - state->points[state->num_points + i].server = mmc; - state->points[state->num_points + i].point = state->hash(key, key_len); - MMC_DEBUG(("mmc_consistent_add_server: key %s, point %lu", key, state->points[state->num_points + i].point)); - } - - state->num_points += points; - state->num_servers++; - state->buckets_populated = 0; - - efree(key); -} -/* }}} */ - -mmc_hash_t mmc_consistent_hash = { - mmc_consistent_create_state, - mmc_consistent_free_state, - mmc_consistent_find_server, - mmc_consistent_add_server -}; - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/memcache_queue.c ^ |
@@ -1,128 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2004 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Antony Dovgal <tony@daylessday.org> | - | Mikael Johansson <mikael AT synd DOT info> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: memcache_queue.c,v 1.4 2008/08/16 10:15:54 tony2001 Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#include "memcache_queue.h" - -void mmc_queue_push(mmc_queue_t *queue, void *ptr) { - if (queue->len >= queue->alloc) { - int increase = 1 + MMC_QUEUE_PREALLOC; - queue->alloc += increase; - queue->items = erealloc(queue->items, sizeof(*queue->items) * queue->alloc); - - /* move tail segment downwards */ - if (queue->head < queue->tail) { - memmove(queue->items + queue->tail + increase, queue->items + queue->tail, (queue->alloc - queue->tail - increase) * sizeof(*queue->items)); - queue->tail += increase; - } - } - - if (queue->len) { - queue->head++; - - if (queue->head >= queue->alloc) { - queue->head = 0; - } - } - - queue->items[queue->head] = ptr; - queue->len++; -} - -void *mmc_queue_pop(mmc_queue_t *queue) { - if (queue->len) { - void *ptr; - - ptr = queue->items[queue->tail]; - queue->len--; - - if (queue->len) { - queue->tail++; - - if (queue->tail >= queue->alloc) { - queue->tail = 0; - } - } - - return ptr; - } - return NULL; -} - -int mmc_queue_contains(mmc_queue_t *queue, void *ptr) { - if (queue != NULL) { - int i; - - for (i=0; i < queue->len; i++) { - if (mmc_queue_item(queue, i) == ptr) { - return 1; - } - } - } - - return 0; -} - -void mmc_queue_free(mmc_queue_t *queue) { - if (queue->items != NULL) { - efree(queue->items); - } - memset(queue, 0, sizeof(*queue)); -} - -void mmc_queue_copy(mmc_queue_t *source, mmc_queue_t *target) { - if (target->alloc != source->alloc) { - target->alloc = source->alloc; - erealloc(target->items, sizeof(*target->items) * target->alloc); - } - - memcpy(target->items, source->items, sizeof(*source->items) * source->alloc); - target->head = source->head; - target->tail = source->tail; - target->len = source->len; -} - -void mmc_queue_remove(mmc_queue_t *queue, void *ptr) { - void *item; - mmc_queue_t original = *queue; - mmc_queue_release(queue); - - while ((item = mmc_queue_pop(&original)) != NULL) { - if (item != ptr) { - mmc_queue_push(queue, item); - } - } - - mmc_queue_free(&original); -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/memcache_queue.h ^ |
@@ -1,56 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2007 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Antony Dovgal <tony@daylessday.org> | - | Mikael Johansson <mikael AT synd DOT info> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: memcache_queue.h,v 1.4 2008/08/16 10:15:54 tony2001 Exp $ */ - -#ifndef MEMCACHE_QUEUE_H_ -#define MEMCACHE_QUEUE_H_ - -/* request / server stack */ -#define MMC_QUEUE_PREALLOC 25 - -typedef struct mmc_queue { - void **items; /* items on queue */ - int alloc; /* allocated size */ - int head; /* head index in ring buffer */ - int tail; /* tail index in ring buffer */ - int len; -} mmc_queue_t; - -#define mmc_queue_release(q) memset((q), 0, sizeof(*(q))) -#define mmc_queue_reset(q) (q)->len = (q)->head = (q)->tail = 0 -#define mmc_queue_item(q, i) ((q)->tail + (i) < (q)->alloc ? (q)->items[(q)->tail + (i)] : (q)->items[(i) - ((q)->alloc - (q)->tail)]) - -void mmc_queue_push(mmc_queue_t *, void *); -void *mmc_queue_pop(mmc_queue_t *); -int mmc_queue_contains(mmc_queue_t *, void *); -void mmc_queue_free(mmc_queue_t *); -void mmc_queue_copy(mmc_queue_t *, mmc_queue_t *); -void mmc_queue_remove(mmc_queue_t *, void *); - -#endif /*MEMCACHE_QUEUE_H_*/ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/memcache_session.c ^ |
@@ -1,286 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2004 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Antony Dovgal <tony@daylessday.org> | - | Mikael Johansson <mikael AT synd DOT info> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: memcache_session.c,v 1.9 2008/08/16 10:15:54 tony2001 Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <ctype.h> -#include "php.h" -#include "php_ini.h" -#include "php_variables.h" - -#include "SAPI.h" -#include "ext/standard/url.h" -#include "php_memcache.h" - -ps_module ps_mod_memcache = { - PS_MOD(memcache) -}; - -/* {{{ PS_OPEN_FUNC - */ -PS_OPEN_FUNC(memcache) -{ - mmc_pool_t *pool; - mmc_t *mmc; - - php_url *url; - zval *params, **param; - int i, j, path_len; - - pool = mmc_pool_new(TSRMLS_C); - - for (i=0,j=0,path_len=strlen(save_path); i<path_len; i=j+1) { - /* find beginning of url */ - while (i<path_len && (isspace(save_path[i]) || save_path[i] == ',')) - i++; - - /* find end of url */ - j = i; - while (j<path_len && !isspace(save_path[j]) && save_path[j] != ',') - j++; - - if (i < j) { - int persistent = 0, weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY; - - /* translate unix: into file: */ - if (!strncmp(save_path+i, "unix:", sizeof("unix:")-1)) { - int len = j-i; - char *path = estrndup(save_path+i, len); - memcpy(path, "file:", sizeof("file:")-1); - url = php_url_parse_ex(path, len); - efree(path); - } - else { - url = php_url_parse_ex(save_path+i, j-i); - } - - if (!url) { - char *path = estrndup(save_path+i, j-i); - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "Failed to parse session.save_path (error at offset %d, url was '%s')", i, path); - efree(path); - - mmc_pool_free(pool TSRMLS_CC); - PS_SET_MOD_DATA(NULL); - return FAILURE; - } - - /* parse parameters */ - if (url->query != NULL) { - MAKE_STD_ZVAL(params); - array_init(params); - - sapi_module.treat_data(PARSE_STRING, estrdup(url->query), params TSRMLS_CC); - - if (zend_hash_find(Z_ARRVAL_P(params), "persistent", sizeof("persistent"), (void **) ¶m) != FAILURE) { - convert_to_boolean_ex(param); - persistent = Z_BVAL_PP(param); - } - - if (zend_hash_find(Z_ARRVAL_P(params), "weight", sizeof("weight"), (void **) ¶m) != FAILURE) { - convert_to_long_ex(param); - weight = Z_LVAL_PP(param); - } - - if (zend_hash_find(Z_ARRVAL_P(params), "timeout", sizeof("timeout"), (void **) ¶m) != FAILURE) { - convert_to_long_ex(param); - timeout = Z_LVAL_PP(param); - } - - if (zend_hash_find(Z_ARRVAL_P(params), "retry_interval", sizeof("retry_interval"), (void **) ¶m) != FAILURE) { - convert_to_long_ex(param); - retry_interval = Z_LVAL_PP(param); - } - - zval_ptr_dtor(¶ms); - } - - if (url->scheme && url->path && !strcmp(url->scheme, "file")) { - char *host; - int host_len = spprintf(&host, 0, "unix://%s", url->path); - - /* chop off trailing :0 port specifier */ - if (!strcmp(host + host_len - 2, ":0")) { - host_len -= 2; - } - - if (persistent) { - mmc = mmc_find_persistent(host, host_len, 0, timeout, retry_interval TSRMLS_CC); - } - else { - mmc = mmc_server_new(host, host_len, 0, 0, timeout, retry_interval TSRMLS_CC); - } - - efree(host); - } - else { - if (url->host == NULL || weight <= 0 || timeout <= 0) { - php_url_free(url); - mmc_pool_free(pool TSRMLS_CC); - PS_SET_MOD_DATA(NULL); - return FAILURE; - } - - if (persistent) { - mmc = mmc_find_persistent(url->host, strlen(url->host), url->port, timeout, retry_interval TSRMLS_CC); - } - else { - mmc = mmc_server_new(url->host, strlen(url->host), url->port, 0, timeout, retry_interval TSRMLS_CC); - } - } - - mmc_pool_add(pool, mmc, weight); - php_url_free(url); - } - } - - if (pool->num_servers) { - PS_SET_MOD_DATA(pool); - return SUCCESS; - } - - mmc_pool_free(pool TSRMLS_CC); - PS_SET_MOD_DATA(NULL); - return FAILURE; -} -/* }}} */ - -/* {{{ PS_CLOSE_FUNC - */ -PS_CLOSE_FUNC(memcache) -{ - mmc_pool_t *pool = PS_GET_MOD_DATA(); - - if (pool) { - mmc_pool_free(pool TSRMLS_CC); - PS_SET_MOD_DATA(NULL); - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ PS_READ_FUNC - */ -PS_READ_FUNC(memcache) -{ - mmc_pool_t *pool = PS_GET_MOD_DATA(); - zval *result; - - if (pool) { - char key_tmp[MMC_KEY_MAX_SIZE]; - unsigned int key_tmp_len; - - if (mmc_prepare_key_ex(key, strlen(key), key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { - return FAILURE; - } - - MAKE_STD_ZVAL(result); - ZVAL_NULL(result); - - if (mmc_exec_retrieval_cmd(pool, key_tmp, key_tmp_len, &result, NULL TSRMLS_CC) <= 0 || Z_TYPE_P(result) != IS_STRING) { - zval_ptr_dtor(&result); - return FAILURE; - } - - *val = Z_STRVAL_P(result); - *vallen = Z_STRLEN_P(result); - FREE_ZVAL(result); - return SUCCESS; - } - - return FAILURE; -} -/* }}} */ - -/* {{{ PS_WRITE_FUNC - */ -PS_WRITE_FUNC(memcache) -{ - mmc_pool_t *pool = PS_GET_MOD_DATA(); - - if (pool) { - char key_tmp[MMC_KEY_MAX_SIZE]; - unsigned int key_tmp_len; - - if (mmc_prepare_key_ex(key, strlen(key), key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { - return FAILURE; - } - - if (mmc_pool_store(pool, "set", sizeof("set")-1, key_tmp, key_tmp_len, 0, INI_INT("session.gc_maxlifetime"), val, vallen TSRMLS_CC)) { - return SUCCESS; - } - } - - return FAILURE; -} -/* }}} */ - -/* {{{ PS_DESTROY_FUNC - */ -PS_DESTROY_FUNC(memcache) -{ - mmc_pool_t *pool = PS_GET_MOD_DATA(); - mmc_t *mmc; - - int result = -1; - - if (pool) { - char key_tmp[MMC_KEY_MAX_SIZE]; - unsigned int key_tmp_len; - - if (mmc_prepare_key_ex(key, strlen(key), key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { - return FAILURE; - } - - while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) { - if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, 0 TSRMLS_CC)) < 0) { - mmc_server_failure(mmc TSRMLS_CC); - } - } - - if (result >= 0) { - return SUCCESS; - } - } - - return FAILURE; -} -/* }}} */ - -/* {{{ PS_GC_FUNC - */ -PS_GC_FUNC(memcache) -{ - return SUCCESS; -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/memcache_standard_hash.c ^ |
@@ -1,132 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2007 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Antony Dovgal <tony@daylessday.org> | - | Mikael Johansson <mikael AT synd DOT info> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: memcache_standard_hash.c,v 1.5 2008/08/16 10:15:54 tony2001 Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#include "php_memcache.h" - -ZEND_EXTERN_MODULE_GLOBALS(memcache) - -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(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; -} -/* }}} */ - -void mmc_standard_free_state(void *s) /* {{{ */ -{ - mmc_standard_state_t *state = s; - if (state != NULL) { - if (state->buckets != NULL) { - efree(state->buckets); - } - efree(state); - } -} -/* }}} */ - -static unsigned int mmc_hash(mmc_standard_state_t *state, const char *key, int key_len) /* {{{ */ -{ - unsigned int hash = (state->hash(key, key_len) >> 16) & 0x7fff; - return hash ? hash : 1; -} -/* }}} */ - -mmc_t *mmc_standard_find_server(void *s, const char *key, int key_len TSRMLS_DC) /* {{{ */ -{ - mmc_standard_state_t *state = s; - mmc_t *mmc; - - if (state->num_servers > 1) { - unsigned int hash = mmc_hash(state, key, key_len), i; - mmc = state->buckets[hash % state->num_buckets]; - - /* perform failover if needed */ - for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i<MEMCACHE_G(max_failover_attempts); i++) { - char *next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1); - int next_len = sprintf(next_key, "%d%s", i+1, key); - MMC_DEBUG(("mmc_standard_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status)); - - hash += mmc_hash(state, next_key, next_len); - mmc = state->buckets[hash % state->num_buckets]; - - efree(next_key); - } - } - else { - mmc = state->buckets[0]; - mmc_open(mmc, 0, NULL, NULL TSRMLS_CC); - } - - return mmc->status != MMC_STATUS_FAILED ? mmc : NULL; -} -/* }}} */ - -void mmc_standard_add_server(void *s, mmc_t *mmc, unsigned int weight) /* {{{ */ -{ - mmc_standard_state_t *state = s; - int i; - - /* add weight number of buckets for this server */ - if (state->num_buckets) { - state->buckets = erealloc(state->buckets, sizeof(mmc_t *) * (state->num_buckets + weight)); - } - else { - state->buckets = emalloc(sizeof(mmc_t *) * (weight)); - } - - for (i=0; i<weight; i++) { - state->buckets[state->num_buckets + i] = mmc; - } - - state->num_buckets += weight; - state->num_servers++; -} -/* }}} */ - -mmc_hash_t mmc_standard_hash = { - mmc_standard_create_state, - mmc_standard_free_state, - mmc_standard_find_server, - mmc_standard_add_server -}; - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
[+] | Deleted | memcache-2.2.5.tgz/memcache-2.2.5/php_memcache.h ^ |
@@ -1,229 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2007 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Antony Dovgal <tony@daylessday.org> | - | Mikael Johansson <mikael AT synd DOT info> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: php_memcache.h,v 1.39 2009/02/27 17:46:22 mikl Exp $ */ - -#ifndef PHP_MEMCACHE_H -#define PHP_MEMCACHE_H - -extern zend_module_entry memcache_module_entry; -#define phpext_memcache_ptr &memcache_module_entry - -#ifdef PHP_WIN32 -#define PHP_MEMCACHE_API __declspec(dllexport) -#else -#define PHP_MEMCACHE_API -#endif - -#ifdef ZTS -#include "TSRM.h" -#endif - -#include "ext/standard/php_smart_str_public.h" - -PHP_MINIT_FUNCTION(memcache); -PHP_MSHUTDOWN_FUNCTION(memcache); -PHP_RINIT_FUNCTION(memcache); -PHP_MINFO_FUNCTION(memcache); - -PHP_FUNCTION(memcache_connect); -PHP_FUNCTION(memcache_pconnect); -PHP_FUNCTION(memcache_add_server); -PHP_FUNCTION(memcache_set_server_params); -PHP_FUNCTION(memcache_get_server_status); -PHP_FUNCTION(memcache_get_version); -PHP_FUNCTION(memcache_add); -PHP_FUNCTION(memcache_set); -PHP_FUNCTION(memcache_replace); -PHP_FUNCTION(memcache_get); -PHP_FUNCTION(memcache_delete); -PHP_FUNCTION(memcache_debug); -PHP_FUNCTION(memcache_get_stats); -PHP_FUNCTION(memcache_get_extended_stats); -PHP_FUNCTION(memcache_set_compress_threshold); -PHP_FUNCTION(memcache_increment); -PHP_FUNCTION(memcache_decrement); -PHP_FUNCTION(memcache_close); -PHP_FUNCTION(memcache_flush); -PHP_FUNCTION(memcache_setoptimeout); - -#define PHP_MEMCACHE_VERSION "2.2.5" - -#define MMC_BUF_SIZE 4096 -#define MMC_SERIALIZED 1 -#define MMC_COMPRESSED 2 -#define MMC_DEFAULT_TIMEOUT 1 /* seconds */ -#define MMC_KEY_MAX_SIZE 250 /* stoled from memcached sources =) */ -#define MMC_DEFAULT_RETRY 15 /* retry failed server after x seconds */ -#define MMC_DEFAULT_SAVINGS 0.2 /* minimum 20% savings for compression to be used */ -#define MMC_DEFAULT_CACHEDUMP_LIMIT 100 /* number of entries */ - -#define MMC_STATUS_FAILED 0 -#define MMC_STATUS_DISCONNECTED 1 -#define MMC_STATUS_UNKNOWN 2 -#define MMC_STATUS_CONNECTED 3 - -#define MMC_OK 0 -#define MMC_REQUEST_FAILURE -1 - -#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 */ - -typedef struct mmc { - php_stream *stream; - char inbuf[MMC_BUF_SIZE]; - smart_str outbuf; - char *host; - unsigned short port; - long timeout; - long timeoutms; /* takes precedence over timeout */ - long connect_timeoutms; /* takes precedence over timeout */ - long failed; - long retry_interval; - int persistent; - int status; - char *error; /* last error message */ - int errnum; /* last error code */ - zval *failure_callback; - zend_bool in_free; -} mmc_t; - -/* hashing strategy */ -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); - -#define mmc_pool_find(pool, key, key_len) \ - pool->hash->find_server(pool->hash_state, key, key_len) - -typedef struct mmc_hash { - mmc_hash_create_state create_state; - mmc_hash_free_state free_state; - mmc_hash_find_server find_server; - mmc_hash_add_server add_server; -} mmc_hash_t; - -/* 32 bit magic FNV-1a prime and init */ -#define FNV_32_PRIME 0x01000193 -#define FNV_32_INIT 0x811c9dc5 - -typedef struct mmc_pool { - mmc_t **servers; - int num_servers; - mmc_t **requests; - int compress_threshold; - double min_compress_savings; - zend_bool in_free; - mmc_hash_t *hash; - void *hash_state; -} mmc_pool_t; - -/* our globals */ -ZEND_BEGIN_MODULE_GLOBALS(memcache) - long debug_mode; - long default_port; - long num_persistent; - long compression_level; - long allow_failover; - long chunk_size; - long max_failover_attempts; - long hash_strategy; - long hash_function; - long default_timeout_ms; -ZEND_END_MODULE_GLOBALS(memcache) - -#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3) -# define IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp) TSRMLS_CC) -#else -# define IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp)) -#endif - -/* internal functions */ -mmc_t *mmc_server_new(char *, int, unsigned short, int, int, int TSRMLS_DC); -mmc_t *mmc_find_persistent(char *, int, int, int, int TSRMLS_DC); -int mmc_server_failure(mmc_t * TSRMLS_DC); -void mmc_server_deactivate(mmc_t * TSRMLS_DC); - -int mmc_prepare_key(zval *, char *, unsigned int * TSRMLS_DC); -int mmc_prepare_key_ex(const char *, unsigned int, char *, unsigned int * TSRMLS_DC); - -mmc_pool_t *mmc_pool_new(TSRMLS_D); -void mmc_pool_free(mmc_pool_t * TSRMLS_DC); -void mmc_pool_add(mmc_pool_t *, mmc_t *, unsigned int); -int mmc_pool_store(mmc_pool_t *, const char *, int, const char *, int, int, int, const char *, int TSRMLS_DC); -int mmc_open(mmc_t *, int, char **, int * TSRMLS_DC); -int mmc_exec_retrieval_cmd(mmc_pool_t *, const char *, int, zval **, zval * TSRMLS_DC); -int mmc_delete(mmc_t *, const char *, int, int TSRMLS_DC); - -/* session handler struct */ -#if HAVE_MEMCACHE_SESSION -#include "ext/session/php_session.h" - -extern ps_module ps_mod_memcache; -#define ps_memcache_ptr &ps_mod_memcache - -PS_FUNCS(memcache); -#endif - -/* {{{ macros */ -#if ZEND_DEBUG - -void mmc_debug(const char *format, ...); - -#define MMC_DEBUG(info) \ -{\ - mmc_debug info; \ -}\ - -#else - -#define MMC_DEBUG(info) \ -{\ -}\ - -#endif -/* }}} */ - -#ifdef ZTS -#define MEMCACHE_G(v) TSRMG(memcache_globals_id, zend_memcache_globals *, v) -#else -#define MEMCACHE_G(v) (memcache_globals.v) -#endif - -#ifndef ZSTR -#define ZSTR -#endif - -#endif /* PHP_MEMCACHE_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
Deleted | memcache-2.2.6.tgz ^ | |
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/CREDITS ^ |
(renamed from memcache-2.2.5/CREDITS) | ||
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/CREDITS ^ |
(renamed from memcache-2.2.5/CREDITS) | ||
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/README ^ |
(renamed from memcache-2.2.5/README) | ||
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/README ^ |
(renamed from memcache-2.2.5/README) | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/config.m4 ^ |
@@ -0,0 +1,4 @@ +dnl $Id: config.m4 223414 2006-11-15 21:05:03Z tony2001 $ +dnl this file is required by phpize + +sinclude(config9.m4) | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/config.w32 ^ |
@@ -0,0 +1,19 @@ +// $Id: config.w32 278414 2009-04-08 08:37:29Z pajoye $ +// vim:ft=javascript + +ARG_ENABLE("memcache", "memcache support", "no"); + +if (PHP_MEMCACHE != "no") { + if ( + ((PHP_ZLIB=="no") && (CHECK_LIB("zlib_a.lib;zlib.lib", "memcache", PHP_MEMCACHE) )) || + (PHP_ZLIB_SHARED && CHECK_LIB("zlib.lib", "memcache", PHP_MEMCACHE)) || (PHP_ZLIB == "yes" && (!PHP_ZLIB_SHARED)) + ) { + EXTENSION("memcache", "memcache.c memcache_queue.c memcache_standard_hash.c memcache_consistent_hash.c memcache_session.c"); + AC_DEFINE('HAVE_MEMCACHE', 1, 'Have memcache support'); + ADD_FLAG("CFLAGS_MEMCACHE", "/D HAVE_MEMCACHE_SESSION=1"); + ADD_EXTENSION_DEP('memcache', 'session'); + } else { + WARNING("memcache not enabled; libraries and headers not found"); + } +} + | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/config9.m4 ^ |
@@ -0,0 +1,112 @@ +dnl +dnl $Id: config9.m4 245380 2007-11-01 14:30:16Z mikl $ +dnl + +PHP_ARG_ENABLE(memcache, whether to enable memcache support, +[ --enable-memcache Enable memcache support]) + +PHP_ARG_ENABLE(memcache-session, whether to enable memcache session handler support, +[ --disable-memcache-session Disable memcache session handler support], yes, no) + +if test -z "$PHP_ZLIB_DIR"; then +PHP_ARG_WITH(zlib-dir, for the location of ZLIB, +[ --with-zlib-dir[=DIR] memcache: Set the path to ZLIB install prefix.], no, no) +fi + +if test -z "$PHP_DEBUG"; then + AC_ARG_ENABLE(debug, + [ --enable-debug compile with debugging symbols],[ + PHP_DEBUG=$enableval + ],[ + PHP_DEBUG=no + ]) +fi + +if test "$PHP_MEMCACHE" != "no"; then + + if test "$PHP_ZLIB_DIR" != "no" && test "$PHP_ZLIB_DIR" != "yes"; then + if test -f "$PHP_ZLIB_DIR/include/zlib/zlib.h"; then + PHP_ZLIB_DIR="$PHP_ZLIB_DIR" + PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include/zlib" + elif test -f "$PHP_ZLIB_DIR/include/zlib.h"; then + PHP_ZLIB_DIR="$PHP_ZLIB_DIR" + PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include" + else + AC_MSG_ERROR([Can't find ZLIB headers under "$PHP_ZLIB_DIR"]) + fi + else + for i in /usr/local /usr; do + if test -f "$i/include/zlib/zlib.h"; then + PHP_ZLIB_DIR="$i" + PHP_ZLIB_INCDIR="$i/include/zlib" + elif test -f "$i/include/zlib.h"; then + PHP_ZLIB_DIR="$i" + PHP_ZLIB_INCDIR="$i/include" + fi + done + fi + + dnl # zlib + AC_MSG_CHECKING([for the location of zlib]) + if test "$PHP_ZLIB_DIR" = "no"; then + AC_MSG_ERROR([memcache support requires ZLIB. Use --with-zlib-dir=<DIR> to specify prefix where ZLIB include and library are located]) + else + AC_MSG_RESULT([$PHP_ZLIB_DIR]) + if test "z$PHP_LIBDIR" != "z"; then + dnl PHP5+ + PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR/$PHP_LIBDIR, MEMCACHE_SHARED_LIBADD) + else + dnl PHP4 + PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR/lib, MEMCACHE_SHARED_LIBADD) + fi + PHP_ADD_INCLUDE($PHP_ZLIB_INCDIR) + fi + + if test "$PHP_MEMCACHE_SESSION" != "no"; then + AC_MSG_CHECKING([for session includes]) + session_inc_path="" + + if test -f "$abs_srcdir/include/php/ext/session/php_session.h"; then + session_inc_path="$abs_srcdir/include/php" + elif test -f "$abs_srcdir/ext/session/php_session.h"; then + session_inc_path="$abs_srcdir" + elif test -f "$phpincludedir/ext/session/php_session.h"; then + session_inc_path="$phpincludedir" + else + for i in php php4 php5 php6; do + if test -f "$prefix/include/$i/ext/session/php_session.h"; then + session_inc_path="$prefix/include/$i" + fi + done + fi + + if test "$session_inc_path" = ""; then + AC_MSG_ERROR([Cannot find php_session.h]) + else + AC_MSG_RESULT([$session_inc_path]) + fi + fi + + AC_MSG_CHECKING([for memcache session support]) + if test "$PHP_MEMCACHE_SESSION" != "no"; then + AC_MSG_RESULT([enabled]) + AC_DEFINE(HAVE_MEMCACHE_SESSION,1,[Whether memcache session handler is enabled]) + AC_DEFINE(HAVE_MEMCACHE,1,[Whether you want memcache support]) + PHP_NEW_EXTENSION(memcache, memcache.c memcache_queue.c memcache_standard_hash.c memcache_consistent_hash.c memcache_session.c, $ext_shared,,-I$session_inc_path) + ifdef([PHP_ADD_EXTENSION_DEP], + [ + PHP_ADD_EXTENSION_DEP(memcache, session) + ]) + else + AC_MSG_RESULT([disabled]) + AC_DEFINE(HAVE_MEMCACHE,1,[Whether you want memcache support]) + PHP_NEW_EXTENSION(memcache, memcache.c memcache_queue.c memcache_standard_hash.c memcache_consistent_hash.c, $ext_shared) + fi + +dnl this is needed to build the extension with phpize and -Wall + + if test "$PHP_DEBUG" = "yes"; then + CFLAGS="$CFLAGS -Wall" + fi + +fi | ||
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/example.php ^ |
(renamed from memcache-2.2.5/example.php) | ||
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/example.php ^ |
(renamed from memcache-2.2.5/example.php) | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/memcache.c ^ |
@@ -0,0 +1,2709 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Antony Dovgal <tony@daylessday.org> | + | Mikael Johansson <mikael AT synd DOT info> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: memcache.c 327750 2012-09-23 01:47:59Z hradtke $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include <stdio.h> +#include <fcntl.h> +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif + +#include <zlib.h> +#include <time.h> +#include "ext/standard/crc32.h" +#include "ext/standard/info.h" +#include "ext/standard/php_string.h" +#include "ext/standard/php_var.h" +#include "ext/standard/php_smart_str.h" +#include "php_network.h" +#include "php_memcache.h" +#include "memcache_queue.h" + +#if HAVE_MEMCACHE_SESSION +#include "ext/session/php_session.h" +#endif + +#ifndef ZEND_ENGINE_2 +#define OnUpdateLong OnUpdateInt +#endif + +/* True global resources - no need for thread safety here */ +static int le_memcache_pool, le_pmemcache; +static zend_class_entry *memcache_class_entry_ptr; + +ZEND_DECLARE_MODULE_GLOBALS(memcache) + +/* {{{ memcache_functions[] + */ +zend_function_entry memcache_functions[] = { + PHP_FE(memcache_connect, NULL) + PHP_FE(memcache_pconnect, NULL) + PHP_FE(memcache_add_server, NULL) + PHP_FE(memcache_set_server_params, NULL) + PHP_FE(memcache_get_server_status, NULL) + PHP_FE(memcache_get_version, NULL) + PHP_FE(memcache_add, NULL) + PHP_FE(memcache_set, NULL) + PHP_FE(memcache_replace, NULL) + PHP_FE(memcache_get, NULL) + PHP_FE(memcache_delete, NULL) + PHP_FE(memcache_debug, NULL) + PHP_FE(memcache_get_stats, NULL) + PHP_FE(memcache_get_extended_stats, NULL) + PHP_FE(memcache_set_compress_threshold, NULL) + PHP_FE(memcache_increment, NULL) + PHP_FE(memcache_decrement, NULL) + PHP_FE(memcache_close, NULL) + PHP_FE(memcache_flush, NULL) + PHP_FE(memcache_setoptimeout, NULL) + {NULL, NULL, NULL} +}; + +static zend_function_entry php_memcache_class_functions[] = { + PHP_FALIAS(connect, memcache_connect, NULL) + PHP_FALIAS(pconnect, memcache_pconnect, NULL) + PHP_FALIAS(addserver, memcache_add_server, NULL) + PHP_FALIAS(setserverparams, memcache_set_server_params, NULL) + PHP_FALIAS(getserverstatus, memcache_get_server_status, NULL) + PHP_FALIAS(getversion, memcache_get_version, NULL) + PHP_FALIAS(add, memcache_add, NULL) + PHP_FALIAS(set, memcache_set, NULL) + PHP_FALIAS(replace, memcache_replace, NULL) + PHP_FALIAS(get, memcache_get, NULL) + PHP_FALIAS(delete, memcache_delete, NULL) + PHP_FALIAS(getstats, memcache_get_stats, NULL) + PHP_FALIAS(getextendedstats, memcache_get_extended_stats, NULL) + PHP_FALIAS(setcompressthreshold, memcache_set_compress_threshold, NULL) + PHP_FALIAS(increment, memcache_increment, NULL) + PHP_FALIAS(decrement, memcache_decrement, NULL) + PHP_FALIAS(close, memcache_close, NULL) + PHP_FALIAS(flush, memcache_flush, NULL) + PHP_FALIAS(setoptimeout, memcache_setoptimeout, NULL) + {NULL, NULL, NULL} +}; + +/* }}} */ + +/* {{{ memcache_module_entry + */ +zend_module_entry memcache_module_entry = { +#if ZEND_MODULE_API_NO >= 20010901 + STANDARD_MODULE_HEADER, +#endif + "memcache", + memcache_functions, + PHP_MINIT(memcache), + PHP_MSHUTDOWN(memcache), + PHP_RINIT(memcache), + NULL, + PHP_MINFO(memcache), +#if ZEND_MODULE_API_NO >= 20010901 + PHP_MEMCACHE_VERSION, +#endif + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +#ifdef COMPILE_DL_MEMCACHE +ZEND_GET_MODULE(memcache) +#endif + +static PHP_INI_MH(OnUpdateChunkSize) /* {{{ */ +{ + long int lval; + + lval = strtol(new_value, NULL, 10); + if (lval <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.chunk_size must be a positive integer ('%s' given)", new_value); + return FAILURE; + } + + return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); +} +/* }}} */ + +static PHP_INI_MH(OnUpdateFailoverAttempts) /* {{{ */ +{ + long int lval; + + lval = strtol(new_value, NULL, 10); + if (lval <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.max_failover_attempts must be a positive integer ('%s' given)", new_value); + return FAILURE; + } + + return OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); +} +/* }}} */ + +static PHP_INI_MH(OnUpdateHashStrategy) /* {{{ */ +{ + if (!strcasecmp(new_value, "standard")) { + MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH; + } + else if (!strcasecmp(new_value, "consistent")) { + MEMCACHE_G(hash_strategy) = MMC_CONSISTENT_HASH; + } + else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.hash_strategy must be in set {standard, consistent} ('%s' given)", new_value); + return FAILURE; + } + + return SUCCESS; +} +/* }}} */ + +static PHP_INI_MH(OnUpdateHashFunction) /* {{{ */ +{ + if (!strcasecmp(new_value, "crc32")) { + MEMCACHE_G(hash_function) = MMC_HASH_CRC32; + } + else if (!strcasecmp(new_value, "fnv")) { + MEMCACHE_G(hash_function) = 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; +} +/* }}} */ + +static PHP_INI_MH(OnUpdateDefaultTimeout) /* {{{ */ +{ + long int lval; + + lval = strtol(new_value, NULL, 10); + if (lval <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.default_timeout must be a positive number greater than or equal to 1 ('%s' given)", new_value); + return FAILURE; + } + MEMCACHE_G(default_timeout_ms) = lval; + 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) + STD_PHP_INI_ENTRY("memcache.max_failover_attempts", "20", PHP_INI_ALL, OnUpdateFailoverAttempts, max_failover_attempts, zend_memcache_globals, memcache_globals) + 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) + STD_PHP_INI_ENTRY("memcache.default_timeout_ms", "1000", PHP_INI_ALL, OnUpdateDefaultTimeout, default_timeout_ms, zend_memcache_globals, memcache_globals) +PHP_INI_END() +/* }}} */ + +/* {{{ internal function protos */ +static void _mmc_pool_list_dtor(zend_rsrc_list_entry * TSRMLS_DC); +static void _mmc_pserver_list_dtor(zend_rsrc_list_entry * TSRMLS_DC); + +static void mmc_server_free(mmc_t * TSRMLS_DC); +static void mmc_server_disconnect(mmc_t * TSRMLS_DC); +static int mmc_server_store(mmc_t *, const char *, int TSRMLS_DC); + +static int mmc_compress(char **, unsigned long *, const char *, int TSRMLS_DC); +static int mmc_uncompress(char **, unsigned long *, const char *, int); +static int mmc_get_pool(zval *, mmc_pool_t ** TSRMLS_DC); +static int mmc_readline(mmc_t * TSRMLS_DC); +static char * mmc_get_version(mmc_t * TSRMLS_DC); +static int mmc_str_left(char *, char *, int, int); +static int mmc_sendcmd(mmc_t *, const char *, int TSRMLS_DC); +static int mmc_parse_response(mmc_t *mmc, char *, int, char **, int *, int *, int *); +static int mmc_exec_retrieval_cmd_multi(mmc_pool_t *, zval *, zval **, zval * TSRMLS_DC); +static int mmc_read_value(mmc_t *, char **, int *, char **, int *, int * TSRMLS_DC); +static int mmc_flush(mmc_t *, int TSRMLS_DC); +static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, char *, int); +static int mmc_get_stats(mmc_t *, char *, int, int, zval * TSRMLS_DC); +static int mmc_incr_decr(mmc_t *, int, char *, int, int, long * TSRMLS_DC); +static void php_mmc_incr_decr(INTERNAL_FUNCTION_PARAMETERS, int); +static void php_mmc_connect(INTERNAL_FUNCTION_PARAMETERS, int); +/* }}} */ + +/* {{{ hash strategies */ +extern mmc_hash_t mmc_standard_hash; +extern mmc_hash_t mmc_consistent_hash; +/* }}} */ + +/* {{{ php_memcache_init_globals() +*/ +static void php_memcache_init_globals(zend_memcache_globals *memcache_globals_p TSRMLS_DC) +{ + MEMCACHE_G(debug_mode) = 0; + MEMCACHE_G(num_persistent) = 0; + MEMCACHE_G(compression_level) = Z_DEFAULT_COMPRESSION; + MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH; + MEMCACHE_G(hash_function) = MMC_HASH_CRC32; + MEMCACHE_G(default_timeout_ms)= (MMC_DEFAULT_TIMEOUT) * 1000; +} +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(memcache) +{ + zend_class_entry memcache_class_entry; + INIT_CLASS_ENTRY(memcache_class_entry, "Memcache", php_memcache_class_functions); + memcache_class_entry_ptr = zend_register_internal_class(&memcache_class_entry TSRMLS_CC); + + le_memcache_pool = zend_register_list_destructors_ex(_mmc_pool_list_dtor, NULL, "memcache connection", module_number); + le_pmemcache = zend_register_list_destructors_ex(NULL, _mmc_pserver_list_dtor, "persistent memcache connection", module_number); + +#ifdef ZTS + ts_allocate_id(&memcache_globals_id, sizeof(zend_memcache_globals), (ts_allocate_ctor) php_memcache_init_globals, NULL); +#else + php_memcache_init_globals(&memcache_globals TSRMLS_CC); +#endif + + REGISTER_LONG_CONSTANT("MEMCACHE_COMPRESSED", MMC_COMPRESSED, CONST_CS | CONST_PERSISTENT); + REGISTER_INI_ENTRIES(); + +#if HAVE_MEMCACHE_SESSION + REGISTER_LONG_CONSTANT("MEMCACHE_HAVE_SESSION", 1, CONST_CS | CONST_PERSISTENT); + php_session_register_module(ps_memcache_ptr); +#else + REGISTER_LONG_CONSTANT("MEMCACHE_HAVE_SESSION", 0, CONST_CS | CONST_PERSISTENT); +#endif + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION + */ +PHP_MSHUTDOWN_FUNCTION(memcache) +{ + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RINIT_FUNCTION + */ +PHP_RINIT_FUNCTION(memcache) +{ + MEMCACHE_G(debug_mode) = 0; + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION + */ +PHP_MINFO_FUNCTION(memcache) +{ + char buf[MAX_LENGTH_OF_LONG + 1]; + + sprintf(buf, "%ld", MEMCACHE_G(num_persistent)); + + php_info_print_table_start(); + php_info_print_table_header(2, "memcache support", "enabled"); + php_info_print_table_row(2, "Active persistent connections", buf); + php_info_print_table_row(2, "Version", PHP_MEMCACHE_VERSION); + php_info_print_table_row(2, "Revision", "$Revision: 327750 $"); + php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); +} +/* }}} */ + +/* ------------------ + internal functions + ------------------ */ + +#if ZEND_DEBUG +void mmc_debug(const char *format, ...) /* {{{ */ +{ + TSRMLS_FETCH(); + + if (MEMCACHE_G(debug_mode)) { + char buffer[1024]; + va_list args; + + va_start(args, format); + vsnprintf(buffer, sizeof(buffer)-1, format, args); + va_end(args); + buffer[sizeof(buffer)-1] = '\0'; + php_printf("%s<br />\n", buffer); + } +} +/* }}} */ +#endif + +static struct timeval _convert_timeoutms_to_ts(long msecs) /* {{{ */ +{ + struct timeval tv; + int secs = 0; + + secs = msecs / 1000; + tv.tv_sec = secs; + tv.tv_usec = ((msecs - (secs * 1000)) * 1000) % 1000000; + return tv; +} +/* }}} */ + +static void _mmc_pool_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + mmc_pool_free((mmc_pool_t *)rsrc->ptr TSRMLS_CC); +} +/* }}} */ + +static void _mmc_pserver_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + mmc_server_free((mmc_t *)rsrc->ptr TSRMLS_CC); +} +/* }}} */ + +mmc_t *mmc_server_new(char *host, int host_len, unsigned short port, int persistent, int timeout, int retry_interval TSRMLS_DC) /* {{{ */ +{ + mmc_t *mmc = pemalloc(sizeof(mmc_t), persistent); + memset(mmc, 0, sizeof(*mmc)); + + mmc->host = pemalloc(host_len + 1, persistent); + memcpy(mmc->host, host, host_len); + mmc->host[host_len] = '\0'; + + mmc->port = port; + mmc->status = MMC_STATUS_DISCONNECTED; + + mmc->persistent = persistent; + if (persistent) { + MEMCACHE_G(num_persistent)++; + } + + mmc->timeout = timeout; + mmc->retry_interval = retry_interval; + + return mmc; +} +/* }}} */ + +static void mmc_server_callback_dtor(zval **callback TSRMLS_DC) /* {{{ */ +{ + zval **this_obj; + + if (!callback || !*callback) return; + + if (Z_TYPE_PP(callback) == IS_ARRAY && + zend_hash_index_find(Z_ARRVAL_PP(callback), 0, (void **)&this_obj) == SUCCESS && + Z_TYPE_PP(this_obj) == IS_OBJECT) { + zval_ptr_dtor(this_obj); + } + zval_ptr_dtor(callback); +} +/* }}} */ + +static void mmc_server_callback_ctor(zval **callback TSRMLS_DC) /* {{{ */ +{ + zval **this_obj; + + if (!callback || !*callback) return; + + if (Z_TYPE_PP(callback) == IS_ARRAY && + zend_hash_index_find(Z_ARRVAL_PP(callback), 0, (void **)&this_obj) == SUCCESS && + Z_TYPE_PP(this_obj) == IS_OBJECT) { + zval_add_ref(this_obj); + } + zval_add_ref(callback); +} +/* }}} */ + +static void mmc_server_sleep(mmc_t *mmc TSRMLS_DC) /* + prepare server struct for persistent sleep {{{ */ +{ + mmc_server_callback_dtor(&mmc->failure_callback TSRMLS_CC); + mmc->failure_callback = NULL; + + if (mmc->error != NULL) { + pefree(mmc->error, mmc->persistent); + mmc->error = NULL; + } +} +/* }}} */ + +static void mmc_server_free(mmc_t *mmc TSRMLS_DC) /* {{{ */ +{ + if (mmc->in_free) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Recursive reference detected, bailing out"); + return; + } + mmc->in_free = 1; + + mmc_server_sleep(mmc TSRMLS_CC); + + if (mmc->persistent) { + free(mmc->host); + free(mmc); + MEMCACHE_G(num_persistent)--; + } + else { + if (mmc->stream != NULL) { + php_stream_close(mmc->stream); + } + efree(mmc->host); + efree(mmc); + } +} +/* }}} */ + +static void mmc_server_seterror(mmc_t *mmc, const char *error, int errnum) /* {{{ */ +{ + if (error != NULL) { + if (mmc->error != NULL) { + pefree(mmc->error, mmc->persistent); + } + + mmc->error = pestrdup(error, mmc->persistent); + mmc->errnum = errnum; + } +} +/* }}} */ + +static void mmc_server_received_error(mmc_t *mmc, int response_len) /* {{{ */ +{ + if (mmc_str_left(mmc->inbuf, "ERROR", response_len, sizeof("ERROR") - 1) || + mmc_str_left(mmc->inbuf, "CLIENT_ERROR", response_len, sizeof("CLIENT_ERROR") - 1) || + mmc_str_left(mmc->inbuf, "SERVER_ERROR", response_len, sizeof("SERVER_ERROR") - 1)) + { + mmc->inbuf[response_len < MMC_BUF_SIZE - 1 ? response_len : MMC_BUF_SIZE - 1] = '\0'; + mmc_server_seterror(mmc, mmc->inbuf, 0); + } + else { + mmc_server_seterror(mmc, "Received malformed response", 0); + } +} +/* }}} */ + +int mmc_server_failure(mmc_t *mmc TSRMLS_DC) /*determines if a request should be retried or is a hard network failure {{{ */ +{ + switch (mmc->status) { + case MMC_STATUS_DISCONNECTED: + return 0; + + /* attempt reconnect of sockets in unknown state */ + case MMC_STATUS_UNKNOWN: + mmc->status = MMC_STATUS_DISCONNECTED; + return 0; + } + + mmc_server_deactivate(mmc TSRMLS_CC); + return 1; +} +/* }}} */ + +static int mmc_server_store(mmc_t *mmc, const char *request, int request_len TSRMLS_DC) /* {{{ */ +{ + int response_len; + php_netstream_data_t *sock = (php_netstream_data_t*)mmc->stream->abstract; + + if (mmc->timeoutms > 1) { + sock->timeout = _convert_timeoutms_to_ts(mmc->timeoutms); + } + + if (php_stream_write(mmc->stream, request, request_len) != request_len) { + mmc_server_seterror(mmc, "Failed sending command and value to stream", 0); + return -1; + } + + if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { + return -1; + } + + if(mmc_str_left(mmc->inbuf, "STORED", response_len, sizeof("STORED") - 1)) { + return 1; + } + + /* return FALSE */ + if(mmc_str_left(mmc->inbuf, "NOT_STORED", response_len, sizeof("NOT_STORED") - 1)) { + return 0; + } + + /* return FALSE without failover */ + if (mmc_str_left(mmc->inbuf, "SERVER_ERROR out of memory", response_len, sizeof("SERVER_ERROR out of memory") - 1) || + mmc_str_left(mmc->inbuf, "SERVER_ERROR object too large", response_len, sizeof("SERVER_ERROR object too large")-1)) { + return 0; + } + + mmc_server_received_error(mmc, response_len); + return -1; +} +/* }}} */ + +int mmc_prepare_key_ex(const char *key, unsigned int key_len, char *result, unsigned int *result_len TSRMLS_DC) /* {{{ */ +{ + unsigned int i; + if (key_len == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key cannot be empty"); + return MMC_REQUEST_FAILURE; + } + + *result_len = key_len < MMC_KEY_MAX_SIZE ? key_len : MMC_KEY_MAX_SIZE; + result[*result_len] = '\0'; + + for (i=0; i<*result_len; i++) { + result[i] = ((unsigned char)key[i]) > ' ' ? key[i] : '_'; + } + + return MMC_OK; +} +/* }}} */ + +int mmc_prepare_key(zval *key, char *result, unsigned int *result_len TSRMLS_DC) /* {{{ */ +{ + if (Z_TYPE_P(key) == IS_STRING) { + return mmc_prepare_key_ex(Z_STRVAL_P(key), Z_STRLEN_P(key), result, result_len TSRMLS_CC); + } else { + int res; + zval *keytmp; + ALLOC_ZVAL(keytmp); + + *keytmp = *key; + zval_copy_ctor(keytmp); + convert_to_string(keytmp); + + res = mmc_prepare_key_ex(Z_STRVAL_P(keytmp), Z_STRLEN_P(keytmp), result, result_len TSRMLS_CC); + + zval_dtor(keytmp); + FREE_ZVAL(keytmp); + + return res; + } +} +/* }}} */ + +static unsigned int mmc_hash_crc32(const char *key, int key_len) /* CRC32 hash {{{ */ +{ + unsigned int crc = ~0; + int i; + + for (i=0; i<key_len; i++) { + CRC32(crc, key[i]); + } + + return ~crc; +} +/* }}} */ + +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 void mmc_pool_init_hash(mmc_pool_t *pool TSRMLS_DC) /* {{{ */ +{ + mmc_hash_function hash; + + switch (MEMCACHE_G(hash_strategy)) { + case MMC_CONSISTENT_HASH: + pool->hash = &mmc_consistent_hash; + break; + 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(hash); +} +/* }}} */ + +mmc_pool_t *mmc_pool_new(TSRMLS_D) /* {{{ */ +{ + mmc_pool_t *pool = emalloc(sizeof(mmc_pool_t)); + pool->num_servers = 0; + pool->compress_threshold = 0; + pool->in_free = 0; + pool->min_compress_savings = MMC_DEFAULT_SAVINGS; + + mmc_pool_init_hash(pool TSRMLS_CC); + + return pool; +} +/* }}} */ + +void mmc_pool_free(mmc_pool_t *pool TSRMLS_DC) /* {{{ */ +{ + int i; + + if (pool->in_free) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Recursive reference detected, bailing out"); + return; + } + pool->in_free = 1; + + for (i=0; i<pool->num_servers; i++) { + if (!pool->servers[i]) { + continue; + } + if (pool->servers[i]->persistent == 0 && pool->servers[i]->host != NULL) { + mmc_server_free(pool->servers[i] TSRMLS_CC); + } else { + mmc_server_sleep(pool->servers[i] TSRMLS_CC); + } + pool->servers[i] = NULL; + } + + if (pool->num_servers) { + efree(pool->servers); + efree(pool->requests); + } + + pool->hash->free_state(pool->hash_state); + efree(pool); +} +/* }}} */ + +void mmc_pool_add(mmc_pool_t *pool, mmc_t *mmc, unsigned int weight) /* {{{ */ +{ + /* add server and a preallocated request pointer */ + if (pool->num_servers) { + pool->servers = erealloc(pool->servers, sizeof(mmc_t *) * (pool->num_servers + 1)); + pool->requests = erealloc(pool->requests, sizeof(mmc_t *) * (pool->num_servers + 1)); + } + else { + pool->servers = emalloc(sizeof(mmc_t *)); + pool->requests = emalloc(sizeof(mmc_t *)); + } + + pool->servers[pool->num_servers] = mmc; + pool->num_servers++; + + pool->hash->add_server(pool->hash_state, mmc, weight); +} +/* }}} */ + +static int mmc_pool_close(mmc_pool_t *pool TSRMLS_DC) /* disconnects and removes all servers in the pool {{{ */ +{ + if (pool->num_servers) { + int i; + + for (i=0; i<pool->num_servers; i++) { + if (pool->servers[i]->persistent == 0 && pool->servers[i]->host != NULL) { + mmc_server_free(pool->servers[i] TSRMLS_CC); + } else { + mmc_server_sleep(pool->servers[i] TSRMLS_CC); + } + } + + efree(pool->servers); + pool->servers = NULL; + pool->num_servers = 0; + + efree(pool->requests); + pool->requests = NULL; + + /* reallocate the hash strategy state */ + pool->hash->free_state(pool->hash_state); + mmc_pool_init_hash(pool TSRMLS_CC); + } + + return 1; +} +/* }}} */ + +int mmc_pool_store(mmc_pool_t *pool, const char *command, int command_len, const char *key, int key_len, int flags, int expire, const char *value, int value_len TSRMLS_DC) /* {{{ */ +{ + mmc_t *mmc; + char *request; + int request_len, result = -1; + char *key_copy = NULL, *data = NULL; + + if (key_len > MMC_KEY_MAX_SIZE) { + key = key_copy = estrndup(key, MMC_KEY_MAX_SIZE); + key_len = MMC_KEY_MAX_SIZE; + } + + /* autocompress large values */ + if (pool->compress_threshold && value_len >= pool->compress_threshold) { + flags |= MMC_COMPRESSED; + } + + if (flags & MMC_COMPRESSED) { + unsigned long data_len; + + if (!mmc_compress(&data, &data_len, value, value_len TSRMLS_CC)) { + /* mmc_server_seterror(mmc, "Failed to compress data", 0); */ + return -1; + } + + /* was enough space saved to motivate uncompress processing on get */ + if (data_len < value_len * (1 - pool->min_compress_savings)) { + value = data; + value_len = data_len; + } + else { + flags &= ~MMC_COMPRESSED; + efree(data); + data = NULL; + } + } + + request = emalloc( + command_len + + 1 /* space */ + + key_len + + 1 /* space */ + + MAX_LENGTH_OF_LONG + + 1 /* space */ + + MAX_LENGTH_OF_LONG + + 1 /* space */ + + MAX_LENGTH_OF_LONG + + sizeof("\r\n") - 1 + + value_len + + sizeof("\r\n") - 1 + + 1 + ); + + request_len = sprintf(request, "%s %s %d %d %d\r\n", command, key, flags, expire, value_len); + + memcpy(request + request_len, value, value_len); + request_len += value_len; + + memcpy(request + request_len, "\r\n", sizeof("\r\n") - 1); + request_len += sizeof("\r\n") - 1; + + request[request_len] = '\0'; + + while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { + if ((result = mmc_server_store(mmc, request, request_len TSRMLS_CC)) < 0) { + mmc_server_failure(mmc TSRMLS_CC); + } + } + + if (key_copy != NULL) { + efree(key_copy); + } + + if (data != NULL) { + efree(data); + } + + efree(request); + + return result; +} +/* }}} */ + +static int mmc_compress(char **result, unsigned long *result_len, const char *data, int data_len TSRMLS_DC) /* {{{ */ +{ + int status, level = MEMCACHE_G(compression_level); + + *result_len = data_len + (data_len / 1000) + 25 + 1; /* some magic from zlib.c */ + *result = (char *) emalloc(*result_len); + + if (!*result) { + return 0; + } + + if (level >= 0) { + status = compress2((unsigned char *) *result, result_len, (unsigned const char *) data, data_len, level); + } else { + status = compress((unsigned char *) *result, result_len, (unsigned const char *) data, data_len); + } + + if (status == Z_OK) { + *result = erealloc(*result, *result_len + 1); + (*result)[*result_len] = '\0'; + return 1; + } + + switch (status) { + case Z_MEM_ERROR: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough memory to perform compression"); + break; + case Z_BUF_ERROR: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough room in the output buffer to perform compression"); + break; + case Z_STREAM_ERROR: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level"); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error during compression"); + break; + } + + efree(*result); + return 0; +} +/* }}}*/ + +static int mmc_uncompress(char **result, unsigned long *result_len, const char *data, int data_len) /* {{{ */ +{ + int status; + unsigned int factor = 1, maxfactor = 16; + char *tmp1 = NULL; + + do { + *result_len = (unsigned long)data_len * (1 << factor++); + *result = (char *) erealloc(tmp1, *result_len); + status = uncompress((unsigned char *) *result, result_len, (unsigned const char *) data, data_len); + tmp1 = *result; + } while (status == Z_BUF_ERROR && factor < maxfactor); + + if (status == Z_OK) { + *result = erealloc(*result, *result_len + 1); + (*result)[*result_len] = '\0'; + return 1; + } + + efree(*result); + return 0; +} +/* }}}*/ + +static int mmc_get_pool(zval *id, mmc_pool_t **pool TSRMLS_DC) /* {{{ */ +{ + zval **connection; + int resource_type; + + if (Z_TYPE_P(id) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(id), "connection", sizeof("connection"), (void **) &connection) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No servers added to memcache connection"); + return 0; + } + + *pool = (mmc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type); + + if (!*pool || resource_type != le_memcache_pool) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Memcache->connection member variable"); + return 0; + } + + return Z_LVAL_PP(connection); +} +/* }}} */ + +static int _mmc_open(mmc_t *mmc, char **error_string, int *errnum TSRMLS_DC) /* {{{ */ +{ + struct timeval tv; + char *hostname = NULL, *hash_key = NULL, *errstr = NULL; + int hostname_len, err = 0; + + /* close open stream */ + if (mmc->stream != NULL) { + mmc_server_disconnect(mmc TSRMLS_CC); + } + + if (mmc->connect_timeoutms > 0) { + tv = _convert_timeoutms_to_ts(mmc->connect_timeoutms); + } else { + tv.tv_sec = mmc->timeout; + tv.tv_usec = 0; + } + + if (mmc->port) { + hostname_len = spprintf(&hostname, 0, "%s:%d", mmc->host, mmc->port); + } + else { + hostname_len = spprintf(&hostname, 0, "%s", mmc->host); + } + + if (mmc->persistent) { + spprintf(&hash_key, 0, "memcache:%s", hostname); + } + +#if PHP_API_VERSION > 20020918 + mmc->stream = php_stream_xport_create( hostname, hostname_len, + ENFORCE_SAFE_MODE | REPORT_ERRORS, + STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, + hash_key, &tv, NULL, &errstr, &err); +#else + if (mmc->persistent) { + switch(php_stream_from_persistent_id(hash_key, &(mmc->stream) TSRMLS_CC)) { + case PHP_STREAM_PERSISTENT_SUCCESS: + if (php_stream_eof(mmc->stream)) { + php_stream_pclose(mmc->stream); + mmc->stream = NULL; + break; + } + case PHP_STREAM_PERSISTENT_FAILURE: + break; + } + } + + if (!mmc->stream) { + int socktype = SOCK_STREAM; + mmc->stream = php_stream_sock_open_host(mmc->host, mmc->port, socktype, &tv, hash_key); + } + +#endif + + efree(hostname); + if (mmc->persistent) { + efree(hash_key); + } + + if (!mmc->stream) { + MMC_DEBUG(("_mmc_open: can't open socket to host")); + mmc_server_seterror(mmc, errstr != NULL ? errstr : "Connection failed", err); + mmc_server_deactivate(mmc TSRMLS_CC); + + if (errstr) { + if (error_string) { + *error_string = errstr; + } + else { + efree(errstr); + } + } + if (errnum) { + *errnum = err; + } + + return 0; + } + + php_stream_auto_cleanup(mmc->stream); + php_stream_set_option(mmc->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv); + php_stream_set_option(mmc->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL); + php_stream_set_chunk_size(mmc->stream, MEMCACHE_G(chunk_size)); + + mmc->status = MMC_STATUS_CONNECTED; + + if (mmc->error != NULL) { + pefree(mmc->error, mmc->persistent); + mmc->error = NULL; + } + + return 1; +} +/* }}} */ + +int mmc_open(mmc_t *mmc, int force_connect, char **error_string, int *errnum TSRMLS_DC) /* {{{ */ +{ + switch (mmc->status) { + case MMC_STATUS_DISCONNECTED: + return _mmc_open(mmc, error_string, errnum TSRMLS_CC); + + case MMC_STATUS_CONNECTED: + return 1; + + case MMC_STATUS_UNKNOWN: + /* check connection if needed */ + if (force_connect) { + char *version; + if ((version = mmc_get_version(mmc TSRMLS_CC)) == NULL && !_mmc_open(mmc, error_string, errnum TSRMLS_CC)) { + break; + } + if (version) { + efree(version); + } + mmc->status = MMC_STATUS_CONNECTED; + } + return 1; + + case MMC_STATUS_FAILED: + if (mmc->retry_interval >= 0 && (long)time(NULL) >= mmc->failed + mmc->retry_interval) { + if (_mmc_open(mmc, error_string, errnum TSRMLS_CC) /*&& mmc_flush(mmc, 0 TSRMLS_CC) > 0*/) { + return 1; + } + } + break; + } + return 0; +} +/* }}} */ + +static void mmc_server_disconnect(mmc_t *mmc TSRMLS_DC) /* {{{ */ +{ + if (mmc->stream != NULL) { + if (mmc->persistent) { + php_stream_pclose(mmc->stream); + } + else { + php_stream_close(mmc->stream); + } + mmc->stream = NULL; + } + mmc->status = MMC_STATUS_DISCONNECTED; +} +/* }}} */ + +void mmc_server_deactivate(mmc_t *mmc TSRMLS_DC) /* disconnect and marks the server as down {{{ */ +{ + mmc_server_disconnect(mmc TSRMLS_CC); + mmc->status = MMC_STATUS_FAILED; + mmc->failed = (long)time(NULL); + + if (mmc->failure_callback != NULL) { + zval *retval = NULL; + zval *host, *tcp_port, *udp_port, *error, *errnum; + zval **params[5]; + + params[0] = &host; + params[1] = &tcp_port; + params[2] = &udp_port; + params[3] = &error; + params[4] = &errnum; + + MAKE_STD_ZVAL(host); + MAKE_STD_ZVAL(tcp_port); MAKE_STD_ZVAL(udp_port); + MAKE_STD_ZVAL(error); MAKE_STD_ZVAL(errnum); + + ZVAL_STRING(host, mmc->host, 1); + ZVAL_LONG(tcp_port, mmc->port); ZVAL_LONG(udp_port, 0); + + if (mmc->error != NULL) { + ZVAL_STRING(error, mmc->error, 1); + } + else { + ZVAL_NULL(error); + } + ZVAL_LONG(errnum, mmc->errnum); + + call_user_function_ex(EG(function_table), NULL, mmc->failure_callback, &retval, 5, params, 0, NULL TSRMLS_CC); + + zval_ptr_dtor(&host); + zval_ptr_dtor(&tcp_port); zval_ptr_dtor(&udp_port); + zval_ptr_dtor(&error); zval_ptr_dtor(&errnum); + + if (retval != NULL) { + zval_ptr_dtor(&retval); + } + } + else { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d) failed with: %s (%d)", + mmc->host, mmc->port, mmc->error, mmc->errnum); + } +} +/* }}} */ + +static int mmc_readline(mmc_t *mmc TSRMLS_DC) /* {{{ */ +{ + char *response; + size_t response_len; + + if (mmc->stream == NULL) { + mmc_server_seterror(mmc, "Socket is closed", 0); + return -1; + } + + response = php_stream_get_line(mmc->stream, ZSTR(mmc->inbuf), MMC_BUF_SIZE, &response_len); + if (response) { + MMC_DEBUG(("mmc_readline: read data:")); + MMC_DEBUG(("mmc_readline:---")); + MMC_DEBUG(("%s", response)); + MMC_DEBUG(("mmc_readline:---")); + return response_len; + } + + mmc_server_seterror(mmc, "Failed reading line from stream", 0); + return -1; +} +/* }}} */ + +static char *mmc_get_version(mmc_t *mmc TSRMLS_DC) /* {{{ */ +{ + char *version_str; + int response_len; + + if (mmc_sendcmd(mmc, "version", sizeof("version") - 1 TSRMLS_CC) < 0) { + return NULL; + } + + if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { + return NULL; + } + + if (mmc_str_left(mmc->inbuf, "VERSION ", response_len, sizeof("VERSION ") - 1)) { + version_str = estrndup(mmc->inbuf + sizeof("VERSION ") - 1, response_len - (sizeof("VERSION ") - 1) - (sizeof("\r\n") - 1) ); + return version_str; + } + + mmc_server_seterror(mmc, "Malformed version string", 0); + return NULL; +} +/* }}} */ + +static int mmc_str_left(char *haystack, char *needle, int haystack_len, int needle_len) /* {{{ */ +{ + char *found; + + found = php_memnstr(haystack, needle, needle_len, haystack + haystack_len); + if ((found - haystack) == 0) { + return 1; + } + return 0; +} +/* }}} */ + +static int mmc_sendcmd(mmc_t *mmc, const char *cmd, int cmdlen TSRMLS_DC) /* {{{ */ +{ + char *command; + int command_len; + php_netstream_data_t *sock = (php_netstream_data_t*)mmc->stream->abstract; + + if (!mmc || !cmd) { + return -1; + } + + MMC_DEBUG(("mmc_sendcmd: sending command '%s'", cmd)); + + command = emalloc(cmdlen + sizeof("\r\n")); + memcpy(command, cmd, cmdlen); + memcpy(command + cmdlen, "\r\n", sizeof("\r\n") - 1); + command_len = cmdlen + sizeof("\r\n") - 1; + command[command_len] = '\0'; + + if (mmc->timeoutms > 1) { + sock->timeout = _convert_timeoutms_to_ts(mmc->timeoutms); + } + + if (php_stream_write(mmc->stream, command, command_len) != command_len) { + mmc_server_seterror(mmc, "Failed writing command to stream", 0); + efree(command); + return -1; + } + efree(command); + + return 1; +} +/* }}}*/ + +static int mmc_parse_response(mmc_t *mmc, char *response, int response_len, char **key, int *key_len, int *flags, int *value_len) /* {{{ */ +{ + int i=0, n=0; + int spaces[3]; + + if (!response || response_len <= 0) { + mmc_server_seterror(mmc, "Empty response", 0); + return -1; + } + + MMC_DEBUG(("mmc_parse_response: got response '%s'", response)); + + for (i=0, n=0; i < response_len && n < 3; i++) { + if (response[i] == ' ') { + spaces[n++] = i; + } + } + + MMC_DEBUG(("mmc_parse_response: found %d spaces", n)); + + if (n < 3) { + mmc_server_seterror(mmc, "Malformed VALUE header", 0); + return -1; + } + + if (key != NULL) { + int len = spaces[1] - spaces[0] - 1; + + *key = emalloc(len + 1); + *key_len = len; + + memcpy(*key, response + spaces[0] + 1, len); + (*key)[len] = '\0'; + } + + *flags = atoi(response + spaces[1]); + *value_len = atoi(response + spaces[2]); + + if (*flags < 0 || *value_len < 0) { + mmc_server_seterror(mmc, "Malformed VALUE header", 0); + return -1; + } + + MMC_DEBUG(("mmc_parse_response: 1st space is at %d position", spaces[1])); + MMC_DEBUG(("mmc_parse_response: 2nd space is at %d position", spaces[2])); + MMC_DEBUG(("mmc_parse_response: flags = %d", *flags)); + MMC_DEBUG(("mmc_parse_response: value_len = %d ", *value_len)); + + return 1; +} +/* }}} */ + +static int mmc_postprocess_value(zval **return_value, char *value, int value_len TSRMLS_DC) /* + post-process a value into a result zval struct, value will be free()'ed during process {{{ */ +{ + const char *value_tmp = value; + php_unserialize_data_t var_hash; + PHP_VAR_UNSERIALIZE_INIT(var_hash); + + if (!php_var_unserialize(return_value, (const unsigned char **)&value_tmp, (const unsigned char *)(value_tmp + value_len), &var_hash TSRMLS_CC)) { + ZVAL_FALSE(*return_value); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + efree(value); + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "unable to unserialize data"); + return 0; + } + + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + efree(value); + return 1; +} +/* }}} */ + +int mmc_exec_retrieval_cmd(mmc_pool_t *pool, const char *key, int key_len, zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */ +{ + mmc_t *mmc; + char *command, *value; + int result = -1, command_len, response_len, value_len, flags = 0; + + MMC_DEBUG(("mmc_exec_retrieval_cmd: key '%s'", key)); + + command_len = spprintf(&command, 0, "get %s", key); + + while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { + MMC_DEBUG(("mmc_exec_retrieval_cmd: found server '%s:%d' for key '%s'", mmc->host, mmc->port, key)); + + /* send command and read value */ + if ((result = mmc_sendcmd(mmc, command, command_len TSRMLS_CC)) > 0 && + (result = mmc_read_value(mmc, NULL, NULL, &value, &value_len, &flags TSRMLS_CC)) >= 0) { + + /* not found */ + if (result == 0) { + ZVAL_FALSE(*return_value); + } + /* read "END" */ + else if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0 || !mmc_str_left(mmc->inbuf, "END", response_len, sizeof("END")-1)) { + mmc_server_seterror(mmc, "Malformed END line", 0); + result = -1; + } + else if (flags & MMC_SERIALIZED ) { + result = mmc_postprocess_value(return_value, value, value_len TSRMLS_CC); + } + else { + ZVAL_STRINGL(*return_value, value, value_len, 0); + } + } + + if (result < 0) { + mmc_server_failure(mmc TSRMLS_CC); + } + } + + if (return_flags != NULL) { + zval_dtor(return_flags); + ZVAL_LONG(return_flags, flags); + } + + efree(command); + return result; +} +/* }}} */ + +static int mmc_exec_retrieval_cmd_multi(mmc_pool_t *pool, zval *keys, zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */ +{ + mmc_t *mmc; + HashPosition pos; + zval **zkey; + char *result_key, *value; + char key[MMC_KEY_MAX_SIZE]; + unsigned int key_len; + + int i = 0, j, num_requests, result, result_status, result_key_len, value_len, flags; + mmc_queue_t serialized = {0}; /* mmc_queue_t<zval *>, pointers to zvals which need unserializing */ + + array_init(*return_value); + + if (return_flags != NULL) { + zval_dtor(return_flags); + array_init(return_flags); + } + + /* until no retrival errors or all servers have failed */ + do { + result_status = num_requests = 0; + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos); + + /* first pass to build requests for each server */ + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&zkey, &pos) == SUCCESS) { + if (mmc_prepare_key(*zkey, key, &key_len TSRMLS_CC) == MMC_OK) { + /* schedule key if first round or if missing from result */ + if ((!i || !zend_hash_exists(Z_ARRVAL_PP(return_value), key, key_len)) && + (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { + if (!(mmc->outbuf.len)) { + smart_str_appendl(&(mmc->outbuf), "get", sizeof("get")-1); + pool->requests[num_requests++] = mmc; + } + + smart_str_appendl(&(mmc->outbuf), " ", 1); + smart_str_appendl(&(mmc->outbuf), key, key_len); + MMC_DEBUG(("mmc_exec_retrieval_cmd_multi: scheduled key '%s' for '%s:%d' request length '%d'", key, mmc->host, mmc->port, mmc->outbuf.len)); + } + } + + zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos); + } + + /* second pass to send requests in parallel */ + for (j=0; j<num_requests; j++) { + smart_str_0(&(pool->requests[j]->outbuf)); + + if ((result = mmc_sendcmd(pool->requests[j], pool->requests[j]->outbuf.c, pool->requests[j]->outbuf.len TSRMLS_CC)) < 0) { + mmc_server_failure(pool->requests[j] TSRMLS_CC); + result_status = result; + } + } + + /* third pass to read responses */ + for (j=0; j<num_requests; j++) { + if (pool->requests[j]->status != MMC_STATUS_FAILED) { + for (value = NULL; (result = mmc_read_value(pool->requests[j], &result_key, &result_key_len, &value, &value_len, &flags TSRMLS_CC)) > 0; value = NULL) { + if (flags & MMC_SERIALIZED) { + zval *result; + MAKE_STD_ZVAL(result); + ZVAL_STRINGL(result, value, value_len, 0); + + /* don't store duplicate values */ + if (zend_hash_add(Z_ARRVAL_PP(return_value), result_key, result_key_len + 1, &result, sizeof(result), NULL) == SUCCESS) { + mmc_queue_push(&serialized, result); + } + else { + zval_ptr_dtor(&result); + } + } + else { + add_assoc_stringl_ex(*return_value, result_key, result_key_len + 1, value, value_len, 0); + } + + if (return_flags != NULL) { + add_assoc_long_ex(return_flags, result_key, result_key_len + 1, flags); + } + + efree(result_key); + } + + /* check for server failure */ + if (result < 0) { + mmc_server_failure(pool->requests[j] TSRMLS_CC); + result_status = result; + } + } + + smart_str_free(&(pool->requests[j]->outbuf)); + } + } while (result_status < 0 && MEMCACHE_G(allow_failover) && i++ < MEMCACHE_G(max_failover_attempts)); + + /* post-process serialized values */ + if (serialized.len) { + zval *value; + + while ((value = (zval *)mmc_queue_pop(&serialized)) != NULL) { + mmc_postprocess_value(&value, Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC); + } + + mmc_queue_free(&serialized); + } + + return result_status; +} +/* }}} */ + +static int mmc_read_value(mmc_t *mmc, char **key, int *key_len, char **value, int *value_len, int *flags TSRMLS_DC) /* {{{ */ +{ + char *data; + int response_len, data_len, i, size; + + /* read "VALUE <key> <flags> <bytes>\r\n" header line */ + if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { + MMC_DEBUG(("failed to read the server's response")); + return -1; + } + + /* reached the end of the data */ + if (mmc_str_left(mmc->inbuf, "END", response_len, sizeof("END") - 1)) { + return 0; + } + + if (mmc_parse_response(mmc, mmc->inbuf, response_len, key, key_len, flags, &data_len) < 0) { + return -1; + } + + MMC_DEBUG(("mmc_read_value: data len is %d bytes", data_len)); + + /* data_len + \r\n + \0 */ + data = emalloc(data_len + 3); + + for (i=0; i<data_len+2; i+=size) { + if ((size = php_stream_read(mmc->stream, data + i, data_len + 2 - i)) == 0) { + mmc_server_seterror(mmc, "Failed reading value response body", 0); + if (key) { + efree(*key); + } + efree(data); + return -1; + } + } + + data[data_len] = '\0'; + + if ((*flags & MMC_COMPRESSED) && data_len > 0) { + char *result_data; + unsigned long result_len = 0; + + if (!mmc_uncompress(&result_data, &result_len, data, data_len)) { + mmc_server_seterror(mmc, "Failed to uncompress data", 0); + if (key) { + efree(*key); + } + efree(data); + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "unable to uncompress data"); + return 0; + } + + efree(data); + data = result_data; + data_len = result_len; + } + + *value = data; + *value_len = data_len; + return 1; +} +/* }}} */ + +int mmc_delete(mmc_t *mmc, const char *key, int key_len, int time TSRMLS_DC) /* {{{ */ +{ + char *command; + int command_len, response_len; + + command_len = spprintf(&command, 0, "delete %s %d", key, time); + + MMC_DEBUG(("mmc_delete: trying to delete '%s'", key)); + + if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { + efree(command); + return -1; + } + efree(command); + + if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0){ + MMC_DEBUG(("failed to read the server's response")); + return -1; + } + + MMC_DEBUG(("mmc_delete: server's response is '%s'", mmc->inbuf)); + + if(mmc_str_left(mmc->inbuf,"DELETED", response_len, sizeof("DELETED") - 1)) { + return 1; + } + + if(mmc_str_left(mmc->inbuf,"NOT_FOUND", response_len, sizeof("NOT_FOUND") - 1)) { + return 0; + } + + mmc_server_received_error(mmc, response_len); + return -1; +} +/* }}} */ + +static int mmc_flush(mmc_t *mmc, int timestamp TSRMLS_DC) /* {{{ */ +{ + char *command; + int command_len, response_len; + + MMC_DEBUG(("mmc_flush: flushing the cache")); + + if (timestamp) { + command_len = spprintf(&command, 0, "flush_all %d", timestamp); + } + else { + command_len = spprintf(&command, 0, "flush_all"); + } + + if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { + efree(command); + return -1; + } + efree(command); + + /* get server's response */ + if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0){ + return -1; + } + + MMC_DEBUG(("mmc_flush: server's response is '%s'", mmc->inbuf)); + + if(mmc_str_left(mmc->inbuf, "OK", response_len, sizeof("OK") - 1)) { + return 1; + } + + mmc_server_received_error(mmc, response_len); + return -1; +} +/* }}} */ + +/* + * STAT 6:chunk_size 64 + */ +static int mmc_stats_parse_stat(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */ +{ + char *space, *colon, *key; + long index = 0; + + /* find space delimiting key and value */ + if ((space = php_memnstr(start, " ", 1, end)) == NULL) { + return 0; + } + + /* find colon delimiting subkeys */ + if ((colon = php_memnstr(start, ":", 1, space - 1)) != NULL) { + zval *element, **elem; + key = estrndup(start, colon - start); + + /* find existing or create subkey array in result */ + if ((is_numeric_string(key, colon - start, &index, NULL, 0) && + zend_hash_index_find(Z_ARRVAL_P(result), index, (void **) &elem) != FAILURE) || + zend_hash_find(Z_ARRVAL_P(result), key, colon - start + 1, (void **) &elem) != FAILURE) { + element = *elem; + } + else { + MAKE_STD_ZVAL(element); + array_init(element); + add_assoc_zval_ex(result, key, colon - start + 1, element); + } + + efree(key); + return mmc_stats_parse_stat(colon + 1, end, element TSRMLS_CC); + } + + /* no more subkeys, add value under last subkey */ + key = estrndup(start, space - start); + add_assoc_stringl_ex(result, key, space - start + 1, space + 1, end - space, 1); + efree(key); + + return 1; +} +/* }}} */ + +/* + * ITEM test_key [3 b; 1157099416 s] + */ +static int mmc_stats_parse_item(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */ +{ + char *space, *value, *value_end, *key; + zval *element; + + /* find space delimiting key and value */ + if ((space = php_memnstr(start, " ", 1, end)) == NULL) { + return 0; + } + + MAKE_STD_ZVAL(element); + array_init(element); + + /* parse each contained value */ + for (value = php_memnstr(space, "[", 1, end); value != NULL && value <= end; value = php_memnstr(value + 1, ";", 1, end)) { + do { + value++; + } while (*value == ' ' && value <= end); + + if (value <= end && (value_end = php_memnstr(value, " ", 1, end)) != NULL && value_end <= end) { + add_next_index_stringl(element, value, value_end - value, 1); + } + } + + /* add parsed values under key */ + key = estrndup(start, space - start); + add_assoc_zval_ex(result, key, space - start + 1, element); + efree(key); + + return 1; +} +/* }}} */ + +static int mmc_stats_parse_generic(char *start, char *end, zval *result TSRMLS_DC) /* {{{ */ +{ + char *space, *key; + + /* "stats maps" returns "\n" delimited lines, other commands uses "\r\n" */ + if (*end == '\r') { + end--; + } + + if (start <= end) { + if ((space = php_memnstr(start, " ", 1, end)) != NULL) { + key = estrndup(start, space - start); + add_assoc_stringl_ex(result, key, space - start + 1, space + 1, end - space, 1); + efree(key); + } + else { + add_next_index_stringl(result, start, end - start, 1); + } + } + + return 1; +} +/* }}} */ + +static int mmc_get_stats(mmc_t *mmc, char *type, int slabid, int limit, zval *result TSRMLS_DC) /* {{{ */ +{ + char *command; + int command_len, response_len; + + if (slabid) { + command_len = spprintf(&command, 0, "stats %s %d %d", type, slabid, limit); + } + else if (type) { + command_len = spprintf(&command, 0, "stats %s", type); + } + else { + command_len = spprintf(&command, 0, "stats"); + } + + if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { + efree(command); + return -1; + } + + efree(command); + array_init(result); + + while ((response_len = mmc_readline(mmc TSRMLS_CC)) >= 0) { + if (mmc_str_left(mmc->inbuf, "ERROR", response_len, sizeof("ERROR") - 1) || + mmc_str_left(mmc->inbuf, "CLIENT_ERROR", response_len, sizeof("CLIENT_ERROR") - 1) || + mmc_str_left(mmc->inbuf, "SERVER_ERROR", response_len, sizeof("SERVER_ERROR") - 1)) { + + zend_hash_destroy(Z_ARRVAL_P(result)); + FREE_HASHTABLE(Z_ARRVAL_P(result)); + + ZVAL_FALSE(result); + return 0; + } + else if (mmc_str_left(mmc->inbuf, "RESET", response_len, sizeof("RESET") - 1)) { + zend_hash_destroy(Z_ARRVAL_P(result)); + FREE_HASHTABLE(Z_ARRVAL_P(result)); + + ZVAL_TRUE(result); + return 1; + } + else if (mmc_str_left(mmc->inbuf, "ITEM ", response_len, sizeof("ITEM ") - 1)) { + if (!mmc_stats_parse_item(mmc->inbuf + (sizeof("ITEM ") - 1), mmc->inbuf + response_len - sizeof("\r\n"), result TSRMLS_CC)) { + zend_hash_destroy(Z_ARRVAL_P(result)); + FREE_HASHTABLE(Z_ARRVAL_P(result)); + return -1; + } + } + else if (mmc_str_left(mmc->inbuf, "STAT ", response_len, sizeof("STAT ") - 1)) { + if (!mmc_stats_parse_stat(mmc->inbuf + (sizeof("STAT ") - 1), mmc->inbuf + response_len - sizeof("\r\n"), result TSRMLS_CC)) { + zend_hash_destroy(Z_ARRVAL_P(result)); + FREE_HASHTABLE(Z_ARRVAL_P(result)); + return -1; + } + } + else if (mmc_str_left(mmc->inbuf, "END", response_len, sizeof("END") - 1)) { + break; + } + else if (!mmc_stats_parse_generic(mmc->inbuf, mmc->inbuf + response_len - sizeof("\n"), result TSRMLS_CC)) { + zend_hash_destroy(Z_ARRVAL_P(result)); + FREE_HASHTABLE(Z_ARRVAL_P(result)); + return -1; + } + } + + if (response_len < 0) { + zend_hash_destroy(Z_ARRVAL_P(result)); + FREE_HASHTABLE(Z_ARRVAL_P(result)); + return -1; + } + + return 1; +} +/* }}} */ + +static int mmc_incr_decr(mmc_t *mmc, int cmd, char *key, int key_len, int value, long *number TSRMLS_DC) /* {{{ */ +{ + char *command; + int command_len, response_len; + + if (cmd > 0) { + command_len = spprintf(&command, 0, "incr %s %d", key, value); + } + else { + command_len = spprintf(&command, 0, "decr %s %d", key, value); + } + + if (mmc_sendcmd(mmc, command, command_len TSRMLS_CC) < 0) { + efree(command); + return -1; + } + efree(command); + + if ((response_len = mmc_readline(mmc TSRMLS_CC)) < 0) { + MMC_DEBUG(("failed to read the server's response")); + return -1; + } + + MMC_DEBUG(("mmc_incr_decr: server's answer is: '%s'", mmc->inbuf)); + if (mmc_str_left(mmc->inbuf, "NOT_FOUND", response_len, sizeof("NOT_FOUND") - 1)) { + MMC_DEBUG(("failed to %sement variable - item with such key not found", cmd > 0 ? "incr" : "decr")); + return 0; + } + else if (mmc_str_left(mmc->inbuf, "ERROR", response_len, sizeof("ERROR") - 1) || + mmc_str_left(mmc->inbuf, "CLIENT_ERROR", response_len, sizeof("CLIENT_ERROR") - 1) || + mmc_str_left(mmc->inbuf, "SERVER_ERROR", response_len, sizeof("SERVER_ERROR") - 1)) { + mmc_server_received_error(mmc, response_len); + return -1; + } + + *number = (long)atol(mmc->inbuf); + return 1; +} +/* }}} */ + +static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, char *command, int command_len) /* {{{ */ +{ + mmc_pool_t *pool; + zval *value, *mmc_object = getThis(); + + int result, key_len; + char *key; + long flags = 0, expire = 0; + char key_tmp[MMC_KEY_MAX_SIZE]; + unsigned int key_tmp_len; + + php_serialize_data_t value_hash; + smart_str buf = {0}; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osz|ll", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &value, &flags, &expire) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|ll", &key, &key_len, &value, &flags, &expire) == FAILURE) { + return; + } + } + + if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { + RETURN_FALSE; + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { + RETURN_FALSE; + } + + switch (Z_TYPE_P(value)) { + case IS_STRING: + result = mmc_pool_store( + pool, command, command_len, key_tmp, key_tmp_len, flags, expire, + Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC); + break; + + case IS_LONG: + case IS_DOUBLE: + case IS_BOOL: { + zval value_copy; + + /* FIXME: we should be using 'Z' instead of this, but unfortunately it's PHP5-only */ + value_copy = *value; + zval_copy_ctor(&value_copy); + convert_to_string(&value_copy); + + result = mmc_pool_store( + pool, command, command_len, key_tmp, key_tmp_len, flags, expire, + Z_STRVAL(value_copy), Z_STRLEN(value_copy) TSRMLS_CC); + + zval_dtor(&value_copy); + break; + } + + default: { + zval value_copy, *value_copy_ptr; + + /* FIXME: we should be using 'Z' instead of this, but unfortunately it's PHP5-only */ + value_copy = *value; + zval_copy_ctor(&value_copy); + value_copy_ptr = &value_copy; + + PHP_VAR_SERIALIZE_INIT(value_hash); + php_var_serialize(&buf, &value_copy_ptr, &value_hash TSRMLS_CC); + PHP_VAR_SERIALIZE_DESTROY(value_hash); + + if (!buf.c) { + /* something went really wrong */ + zval_dtor(&value_copy); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to serialize value"); + RETURN_FALSE; + } + + flags |= MMC_SERIALIZED; + zval_dtor(&value_copy); + + result = mmc_pool_store( + pool, command, command_len, key_tmp, key_tmp_len, flags, expire, + buf.c, buf.len TSRMLS_CC); + } + } + + if (flags & MMC_SERIALIZED) { + smart_str_free(&buf); + } + + if (result > 0) { + RETURN_TRUE; + } + + RETURN_FALSE; +} +/* }}} */ + +static void php_mmc_incr_decr(INTERNAL_FUNCTION_PARAMETERS, int cmd) /* {{{ */ +{ + mmc_t *mmc; + mmc_pool_t *pool; + int result = -1, key_len; + long value = 1, number; + char *key; + zval *mmc_object = getThis(); + char key_tmp[MMC_KEY_MAX_SIZE]; + unsigned int key_tmp_len; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &value) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len, &value) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { + RETURN_FALSE; + } + + if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { + RETURN_FALSE; + } + + while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) { + if ((result = mmc_incr_decr(mmc, cmd, key_tmp, key_tmp_len, value, &number TSRMLS_CC)) < 0) { + mmc_server_failure(mmc TSRMLS_CC); + } + } + + if (result > 0) { + RETURN_LONG(number); + } + RETURN_FALSE; +} +/* }}} */ + +static void php_mmc_connect (INTERNAL_FUNCTION_PARAMETERS, int persistent) /* {{{ */ +{ + zval **connection, *mmc_object = getThis(); + mmc_t *mmc = NULL; + mmc_pool_t *pool; + int resource_type, host_len, errnum = 0, list_id; + char *host, *error_string = NULL; + long port = MEMCACHE_G(default_port), timeout = MMC_DEFAULT_TIMEOUT, timeoutms = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lll", &host, &host_len, &port, &timeout, &timeoutms) == FAILURE) { + return; + } + + if (timeoutms < 1) { + timeoutms = MEMCACHE_G(default_timeout_ms); + } + + /* initialize and connect server struct */ + if (persistent) { + mmc = mmc_find_persistent(host, host_len, port, timeout, MMC_DEFAULT_RETRY TSRMLS_CC); + } + else { + MMC_DEBUG(("php_mmc_connect: creating regular connection")); + mmc = mmc_server_new(host, host_len, port, 0, timeout, MMC_DEFAULT_RETRY TSRMLS_CC); + } + + mmc->timeout = timeout; + mmc->connect_timeoutms = timeoutms; + + if (!mmc_open(mmc, 1, &error_string, &errnum TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%ld, %s (%d)", host, port, error_string ? error_string : "Unknown error", errnum); + if (!persistent) { + mmc_server_free(mmc TSRMLS_CC); + } + if (error_string) { + efree(error_string); + } + RETURN_FALSE; + } + + /* initialize pool and object if need be */ + if (!mmc_object) { + pool = mmc_pool_new(TSRMLS_C); + mmc_pool_add(pool, mmc, 1); + + object_init_ex(return_value, memcache_class_entry_ptr); + list_id = MEMCACHE_LIST_INSERT(pool, le_memcache_pool); + add_property_resource(return_value, "connection", list_id); + } + else if (zend_hash_find(Z_OBJPROP_P(mmc_object), "connection", sizeof("connection"), (void **) &connection) != FAILURE) { + pool = (mmc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type); + if (!pool || resource_type != le_memcache_pool) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown connection identifier"); + RETURN_FALSE; + } + + mmc_pool_add(pool, mmc, 1); + RETURN_TRUE; + } + else { + pool = mmc_pool_new(TSRMLS_C); + mmc_pool_add(pool, mmc, 1); + + list_id = MEMCACHE_LIST_INSERT(pool, le_memcache_pool); + add_property_resource(mmc_object, "connection", list_id); + RETURN_TRUE; + } +} +/* }}} */ + +/* ---------------- + module functions + ---------------- */ + +/* {{{ proto object memcache_connect( string host [, int port [, int timeout ] ]) + Connects to server and returns a Memcache object */ +PHP_FUNCTION(memcache_connect) +{ + php_mmc_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto object memcache_pconnect( string host [, int port [, int timeout ] ]) + Connects to server and returns a Memcache object */ +PHP_FUNCTION(memcache_pconnect) +{ + php_mmc_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + +/* {{{ proto bool memcache_add_server( string host [, int port [, bool persistent [, int weight [, int timeout [, int retry_interval [, bool status [, callback failure_callback ] ] ] ] ] ] ]) + Adds a connection to the pool. The order in which this function is called is significant */ +PHP_FUNCTION(memcache_add_server) +{ + zval **connection, *mmc_object = getThis(), *failure_callback = NULL; + mmc_pool_t *pool; + mmc_t *mmc; + long port = MEMCACHE_G(default_port), weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY, timeoutms = 0; + zend_bool persistent = 1, status = 1; + int resource_type, host_len, list_id; + char *host; + + if (mmc_object) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lblllbzl", &host, &host_len, &port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback, &timeoutms) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lblllbzl", &mmc_object, memcache_class_entry_ptr, &host, &host_len, &port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback, &timeoutms) == FAILURE) { + return; + } + } + + if (timeoutms < 1) { + timeoutms = MEMCACHE_G(default_timeout_ms); + } + + if (weight < 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "weight must be a positive integer"); + RETURN_FALSE; + } + + if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { + if (!MEMCACHE_IS_CALLABLE(failure_callback, 0, NULL)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback"); + RETURN_FALSE; + } + } + + /* lazy initialization of server struct */ + if (persistent) { + mmc = mmc_find_persistent(host, host_len, port, timeout, retry_interval TSRMLS_CC); + } + else { + MMC_DEBUG(("memcache_add_server: initializing regular struct")); + mmc = mmc_server_new(host, host_len, port, 0, timeout, retry_interval TSRMLS_CC); + } + + mmc->connect_timeoutms = timeoutms; + + /* add server in failed mode */ + if (!status) { + mmc->status = MMC_STATUS_FAILED; + } + + if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { + mmc->failure_callback = failure_callback; + mmc_server_callback_ctor(&mmc->failure_callback TSRMLS_CC); + } + + /* initialize pool if need be */ + if (zend_hash_find(Z_OBJPROP_P(mmc_object), "connection", sizeof("connection"), (void **) &connection) == FAILURE) { + pool = mmc_pool_new(TSRMLS_C); + list_id = MEMCACHE_LIST_INSERT(pool, le_memcache_pool); + add_property_resource(mmc_object, "connection", list_id); + } + else { + pool = (mmc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type); + if (!pool || resource_type != le_memcache_pool) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to extract 'connection' variable from object"); + RETURN_FALSE; + } + } + + mmc_pool_add(pool, mmc, weight); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool memcache_set_server_params( string host [, int port [, int timeout [, int retry_interval [, bool status [, callback failure_callback ] ] ] ] ]) + Changes server parameters at runtime */ +PHP_FUNCTION(memcache_set_server_params) +{ + zval *mmc_object = getThis(), *failure_callback = NULL; + mmc_pool_t *pool; + mmc_t *mmc = NULL; + long port = MEMCACHE_G(default_port), timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY; + zend_bool status = 1; + int host_len, i; + char *host; + + if (mmc_object) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lllbz", &host, &host_len, &port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lllbz", &mmc_object, memcache_class_entry_ptr, &host, &host_len, &port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + for (i=0; i<pool->num_servers; i++) { + if (!strcmp(pool->servers[i]->host, host) && pool->servers[i]->port == port) { + mmc = pool->servers[i]; + break; + } + } + + if (!mmc) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server not found in pool"); + RETURN_FALSE; + } + + if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { + if (!MEMCACHE_IS_CALLABLE(failure_callback, 0, NULL)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback"); + RETURN_FALSE; + } + } + + mmc->timeout = timeout; + mmc->retry_interval = retry_interval; + + if (!status) { + mmc->status = MMC_STATUS_FAILED; + } + else if (mmc->status == MMC_STATUS_FAILED) { + mmc->status = MMC_STATUS_DISCONNECTED; + } + + if (failure_callback != NULL) { + if (mmc->failure_callback != NULL) { + mmc_server_callback_dtor(&mmc->failure_callback TSRMLS_CC); + } + + if (Z_TYPE_P(failure_callback) != IS_NULL) { + mmc->failure_callback = failure_callback; + mmc_server_callback_ctor(&mmc->failure_callback TSRMLS_CC); + } + else { + mmc->failure_callback = NULL; + } + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int memcache_get_server_status( string host [, int port ]) + Returns server status (0 if server is failed, otherwise non-zero) */ +PHP_FUNCTION(memcache_get_server_status) +{ + zval *mmc_object = getThis(); + mmc_pool_t *pool; + mmc_t *mmc = NULL; + long port = MEMCACHE_G(default_port); + int host_len, i; + char *host; + + if (mmc_object) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &host, &host_len, &port) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &host, &host_len, &port) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + for (i=0; i<pool->num_servers; i++) { + if (!strcmp(pool->servers[i]->host, host) && pool->servers[i]->port == port) { + mmc = pool->servers[i]; + break; + } + } + + if (!mmc) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server not found in pool"); + RETURN_FALSE; + } + + RETURN_LONG(mmc->status); +} +/* }}} */ + +mmc_t *mmc_find_persistent(char *host, int host_len, int port, int timeout, int retry_interval TSRMLS_DC) /* {{{ */ +{ + mmc_t *mmc; + zend_rsrc_list_entry *le; + char *hash_key; + int hash_key_len; + + MMC_DEBUG(("mmc_find_persistent: seeking for persistent connection")); + hash_key_len = spprintf(&hash_key, 0, "mmc_connect___%s:%d", host, port); + + if (zend_hash_find(&EG(persistent_list), hash_key, hash_key_len+1, (void **) &le) == FAILURE) { + zend_rsrc_list_entry new_le; + MMC_DEBUG(("mmc_find_persistent: connection wasn't found in the hash")); + + mmc = mmc_server_new(host, host_len, port, 1, timeout, retry_interval TSRMLS_CC); + new_le.type = le_pmemcache; + new_le.ptr = mmc; + + /* register new persistent connection */ + if (zend_hash_update(&EG(persistent_list), hash_key, hash_key_len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) { + mmc_server_free(mmc TSRMLS_CC); + mmc = NULL; + } else { + MEMCACHE_LIST_INSERT(mmc, le_pmemcache); + } + } + else if (le->type != le_pmemcache || le->ptr == NULL) { + zend_rsrc_list_entry new_le; + MMC_DEBUG(("mmc_find_persistent: something was wrong, reconnecting..")); + zend_hash_del(&EG(persistent_list), hash_key, hash_key_len+1); + + mmc = mmc_server_new(host, host_len, port, 1, timeout, retry_interval TSRMLS_CC); + new_le.type = le_pmemcache; + new_le.ptr = mmc; + + /* register new persistent connection */ + if (zend_hash_update(&EG(persistent_list), hash_key, hash_key_len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) { + mmc_server_free(mmc TSRMLS_CC); + mmc = NULL; + } + else { + MEMCACHE_LIST_INSERT(mmc, le_pmemcache); + } + } + else { + MMC_DEBUG(("mmc_find_persistent: connection found in the hash")); + mmc = (mmc_t *)le->ptr; + mmc->timeout = timeout; + mmc->retry_interval = retry_interval; + + /* attempt to reconnect this node before failover in case connection has gone away */ + if (mmc->status == MMC_STATUS_CONNECTED) { + mmc->status = MMC_STATUS_UNKNOWN; + } + } + + efree(hash_key); + return mmc; +} +/* }}} */ + +/* {{{ proto string memcache_get_version( object memcache ) + Returns server's version */ +PHP_FUNCTION(memcache_get_version) +{ + mmc_pool_t *pool; + char *version; + int i; + zval *mmc_object = getThis(); + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_class_entry_ptr) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + for (i=0; i<pool->num_servers; i++) { + if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { + if ((version = mmc_get_version(pool->servers[i] TSRMLS_CC)) != NULL) { + RETURN_STRING(version, 0); + } + else { + mmc_server_failure(pool->servers[i] TSRMLS_CC); + } + } + } + + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool memcache_add( object memcache, string key, mixed var [, int flag [, int expire ] ] ) + Adds new item. Item with such key should not exist. */ +PHP_FUNCTION(memcache_add) +{ + php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "add", sizeof("add") - 1); +} +/* }}} */ + +/* {{{ proto bool memcache_set( object memcache, string key, mixed var [, int flag [, int expire ] ] ) + Sets the value of an item. Item may exist or not */ +PHP_FUNCTION(memcache_set) +{ + php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "set", sizeof("set") - 1); +} +/* }}} */ + +/* {{{ proto bool memcache_replace( object memcache, string key, mixed var [, int flag [, int expire ] ] ) + Replaces existing item. Returns false if item doesn't exist */ +PHP_FUNCTION(memcache_replace) +{ + php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "replace", sizeof("replace") - 1); +} +/* }}} */ + +/* {{{ proto mixed memcache_get( object memcache, mixed key [, mixed &flags ] ) + Returns value of existing item or false */ +PHP_FUNCTION(memcache_get) +{ + mmc_pool_t *pool; + zval *zkey, *mmc_object = getThis(), *flags = NULL; + char key[MMC_KEY_MAX_SIZE]; + unsigned int key_len; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|z", &mmc_object, memcache_class_entry_ptr, &zkey, &flags) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &zkey, &flags) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { + RETURN_FALSE; + } + + if (Z_TYPE_P(zkey) != IS_ARRAY) { + if (mmc_prepare_key(zkey, key, &key_len TSRMLS_CC) == MMC_OK) { + if (mmc_exec_retrieval_cmd(pool, key, key_len, &return_value, flags TSRMLS_CC) < 0) { + zval_dtor(return_value); + RETVAL_FALSE; + } + } + else { + RETVAL_FALSE; + } + } else if (zend_hash_num_elements(Z_ARRVAL_P(zkey))){ + if (mmc_exec_retrieval_cmd_multi(pool, zkey, &return_value, flags TSRMLS_CC) < 0) { + zval_dtor(return_value); + RETVAL_FALSE; + } + } else { + RETVAL_FALSE; + } +} +/* }}} */ + +/* {{{ proto bool memcache_delete( object memcache, string key [, int expire ]) + Deletes existing item */ +PHP_FUNCTION(memcache_delete) +{ + mmc_t *mmc; + mmc_pool_t *pool; + int result = -1, key_len; + zval *mmc_object = getThis(); + char *key; + long time = 0; + char key_tmp[MMC_KEY_MAX_SIZE]; + unsigned int key_tmp_len; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &time) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len, &time) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { + RETURN_FALSE; + } + + if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { + RETURN_FALSE; + } + + while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) { + if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, time TSRMLS_CC)) < 0) { + mmc_server_failure(mmc TSRMLS_CC); + } + } + + if (result > 0) { + RETURN_TRUE; + } + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool memcache_debug( bool onoff ) + Turns on/off internal debugging */ +PHP_FUNCTION(memcache_debug) +{ +#if ZEND_DEBUG + zend_bool onoff; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &onoff) == FAILURE) { + return; + } + + MEMCACHE_G(debug_mode) = onoff ? 1 : 0; + + RETURN_TRUE; +#else + RETURN_FALSE; +#endif + +} +/* }}} */ + +/* {{{ proto array memcache_get_stats( object memcache [, string type [, int slabid [, int limit ] ] ]) + Returns server's statistics */ +PHP_FUNCTION(memcache_get_stats) +{ + mmc_pool_t *pool; + int i, failures = 0; + zval *mmc_object = getThis(); + + char *type = NULL; + int type_len = 0; + long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_class_entry_ptr, &type, &type_len, &slabid, &limit) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sll", &type, &type_len, &slabid, &limit) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + for (i=0; i<pool->num_servers; i++) { + if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { + if (mmc_get_stats(pool->servers[i], type, slabid, limit, return_value TSRMLS_CC) < 0) { + mmc_server_failure(pool->servers[i] TSRMLS_CC); + failures++; + } + else { + break; + } + } + else { + failures++; + } + } + + if (failures >= pool->num_servers) { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto array memcache_get_extended_stats( object memcache [, string type [, int slabid [, int limit ] ] ]) + Returns statistics for each server in the pool */ +PHP_FUNCTION(memcache_get_extended_stats) +{ + mmc_pool_t *pool; + char *hostname; + int i, hostname_len; + zval *mmc_object = getThis(), *stats; + + char *type = NULL; + int type_len = 0; + long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_class_entry_ptr, &type, &type_len, &slabid, &limit) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sll", &type, &type_len, &slabid, &limit) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + array_init(return_value); + for (i=0; i<pool->num_servers; i++) { + MAKE_STD_ZVAL(stats); + + hostname_len = spprintf(&hostname, 0, "%s:%d", pool->servers[i]->host, pool->servers[i]->port); + + if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { + if (mmc_get_stats(pool->servers[i], type, slabid, limit, stats TSRMLS_CC) < 0) { + mmc_server_failure(pool->servers[i] TSRMLS_CC); + ZVAL_FALSE(stats); + } + } + else { + ZVAL_FALSE(stats); + } + + add_assoc_zval_ex(return_value, hostname, hostname_len + 1, stats); + efree(hostname); + } +} +/* }}} */ + +/* {{{ proto array memcache_set_compress_threshold( object memcache, int threshold [, float min_savings ] ) + Set automatic compress threshold */ +PHP_FUNCTION(memcache_set_compress_threshold) +{ + mmc_pool_t *pool; + zval *mmc_object = getThis(); + long threshold; + double min_savings = MMC_DEFAULT_SAVINGS; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|d", &mmc_object, memcache_class_entry_ptr, &threshold, &min_savings) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|d", &threshold, &min_savings) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + if (threshold < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "threshold must be a positive integer"); + RETURN_FALSE; + } + pool->compress_threshold = threshold; + + if (min_savings != MMC_DEFAULT_SAVINGS) { + if (min_savings < 0 || min_savings > 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "min_savings must be a float in the 0..1 range"); + RETURN_FALSE; + } + pool->min_compress_savings = min_savings; + } + else { + pool->min_compress_savings = MMC_DEFAULT_SAVINGS; + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int memcache_increment( object memcache, string key [, int value ] ) + Increments existing variable */ +PHP_FUNCTION(memcache_increment) +{ + php_mmc_incr_decr(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + +/* {{{ proto int memcache_decrement( object memcache, string key [, int value ] ) + Decrements existing variable */ +PHP_FUNCTION(memcache_decrement) +{ + php_mmc_incr_decr(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto bool memcache_close( object memcache ) + Closes connection to memcached */ +PHP_FUNCTION(memcache_close) +{ + mmc_pool_t *pool; + zval *mmc_object = getThis(); + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_class_entry_ptr) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + if (!mmc_pool_close(pool TSRMLS_CC)) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool memcache_flush( object memcache [, int timestamp ] ) + Flushes cache, optionally at the specified time */ +PHP_FUNCTION(memcache_flush) +{ + mmc_pool_t *pool; + int i, failures = 0; + zval *mmc_object = getThis(); + long timestamp = 0; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &mmc_object, memcache_class_entry_ptr, ×tamp) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", ×tamp) == FAILURE) { + return; + } + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + for (i=0; i<pool->num_servers; i++) { + if (mmc_open(pool->servers[i], 1, NULL, NULL TSRMLS_CC)) { + if (mmc_flush(pool->servers[i], timestamp TSRMLS_CC) < 0) { + mmc_server_failure(pool->servers[i] TSRMLS_CC); + failures++; + } + } + else { + failures++; + } + } + + if (failures && failures >= pool->num_servers) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool memcache_setoptimeout( object memcache , int timeoutms ) + Set the timeout, in milliseconds, for subsequent operations on all open connections */ +PHP_FUNCTION(memcache_setoptimeout) +{ + mmc_pool_t *pool; + mmc_t *mmc; + int i; + zval *mmc_object = getThis(); + long timeoutms = 0; + + if (mmc_object == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &mmc_object, memcache_class_entry_ptr, &timeoutms) == FAILURE) { + return; + } + } + else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &timeoutms) == FAILURE) { + return; + } + } + + if (timeoutms < 1) { + timeoutms = MEMCACHE_G(default_timeout_ms); + } + + if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) { + RETURN_FALSE; + } + + for (i = 0; i < pool->num_servers; i++) { + mmc = pool->servers[i]; + mmc->timeoutms = timeoutms; + } + RETURN_TRUE; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/memcache.dsp ^ |
(renamed from memcache-2.2.5/memcache.dsp) | ||
[+] | Changed | memcache-2.2.7.tgz/memcache-2.2.7/memcache.dsp ^ |
(renamed from memcache-2.2.5/memcache.dsp) | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/memcache.php ^ |
@@ -0,0 +1,899 @@ +<?php +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Harun Yayli <harunyayli at gmail.com> | + +----------------------------------------------------------------------+ +*/ + +$VERSION='$Id: memcache.php 309747 2011-03-27 17:28:56Z hradtke $'; + +define('ADMIN_USERNAME','memcache'); // Admin Username +define('ADMIN_PASSWORD','password'); // Admin Password +define('DATE_FORMAT','Y/m/d H:i:s'); +define('GRAPH_SIZE',200); +define('MAX_ITEM_DUMP',50); + +$MEMCACHE_SERVERS[] = 'mymemcache-server1:11211'; // add more as an array +$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array + + +////////// END OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////// + +///////////////// Password protect //////////////////////////////////////////////////////////////// +if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || + $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||$_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) { + Header("WWW-Authenticate: Basic realm=\"Memcache Login\""); + Header("HTTP/1.0 401 Unauthorized"); + + echo <<<EOB + <html><body> + <h1>Rejected!</h1> + <big>Wrong Username or Password!</big> + </body></html> +EOB; + exit; +} + +///////////MEMCACHE FUNCTIONS ///////////////////////////////////////////////////////////////////// + +function get_host_port_from_server($server){ + $values = explode(':', $server); + if (($values[0] == 'unix') && (!is_numeric( $values[1]))) { + return array($server, 0); + } + else { + return $values; + } +} + +function sendMemcacheCommands($command){ + global $MEMCACHE_SERVERS; + $result = array(); + + foreach($MEMCACHE_SERVERS as $server){ + $strs = get_host_port_from_server($server); + $host = $strs[0]; + $port = $strs[1]; + $result[$server] = sendMemcacheCommand($host,$port,$command); + } + return $result; +} +function sendMemcacheCommand($server,$port,$command){ + + $s = @fsockopen($server,$port); + if (!$s){ + die("Cant connect to:".$server.':'.$port); + } + + fwrite($s, $command."\r\n"); + + $buf=''; + while ((!feof($s))) { + $buf .= fgets($s, 256); + if (strpos($buf,"END\r\n")!==false){ // stat says end + break; + } + if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these + break; + } + if (strpos($buf,"OK\r\n")!==false){ // flush_all says ok + break; + } + } + fclose($s); + return parseMemcacheResults($buf); +} +function parseMemcacheResults($str){ + + $res = array(); + $lines = explode("\r\n",$str); + $cnt = count($lines); + for($i=0; $i< $cnt; $i++){ + $line = $lines[$i]; + $l = explode(' ',$line,3); + if (count($l)==3){ + $res[$l[0]][$l[1]]=$l[2]; + if ($l[0]=='VALUE'){ // next line is the value + $res[$l[0]][$l[1]] = array(); + list ($flag,$size)=explode(' ',$l[2]); + $res[$l[0]][$l[1]]['stat']=array('flag'=>$flag,'size'=>$size); + $res[$l[0]][$l[1]]['value']=$lines[++$i]; + } + }elseif($line=='DELETED' || $line=='NOT_FOUND' || $line=='OK'){ + return $line; + } + } + return $res; + +} + +function dumpCacheSlab($server,$slabId,$limit){ + list($host,$port) = get_host_port_from_server($server); + $resp = sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit); + + return $resp; + +} + +function flushServer($server){ + list($host,$port) = get_host_port_from_server($server); + $resp = sendMemcacheCommand($host,$port,'flush_all'); + return $resp; +} +function getCacheItems(){ + $items = sendMemcacheCommands('stats items'); + $serverItems = array(); + $totalItems = array(); + foreach ($items as $server=>$itemlist){ + $serverItems[$server] = array(); + $totalItems[$server]=0; + if (!isset($itemlist['STAT'])){ + continue; + } + + $iteminfo = $itemlist['STAT']; + + foreach($iteminfo as $keyinfo=>$value){ + if (preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){ + $serverItems[$server][$matches[1]][$matches[2]] = $value; + if ($matches[2]=='number'){ + $totalItems[$server] +=$value; + } + } + } + } + return array('items'=>$serverItems,'counts'=>$totalItems); +} +function getMemcacheStats($total=true){ + $resp = sendMemcacheCommands('stats'); + if ($total){ + $res = array(); + foreach($resp as $server=>$r){ + foreach($r['STAT'] as $key=>$row){ + if (!isset($res[$key])){ + $res[$key]=null; + } + switch ($key){ + case 'pid': + $res['pid'][$server]=$row; + break; + case 'uptime': + $res['uptime'][$server]=$row; + break; + case 'time': + $res['time'][$server]=$row; + break; + case 'version': + $res['version'][$server]=$row; + break; + case 'pointer_size': + $res['pointer_size'][$server]=$row; + break; + case 'rusage_user': + $res['rusage_user'][$server]=$row; + break; + case 'rusage_system': + $res['rusage_system'][$server]=$row; + break; + case 'curr_items': + $res['curr_items']+=$row; + break; + case 'total_items': + $res['total_items']+=$row; + break; + case 'bytes': + $res['bytes']+=$row; + break; + case 'curr_connections': + $res['curr_connections']+=$row; + break; + case 'total_connections': + $res['total_connections']+=$row; + break; + case 'connection_structures': + $res['connection_structures']+=$row; + break; + case 'cmd_get': + $res['cmd_get']+=$row; + break; + case 'cmd_set': + $res['cmd_set']+=$row; + break; + case 'get_hits': + $res['get_hits']+=$row; + break; + case 'get_misses': + $res['get_misses']+=$row; + break; + case 'evictions': + $res['evictions']+=$row; + break; + case 'bytes_read': + $res['bytes_read']+=$row; + break; + case 'bytes_written': + $res['bytes_written']+=$row; + break; + case 'limit_maxbytes': + $res['limit_maxbytes']+=$row; + break; + case 'threads': + $res['rusage_system'][$server]=$row; + break; + } + } + } + return $res; + } + return $resp; +} + +////////////////////////////////////////////////////// + +// +// don't cache this page +// +header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); // HTTP/1.0 + +function duration($ts) { + global $time; + $years = (int)((($time - $ts)/(7*86400))/52.177457); + $rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400)); + $weeks = (int)(($rem)/(7*86400)); + $days = (int)(($rem)/86400) - $weeks*7; + $hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24; + $mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60; + $str = ''; + if($years==1) $str .= "$years year, "; + if($years>1) $str .= "$years years, "; + if($weeks==1) $str .= "$weeks week, "; + if($weeks>1) $str .= "$weeks weeks, "; + if($days==1) $str .= "$days day,"; + if($days>1) $str .= "$days days,"; + if($hours == 1) $str .= " $hours hour and"; + if($hours>1) $str .= " $hours hours and"; + if($mins == 1) $str .= " 1 minute"; + else $str .= " $mins minutes"; + return $str; +} + +// create graphics +// +function graphics_avail() { + return extension_loaded('gd'); +} + +function bsize($s) { + foreach (array('','K','M','G') as $i => $k) { + if ($s < 1024) break; + $s/=1024; + } + return sprintf("%5.1f %sBytes",$s,$k); +} + +// create menu entry +function menu_entry($ob,$title) { + global $PHP_SELF; + if ($ob==$_GET['op']){ + return "<li><a class=\"child_active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>"; + } + return "<li><a class=\"active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>"; +} + +function getHeader(){ + $header = <<<EOB +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head><title>MEMCACHE INFO</title> +<style type="text/css"><!-- +body { background:white; font-size:100.01%; margin:0; padding:0; } +body,p,td,th,input,submit { font-size:0.8em;font-family:arial,helvetica,sans-serif; } +* html body {font-size:0.8em} +* html p {font-size:0.8em} +* html td {font-size:0.8em} +* html th {font-size:0.8em} +* html input {font-size:0.8em} +* html submit {font-size:0.8em} +td { vertical-align:top } +a { color:black; font-weight:none; text-decoration:none; } +a:hover { text-decoration:underline; } +div.content { padding:1em 1em 1em 1em; position:absolute; width:97%; z-index:100; } + +h1.memcache { background:rgb(153,153,204); margin:0; padding:0.5em 1em 0.5em 1em; } +* html h1.memcache { margin-bottom:-7px; } +h1.memcache a:hover { text-decoration:none; color:rgb(90,90,90); } +h1.memcache span.logo { + background:rgb(119,123,180); + color:black; + border-right: solid black 1px; + border-bottom: solid black 1px; + font-style:italic; + font-size:1em; + padding-left:1.2em; + padding-right:1.2em; + text-align:right; + display:block; + width:130px; + } +h1.memcache span.logo span.name { color:white; font-size:0.7em; padding:0 0.8em 0 2em; } +h1.memcache span.nameinfo { color:white; display:inline; font-size:0.4em; margin-left: 3em; } +h1.memcache div.copy { color:black; font-size:0.4em; position:absolute; right:1em; } +hr.memcache { + background:white; + border-bottom:solid rgb(102,102,153) 1px; + border-style:none; + border-top:solid rgb(102,102,153) 10px; + height:12px; + margin:0; + margin-top:1px; + padding:0; +} + +ol,menu { margin:1em 0 0 0; padding:0.2em; margin-left:1em;} +ol.menu li { display:inline; margin-right:0.7em; list-style:none; font-size:85%} +ol.menu a { + background:rgb(153,153,204); + border:solid rgb(102,102,153) 2px; + color:white; + font-weight:bold; + margin-right:0em; + padding:0.1em 0.5em 0.1em 0.5em; + text-decoration:none; + margin-left: 5px; + } +ol.menu a.child_active { + background:rgb(153,153,204); + border:solid rgb(102,102,153) 2px; + color:white; + font-weight:bold; + margin-right:0em; + padding:0.1em 0.5em 0.1em 0.5em; + text-decoration:none; + border-left: solid black 5px; + margin-left: 0px; + } +ol.menu span.active { + background:rgb(153,153,204); + border:solid rgb(102,102,153) 2px; + color:black; + font-weight:bold; + margin-right:0em; + padding:0.1em 0.5em 0.1em 0.5em; + text-decoration:none; + border-left: solid black 5px; + } +ol.menu span.inactive { + background:rgb(193,193,244); + border:solid rgb(182,182,233) 2px; + color:white; + font-weight:bold; + margin-right:0em; + padding:0.1em 0.5em 0.1em 0.5em; + text-decoration:none; + margin-left: 5px; + } +ol.menu a:hover { + background:rgb(193,193,244); + text-decoration:none; + } + + +div.info { + background:rgb(204,204,204); + border:solid rgb(204,204,204) 1px; + margin-bottom:1em; + } +div.info h2 { + background:rgb(204,204,204); + color:black; + font-size:1em; + margin:0; + padding:0.1em 1em 0.1em 1em; + } +div.info table { + border:solid rgb(204,204,204) 1px; + border-spacing:0; + width:100%; + } +div.info table th { + background:rgb(204,204,204); + color:white; + margin:0; + padding:0.1em 1em 0.1em 1em; + } +div.info table th a.sortable { color:black; } +div.info table tr.tr-0 { background:rgb(238,238,238); } +div.info table tr.tr-1 { background:rgb(221,221,221); } +div.info table td { padding:0.3em 1em 0.3em 1em; } +div.info table td.td-0 { border-right:solid rgb(102,102,153) 1px; white-space:nowrap; } +div.info table td.td-n { border-right:solid rgb(102,102,153) 1px; } +div.info table td h3 { + color:black; + font-size:1.1em; + margin-left:-0.3em; + } +.td-0 a , .td-n a, .tr-0 a , tr-1 a { + text-decoration:underline; +} +div.graph { margin-bottom:1em } +div.graph h2 { background:rgb(204,204,204);; color:black; font-size:1em; margin:0; padding:0.1em 1em 0.1em 1em; } +div.graph table { border:solid rgb(204,204,204) 1px; color:black; font-weight:normal; width:100%; } +div.graph table td.td-0 { background:rgb(238,238,238); } +div.graph table td.td-1 { background:rgb(221,221,221); } +div.graph table td { padding:0.2em 1em 0.4em 1em; } + +div.div1,div.div2 { margin-bottom:1em; width:35em; } +div.div3 { position:absolute; left:40em; top:1em; width:580px; } +//div.div3 { position:absolute; left:37em; top:1em; right:1em; } + +div.sorting { margin:1.5em 0em 1.5em 2em } +.center { text-align:center } +.aright { position:absolute;right:1em } +.right { text-align:right } +.ok { color:rgb(0,200,0); font-weight:bold} +.failed { color:rgb(200,0,0); font-weight:bold} + +span.box { + border: black solid 1px; + border-right:solid black 2px; + border-bottom:solid black 2px; + padding:0 0.5em 0 0.5em; + margin-right:1em; +} +span.green { background:#60F060; padding:0 0.5em 0 0.5em} +span.red { background:#D06030; padding:0 0.5em 0 0.5em } + +div.authneeded { + background:rgb(238,238,238); + border:solid rgb(204,204,204) 1px; + color:rgb(200,0,0); + font-size:1.2em; + font-weight:bold; + padding:2em; + text-align:center; + } + +input { + background:rgb(153,153,204); + border:solid rgb(102,102,153) 2px; + color:white; + font-weight:bold; + margin-right:1em; + padding:0.1em 0.5em 0.1em 0.5em; + } +//--> +</style> +</head> +<body> +<div class="head"> + <h1 class="memcache"> + <span class="logo"><a href="http://pecl.php.net/package/memcache">memcache</a></span> + <span class="nameinfo">memcache.php by <a href="http://livebookmark.net">Harun Yayli</a></span> + </h1> + <hr class="memcache"> +</div> +<div class=content> +EOB; + + return $header; +} +function getFooter(){ + global $VERSION; + $footer = '</div><!-- Based on apc.php '.$VERSION.'--></body> +</html> +'; + + return $footer; + +} +function getMenu(){ + global $PHP_SELF; +echo "<ol class=menu>"; +if ($_GET['op']!=4){ +echo <<<EOB + <li><a href="$PHP_SELF&op={$_GET['op']}">Refresh Data</a></li> +EOB; +} +else { +echo <<<EOB + <li><a href="$PHP_SELF&op=2}">Back</a></li> +EOB; +} +echo + menu_entry(1,'View Host Stats'), + menu_entry(2,'Variables'); + +echo <<<EOB + </ol> + <br/> +EOB; +} + +// TODO, AUTH + +$_GET['op'] = !isset($_GET['op'])? '1':$_GET['op']; +$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : ''; + +$PHP_SELF=$PHP_SELF.'?'; +$time = time(); +// sanitize _GET + +foreach($_GET as $key=>$g){ + $_GET[$key]=htmlentities($g); +} + + +// singleout +// when singleout is set, it only gives details for that server. +if (isset($_GET['singleout']) && $_GET['singleout']>=0 && $_GET['singleout'] <count($MEMCACHE_SERVERS)){ + $MEMCACHE_SERVERS = array($MEMCACHE_SERVERS[$_GET['singleout']]); +} + +// display images +if (isset($_GET['IMG'])){ + $memcacheStats = getMemcacheStats(); + $memcacheStatsSingle = getMemcacheStats(false); + + if (!graphics_avail()) { + exit(0); + } + + function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') { + global $col_black; + $x1=$x+$w-1; + $y1=$y+$h-1; + + imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black); + if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2); + else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2); + imagerectangle($im, $x, $y1, $x1, $y, $color1); + if ($text) { + if ($placeindex>0) { + + if ($placeindex<16) + { + $px=5; + $py=$placeindex*12+6; + imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2); + imageline($im,$x,$y+$h/2,$px+90,$py,$color2); + imagestring($im,2,$px,$py-6,$text,$color1); + + } else { + if ($placeindex<31) { + $px=$x+40*2; + $py=($placeindex-15)*12+6; + } else { + $px=$x+40*2+100*intval(($placeindex-15)/15); + $py=($placeindex%15)*12+6; + } + imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2); + imageline($im,$x+$w,$y+$h/2,$px,$py,$color2); + imagestring($im,2,$px+2,$py-6,$text,$color1); + } + } else { + imagestring($im,4,$x+5,$y1-16,$text,$color1); + } + } + } + + + function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) { + $r=$diameter/2; + $w=deg2rad((360+$start+($end-$start)/2)%360); + + + if (function_exists("imagefilledarc")) { + // exists only if GD 2.0.1 is avaliable + imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE); + imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE); + imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); + } else { + imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2); + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); + imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2); + } + if ($text) { + if ($placeindex>0) { + imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); + imagestring($im,4,$diameter, $placeindex*12,$text,$color1); + + } else { + imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); + } + } + } + $size = GRAPH_SIZE; // image size + $image = imagecreate($size+50, $size+10); + + $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF); + $col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30); + $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60); + $col_black = imagecolorallocate($image, 0, 0, 0); + + imagecolortransparent($image,$col_white); + + switch ($_GET['IMG']){ + case 1: // pie chart + $tsize=$memcacheStats['limit_maxbytes']; + $avail=$tsize-$memcacheStats['bytes']; + $x=$y=$size/2; + $angle_from = 0; + $fuzz = 0.000001; + + foreach($memcacheStatsSingle as $serv=>$mcs) { + $free = $mcs['STAT']['limit_maxbytes']-$mcs['STAT']['bytes']; + $used = $mcs['STAT']['bytes']; + + + if ($free>0){ + // draw free + $angle_to = ($free*360)/$tsize; + $perc =sprintf("%.2f%%", ($free *100) / $tsize) ; + + fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_green,$perc); + $angle_from = $angle_from + $angle_to ; + } + if ($used>0){ + // draw used + $angle_to = ($used*360)/$tsize; + $perc =sprintf("%.2f%%", ($used *100) / $tsize) ; + fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_red, '('.$perc.')' ); + $angle_from = $angle_from+ $angle_to ; + } + } + + break; + + case 2: // hit miss + + $hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits']; + $misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses']; + $total = $hits + $misses ; + + fill_box($image, 30,$size,50,-$hits*($size-21)/$total,$col_black,$col_green,sprintf("%.1f%%",$hits*100/$total)); + fill_box($image,130,$size,50,-max(4,($total-$hits)*($size-21)/$total),$col_black,$col_red,sprintf("%.1f%%",$misses*100/$total)); + break; + + } + header("Content-type: image/png"); + imagepng($image); + exit; +} + +echo getHeader(); +echo getMenu(); + +switch ($_GET['op']) { + + case 1: // host stats + $phpversion = phpversion(); + $memcacheStats = getMemcacheStats(); + $memcacheStatsSingle = getMemcacheStats(false); + + $mem_size = $memcacheStats['limit_maxbytes']; + $mem_used = $memcacheStats['bytes']; + $mem_avail= $mem_size-$mem_used; + $startTime = time()-array_sum($memcacheStats['uptime']); + + $curr_items = $memcacheStats['curr_items']; + $total_items = $memcacheStats['total_items']; + $hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits']; + $misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses']; + $sets = $memcacheStats['cmd_set']; + + $req_rate = sprintf("%.2f",($hits+$misses)/($time-$startTime)); + $hit_rate = sprintf("%.2f",($hits)/($time-$startTime)); + $miss_rate = sprintf("%.2f",($misses)/($time-$startTime)); + $set_rate = sprintf("%.2f",($sets)/($time-$startTime)); + + echo <<< EOB + <div class="info div1"><h2>General Cache Information</h2> + <table cellspacing=0><tbody> + <tr class=tr-1><td class=td-0>PHP Version</td><td>$phpversion</td></tr> +EOB; + echo "<tr class=tr-0><td class=td-0>Memcached Host". ((count($MEMCACHE_SERVERS)>1) ? 's':'')."</td><td>"; + $i=0; + if (!isset($_GET['singleout']) && count($MEMCACHE_SERVERS)>1){ + foreach($MEMCACHE_SERVERS as $server){ + echo ($i+1).'. <a href="'.$PHP_SELF.'&singleout='.$i++.'">'.$server.'</a><br/>'; + } + } + else{ + echo '1.'.$MEMCACHE_SERVERS[0]; + } + if (isset($_GET['singleout'])){ + echo '<a href="'.$PHP_SELF.'">(all servers)</a><br/>'; + } + echo "</td></tr>\n"; + echo "<tr class=tr-1><td class=td-0>Total Memcache Cache</td><td>".bsize($memcacheStats['limit_maxbytes'])."</td></tr>\n"; + + echo <<<EOB + </tbody></table> + </div> + + <div class="info div1"><h2>Memcache Server Information</h2> +EOB; + foreach($MEMCACHE_SERVERS as $server){ + echo '<table cellspacing=0><tbody>'; + echo '<tr class=tr-1><td class=td-1>'.$server.'</td><td><a href="'.$PHP_SELF.'&server='.array_search($server,$MEMCACHE_SERVERS).'&op=6">[<b>Flush this server</b>]</a></td></tr>'; + echo '<tr class=tr-0><td class=td-0>Start Time</td><td>',date(DATE_FORMAT,$memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>'; + echo '<tr class=tr-1><td class=td-0>Uptime</td><td>',duration($memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>'; + echo '<tr class=tr-0><td class=td-0>Memcached Server Version</td><td>'.$memcacheStatsSingle[$server]['STAT']['version'].'</td></tr>'; + echo '<tr class=tr-1><td class=td-0>Used Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['bytes']),'</td></tr>'; + echo '<tr class=tr-0><td class=td-0>Total Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['limit_maxbytes']),'</td></tr>'; + echo '</tbody></table>'; + } + echo <<<EOB + + </div> + <div class="graph div3"><h2>Host Status Diagrams</h2> + <table cellspacing=0><tbody> +EOB; + + $size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10); + echo <<<EOB + <tr> + <td class=td-0>Cache Usage</td> + <td class=td-1>Hits & Misses</td> + </tr> +EOB; + + echo + graphics_avail() ? + '<tr>'. + "<td class=td-0><img alt=\"\" $size src=\"$PHP_SELF&IMG=1&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td>". + "<td class=td-1><img alt=\"\" $size src=\"$PHP_SELF&IMG=2&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td></tr>\n" + : "", + '<tr>', + '<td class=td-0><span class="green box"> </span>Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size),"</td>\n", + '<td class=td-1><span class="green box"> </span>Hits: ',$hits.sprintf(" (%.1f%%)",$hits*100/($hits+$misses)),"</td>\n", + '</tr>', + '<tr>', + '<td class=td-0><span class="red box"> </span>Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size),"</td>\n", + '<td class=td-1><span class="red box"> </span>Misses: ',$misses.sprintf(" (%.1f%%)",$misses*100/($hits+$misses)),"</td>\n"; + echo <<< EOB + </tr> + </tbody></table> +<br/> + <div class="info"><h2>Cache Information</h2> + <table cellspacing=0><tbody> + <tr class=tr-0><td class=td-0>Current Items(total)</td><td>$curr_items ($total_items)</td></tr> + <tr class=tr-1><td class=td-0>Hits</td><td>{$hits}</td></tr> + <tr class=tr-0><td class=td-0>Misses</td><td>{$misses}</td></tr> + <tr class=tr-1><td class=td-0>Request Rate (hits, misses)</td><td>$req_rate cache requests/second</td></tr> + <tr class=tr-0><td class=td-0>Hit Rate</td><td>$hit_rate cache requests/second</td></tr> + <tr class=tr-1><td class=td-0>Miss Rate</td><td>$miss_rate cache requests/second</td></tr> + <tr class=tr-0><td class=td-0>Set Rate</td><td>$set_rate cache requests/second</td></tr> + </tbody></table> + </div> + +EOB; + + break; + + case 2: // variables + + $m=0; + $cacheItems= getCacheItems(); + $items = $cacheItems['items']; + $totals = $cacheItems['counts']; + $maxDump = MAX_ITEM_DUMP; + foreach($items as $server => $entries) { + + echo <<< EOB + + <div class="info"><table cellspacing=0><tbody> + <tr><th colspan="2">$server</th></tr> + <tr><th>Slab Id</th><th>Info</th></tr> +EOB; + + foreach($entries as $slabId => $slab) { + $dumpUrl = $PHP_SELF.'&op=2&server='.(array_search($server,$MEMCACHE_SERVERS)).'&dumpslab='.$slabId; + echo + "<tr class=tr-$m>", + "<td class=td-0><center>",'<a href="',$dumpUrl,'">',$slabId,'</a>',"</center></td>", + "<td class=td-last><b>Item count:</b> ",$slab['number'],'<br/><b>Age:</b>',duration($time-$slab['age']),'<br/> <b>Evicted:</b>',((isset($slab['evicted']) && $slab['evicted']==1)? 'Yes':'No'); + if ((isset($_GET['dumpslab']) && $_GET['dumpslab']==$slabId) && (isset($_GET['server']) && $_GET['server']==array_search($server,$MEMCACHE_SERVERS))){ + echo "<br/><b>Items: item</b><br/>"; + $items = dumpCacheSlab($server,$slabId,$slab['number']); + // maybe someone likes to do a pagination here :) + $i=1; + foreach($items['ITEM'] as $itemKey=>$itemInfo){ + $itemInfo = trim($itemInfo,'[ ]'); + + + echo '<a href="',$PHP_SELF,'&op=4&server=',(array_search($server,$MEMCACHE_SERVERS)),'&key=',base64_encode($itemKey).'">',$itemKey,'</a>'; + if ($i++ % 10 == 0) { + echo '<br/>'; + } + elseif ($i!=$slab['number']+1){ + echo ','; + } + } + } + + echo "</td></tr>"; + $m=1-$m; + } + echo <<<EOB + </tbody></table> + </div><hr/> +EOB; +} + break; + + break; + + case 4: //item dump + if (!isset($_GET['key']) || !isset($_GET['server'])){ + echo "No key set!"; + break; + } + // I'm not doing anything to check the validity of the key string. + // probably an exploit can be written to delete all the files in key=base64_encode("\n\r delete all"). + // somebody has to do a fix to this. + $theKey = htmlentities(base64_decode($_GET['key'])); + + $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; + list($h,$p) = get_host_port_from_server($theserver); + $r = sendMemcacheCommand($h,$p,'get '.$theKey); + echo <<<EOB + <div class="info"><table cellspacing=0><tbody> + <tr><th>Server<th>Key</th><th>Value</th><th>Delete</th></tr> +EOB; + if (!isset($r['VALUE'])) { + echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey, + "</td><td>[The requested item was not found or has expired]</td>", + "<td></td>","</tr>"; + } + else { + + echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey, + " <br/>flag:",$r['VALUE'][$theKey]['stat']['flag'], + " <br/>Size:",bsize($r['VALUE'][$theKey]['stat']['size']), + "</td><td>",chunk_split($r['VALUE'][$theKey]['value'],40),"</td>", + '<td><a href="',$PHP_SELF,'&op=5&server=',(int)$_GET['server'],'&key=',base64_encode($theKey),"\">Delete</a></td>","</tr>"; + } + echo <<<EOB + </tbody></table> + </div><hr/> +EOB; + break; + case 5: // item delete + if (!isset($_GET['key']) || !isset($_GET['server'])){ + echo "No key set!"; + break; + } + $theKey = htmlentities(base64_decode($_GET['key'])); + $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; + list($h,$p) = get_host_port_from_server($theserver); + $r = sendMemcacheCommand($h,$p,'delete '.$theKey); + echo 'Deleting '.$theKey.':'.$r; + break; + + case 6: // flush server + $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; + $r = flushServer($theserver); + echo 'Flush '.$theserver.":".$r; + break; +} +echo getFooter(); + +?> | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/memcache_consistent_hash.c ^ |
@@ -0,0 +1,198 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Antony Dovgal <tony@daylessday.org> | + | Mikael Johansson <mikael AT synd DOT info> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: memcache_consistent_hash.c 273596 2009-01-15 18:11:41Z mikl $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> + +#include "php.h" +#include "php_memcache.h" + +ZEND_EXTERN_MODULE_GLOBALS(memcache) + +typedef struct mmc_consistent_point { + mmc_t *server; + unsigned int point; +} mmc_consistent_point_t; + +typedef struct mmc_consistent_state { + int num_servers; + mmc_consistent_point_t *points; + 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(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; +} +/* }}} */ + +void mmc_consistent_free_state(void *s) /* {{{ */ +{ + mmc_consistent_state_t *state = s; + if (state != NULL) { + if (state->points != NULL) { + efree(state->points); + } + efree(state); + } +} +/* }}} */ + +static int mmc_consistent_compare(const void *a, const void *b) /* {{{ */ +{ + if (((mmc_consistent_point_t *)a)->point < ((mmc_consistent_point_t *)b)->point) { + return -1; + } + if (((mmc_consistent_point_t *)a)->point > ((mmc_consistent_point_t *)b)->point) { + return 1; + } + return 0; +} +/* }}} */ + +static mmc_t *mmc_consistent_find(mmc_consistent_state_t *state, unsigned int point) /* {{{ */ +{ + int lo = 0, hi = state->num_points - 1, mid; + + while (1) { + /* point is outside interval or lo >= hi, wrap-around */ + if (point <= state->points[lo].point || point > state->points[hi].point) { + return state->points[lo].server; + } + + /* test middle point */ + mid = lo + (hi - lo) / 2; + MMC_DEBUG(("mmc_consistent_find: lo %d, hi %d, mid %d, point %u, midpoint %u", lo, hi, mid, point, state->points[mid].point)); + + /* perfect match */ + if (point <= state->points[mid].point && point > (mid ? state->points[mid-1].point : 0)) { + return state->points[mid].server; + } + + /* too low, go up */ + if (state->points[mid].point < point) { + lo = mid + 1; + } + else { + hi = mid - 1; + } + } +} +/* }}} */ + +static void mmc_consistent_populate_buckets(mmc_consistent_state_t *state) /* {{{ */ +{ + unsigned int i, step = 0xffffffff / MMC_CONSISTENT_BUCKETS; + + qsort((void *)state->points, state->num_points, sizeof(mmc_consistent_point_t), mmc_consistent_compare); + for (i=0; i<MMC_CONSISTENT_BUCKETS; i++) { + state->buckets[i] = mmc_consistent_find(state, step * i); + } + + state->buckets_populated = 1; +} +/* }}} */ + +mmc_t *mmc_consistent_find_server(void *s, const char *key, int key_len TSRMLS_DC) /* {{{ */ +{ + mmc_consistent_state_t *state = s; + mmc_t *mmc; + + if (state->num_servers > 1) { + unsigned int i, hash = state->hash(key, key_len); + + if (!state->buckets_populated) { + mmc_consistent_populate_buckets(state); + } + + mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS]; + + /* perform failover if needed */ + for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i<MEMCACHE_G(max_failover_attempts); i++) { + char *next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1); + int next_len = sprintf(next_key, "%s-%d", key, i); + MMC_DEBUG(("mmc_consistent_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status)); + + hash = state->hash(next_key, next_len); + mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS]; + + efree(next_key); + } + } + else { + mmc = state->points[0].server; + mmc_open(mmc, 0, NULL, NULL TSRMLS_CC); + } + + return mmc->status != MMC_STATUS_FAILED ? mmc : NULL; +} +/* }}} */ + +void mmc_consistent_add_server(void *s, mmc_t *mmc, unsigned int weight) /* {{{ */ +{ + mmc_consistent_state_t *state = s; + int i, key_len, points = weight * MMC_CONSISTENT_POINTS; + + /* buffer for "host:port-i\0" */ + char *key = emalloc(strlen(mmc->host) + MAX_LENGTH_OF_LONG * 2 + 3); + + /* add weight * MMC_CONSISTENT_POINTS number of points for this server */ + state->points = erealloc(state->points, sizeof(mmc_consistent_point_t) * (state->num_points + points)); + + for (i=0; i<points; i++) { + key_len = sprintf(key, "%s:%d-%d", mmc->host, mmc->port, i); + state->points[state->num_points + i].server = mmc; + state->points[state->num_points + i].point = state->hash(key, key_len); + MMC_DEBUG(("mmc_consistent_add_server: key %s, point %lu", key, state->points[state->num_points + i].point)); + } + + state->num_points += points; + state->num_servers++; + state->buckets_populated = 0; + + efree(key); +} +/* }}} */ + +mmc_hash_t mmc_consistent_hash = { + mmc_consistent_create_state, + mmc_consistent_free_state, + mmc_consistent_find_server, + mmc_consistent_add_server +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/memcache_queue.c ^ |
@@ -0,0 +1,130 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Antony Dovgal <tony@daylessday.org> | + | Mikael Johansson <mikael AT synd DOT info> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: memcache_queue.c 303929 2010-10-01 21:39:51Z rasmus $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "memcache_queue.h" + +void mmc_queue_push(mmc_queue_t *queue, void *ptr) { + if (mmc_queue_contains(queue, ptr)) return; + + if (queue->len >= queue->alloc) { + int increase = 1 + MMC_QUEUE_PREALLOC; + queue->alloc += increase; + queue->items = erealloc(queue->items, sizeof(*queue->items) * queue->alloc); + + /* move tail segment downwards */ + if (queue->head < queue->tail) { + memmove(queue->items + queue->tail + increase, queue->items + queue->tail, (queue->alloc - queue->tail - increase) * sizeof(*queue->items)); + queue->tail += increase; + } + } + + if (queue->len) { + queue->head++; + + if (queue->head >= queue->alloc) { + queue->head = 0; + } + } + + queue->items[queue->head] = ptr; + queue->len++; +} + +void *mmc_queue_pop(mmc_queue_t *queue) { + if (queue->len) { + void *ptr; + + ptr = queue->items[queue->tail]; + queue->len--; + + if (queue->len) { + queue->tail++; + + if (queue->tail >= queue->alloc) { + queue->tail = 0; + } + } + + return ptr; + } + return NULL; +} + +int mmc_queue_contains(mmc_queue_t *queue, void *ptr) { + if (queue != NULL) { + int i; + + for (i=0; i < queue->len; i++) { + if (mmc_queue_item(queue, i) == ptr) { + return 1; + } + } + } + + return 0; +} + +void mmc_queue_free(mmc_queue_t *queue) { + if (queue->items != NULL) { + efree(queue->items); + } + memset(queue, 0, sizeof(*queue)); +} + +void mmc_queue_copy(mmc_queue_t *source, mmc_queue_t *target) { + if (target->alloc != source->alloc) { + target->alloc = source->alloc; + erealloc(target->items, sizeof(*target->items) * target->alloc); + } + + memcpy(target->items, source->items, sizeof(*source->items) * source->alloc); + target->head = source->head; + target->tail = source->tail; + target->len = source->len; +} + +void mmc_queue_remove(mmc_queue_t *queue, void *ptr) { + void *item; + mmc_queue_t original = *queue; + mmc_queue_release(queue); + + while ((item = mmc_queue_pop(&original)) != NULL) { + if (item != ptr) { + mmc_queue_push(queue, item); + } + } + + mmc_queue_free(&original); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/memcache_queue.h ^ |
@@ -0,0 +1,56 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Antony Dovgal <tony@daylessday.org> | + | Mikael Johansson <mikael AT synd DOT info> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: memcache_queue.h 264971 2008-08-16 10:15:54Z tony2001 $ */ + +#ifndef MEMCACHE_QUEUE_H_ +#define MEMCACHE_QUEUE_H_ + +/* request / server stack */ +#define MMC_QUEUE_PREALLOC 25 + +typedef struct mmc_queue { + void **items; /* items on queue */ + int alloc; /* allocated size */ + int head; /* head index in ring buffer */ + int tail; /* tail index in ring buffer */ + int len; +} mmc_queue_t; + +#define mmc_queue_release(q) memset((q), 0, sizeof(*(q))) +#define mmc_queue_reset(q) (q)->len = (q)->head = (q)->tail = 0 +#define mmc_queue_item(q, i) ((q)->tail + (i) < (q)->alloc ? (q)->items[(q)->tail + (i)] : (q)->items[(i) - ((q)->alloc - (q)->tail)]) + +void mmc_queue_push(mmc_queue_t *, void *); +void *mmc_queue_pop(mmc_queue_t *); +int mmc_queue_contains(mmc_queue_t *, void *); +void mmc_queue_free(mmc_queue_t *); +void mmc_queue_copy(mmc_queue_t *, mmc_queue_t *); +void mmc_queue_remove(mmc_queue_t *, void *); + +#endif /*MEMCACHE_QUEUE_H_*/ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/memcache_session.c ^ |
@@ -0,0 +1,290 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Antony Dovgal <tony@daylessday.org> | + | Mikael Johansson <mikael AT synd DOT info> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: memcache_session.c 278743 2009-04-15 11:47:27Z felipe $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include "php.h" +#include "php_ini.h" +#include "php_variables.h" + +#include "SAPI.h" +#include "ext/standard/url.h" +#include "php_memcache.h" + +#if HAVE_MEMCACHE_SESSION +#include "ext/session/php_session.h" +#endif + +ps_module ps_mod_memcache = { + PS_MOD(memcache) +}; + +/* {{{ PS_OPEN_FUNC + */ +PS_OPEN_FUNC(memcache) +{ + mmc_pool_t *pool; + mmc_t *mmc; + + php_url *url; + zval *params, **param; + int i, j, path_len; + + pool = mmc_pool_new(TSRMLS_C); + + for (i=0,j=0,path_len=strlen(save_path); i<path_len; i=j+1) { + /* find beginning of url */ + while (i<path_len && (isspace(save_path[i]) || save_path[i] == ',')) + i++; + + /* find end of url */ + j = i; + while (j<path_len && !isspace(save_path[j]) && save_path[j] != ',') + j++; + + if (i < j) { + int persistent = 0, weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY; + + /* translate unix: into file: */ + if (!strncmp(save_path+i, "unix:", sizeof("unix:")-1)) { + int len = j-i; + char *path = estrndup(save_path+i, len); + memcpy(path, "file:", sizeof("file:")-1); + url = php_url_parse_ex(path, len); + efree(path); + } + else { + url = php_url_parse_ex(save_path+i, j-i); + } + + if (!url) { + char *path = estrndup(save_path+i, j-i); + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "Failed to parse session.save_path (error at offset %d, url was '%s')", i, path); + efree(path); + + mmc_pool_free(pool TSRMLS_CC); + PS_SET_MOD_DATA(NULL); + return FAILURE; + } + + /* parse parameters */ + if (url->query != NULL) { + MAKE_STD_ZVAL(params); + array_init(params); + + sapi_module.treat_data(PARSE_STRING, estrdup(url->query), params TSRMLS_CC); + + if (zend_hash_find(Z_ARRVAL_P(params), "persistent", sizeof("persistent"), (void **) ¶m) != FAILURE) { + convert_to_boolean_ex(param); + persistent = Z_BVAL_PP(param); + } + + if (zend_hash_find(Z_ARRVAL_P(params), "weight", sizeof("weight"), (void **) ¶m) != FAILURE) { + convert_to_long_ex(param); + weight = Z_LVAL_PP(param); + } + + if (zend_hash_find(Z_ARRVAL_P(params), "timeout", sizeof("timeout"), (void **) ¶m) != FAILURE) { + convert_to_long_ex(param); + timeout = Z_LVAL_PP(param); + } + + if (zend_hash_find(Z_ARRVAL_P(params), "retry_interval", sizeof("retry_interval"), (void **) ¶m) != FAILURE) { + convert_to_long_ex(param); + retry_interval = Z_LVAL_PP(param); + } + + zval_ptr_dtor(¶ms); + } + + if (url->scheme && url->path && !strcmp(url->scheme, "file")) { + char *host; + int host_len = spprintf(&host, 0, "unix://%s", url->path); + + /* chop off trailing :0 port specifier */ + if (!strcmp(host + host_len - 2, ":0")) { + host_len -= 2; + } + + if (persistent) { + mmc = mmc_find_persistent(host, host_len, 0, timeout, retry_interval TSRMLS_CC); + } + else { + mmc = mmc_server_new(host, host_len, 0, 0, timeout, retry_interval TSRMLS_CC); + } + + efree(host); + } + else { + if (url->host == NULL || weight <= 0 || timeout <= 0) { + php_url_free(url); + mmc_pool_free(pool TSRMLS_CC); + PS_SET_MOD_DATA(NULL); + return FAILURE; + } + + if (persistent) { + mmc = mmc_find_persistent(url->host, strlen(url->host), url->port, timeout, retry_interval TSRMLS_CC); + } + else { + mmc = mmc_server_new(url->host, strlen(url->host), url->port, 0, timeout, retry_interval TSRMLS_CC); + } + } + + mmc_pool_add(pool, mmc, weight); + php_url_free(url); + } + } + + if (pool->num_servers) { + PS_SET_MOD_DATA(pool); + return SUCCESS; + } + + mmc_pool_free(pool TSRMLS_CC); + PS_SET_MOD_DATA(NULL); + return FAILURE; +} +/* }}} */ + +/* {{{ PS_CLOSE_FUNC + */ +PS_CLOSE_FUNC(memcache) +{ + mmc_pool_t *pool = PS_GET_MOD_DATA(); + + if (pool) { + mmc_pool_free(pool TSRMLS_CC); + PS_SET_MOD_DATA(NULL); + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ PS_READ_FUNC + */ +PS_READ_FUNC(memcache) +{ + mmc_pool_t *pool = PS_GET_MOD_DATA(); + zval *result; + + if (pool) { + char key_tmp[MMC_KEY_MAX_SIZE]; + unsigned int key_tmp_len; + + if (mmc_prepare_key_ex(key, strlen(key), key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { + return FAILURE; + } + + MAKE_STD_ZVAL(result); + ZVAL_NULL(result); + + if (mmc_exec_retrieval_cmd(pool, key_tmp, key_tmp_len, &result, NULL TSRMLS_CC) <= 0 || Z_TYPE_P(result) != IS_STRING) { + zval_ptr_dtor(&result); + return FAILURE; + } + + *val = Z_STRVAL_P(result); + *vallen = Z_STRLEN_P(result); + FREE_ZVAL(result); + return SUCCESS; + } + + return FAILURE; +} +/* }}} */ + +/* {{{ PS_WRITE_FUNC + */ +PS_WRITE_FUNC(memcache) +{ + mmc_pool_t *pool = PS_GET_MOD_DATA(); + + if (pool) { + char key_tmp[MMC_KEY_MAX_SIZE]; + unsigned int key_tmp_len; + + if (mmc_prepare_key_ex(key, strlen(key), key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { + return FAILURE; + } + + if (mmc_pool_store(pool, "set", sizeof("set")-1, key_tmp, key_tmp_len, 0, INI_INT("session.gc_maxlifetime"), val, vallen TSRMLS_CC)) { + return SUCCESS; + } + } + + return FAILURE; +} +/* }}} */ + +/* {{{ PS_DESTROY_FUNC + */ +PS_DESTROY_FUNC(memcache) +{ + mmc_pool_t *pool = PS_GET_MOD_DATA(); + mmc_t *mmc; + + int result = -1; + + if (pool) { + char key_tmp[MMC_KEY_MAX_SIZE]; + unsigned int key_tmp_len; + + if (mmc_prepare_key_ex(key, strlen(key), key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { + return FAILURE; + } + + while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) { + if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, 0 TSRMLS_CC)) < 0) { + mmc_server_failure(mmc TSRMLS_CC); + } + } + + if (result >= 0) { + return SUCCESS; + } + } + + return FAILURE; +} +/* }}} */ + +/* {{{ PS_GC_FUNC + */ +PS_GC_FUNC(memcache) +{ + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/memcache_standard_hash.c ^ |
@@ -0,0 +1,132 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Antony Dovgal <tony@daylessday.org> | + | Mikael Johansson <mikael AT synd DOT info> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: memcache_standard_hash.c 264971 2008-08-16 10:15:54Z tony2001 $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_memcache.h" + +ZEND_EXTERN_MODULE_GLOBALS(memcache) + +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(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; +} +/* }}} */ + +void mmc_standard_free_state(void *s) /* {{{ */ +{ + mmc_standard_state_t *state = s; + if (state != NULL) { + if (state->buckets != NULL) { + efree(state->buckets); + } + efree(state); + } +} +/* }}} */ + +static unsigned int mmc_hash(mmc_standard_state_t *state, const char *key, int key_len) /* {{{ */ +{ + unsigned int hash = (state->hash(key, key_len) >> 16) & 0x7fff; + return hash ? hash : 1; +} +/* }}} */ + +mmc_t *mmc_standard_find_server(void *s, const char *key, int key_len TSRMLS_DC) /* {{{ */ +{ + mmc_standard_state_t *state = s; + mmc_t *mmc; + + if (state->num_servers > 1) { + unsigned int hash = mmc_hash(state, key, key_len), i; + mmc = state->buckets[hash % state->num_buckets]; + + /* perform failover if needed */ + for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i<MEMCACHE_G(max_failover_attempts); i++) { + char *next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1); + int next_len = sprintf(next_key, "%d%s", i+1, key); + MMC_DEBUG(("mmc_standard_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status)); + + hash += mmc_hash(state, next_key, next_len); + mmc = state->buckets[hash % state->num_buckets]; + + efree(next_key); + } + } + else { + mmc = state->buckets[0]; + mmc_open(mmc, 0, NULL, NULL TSRMLS_CC); + } + + return mmc->status != MMC_STATUS_FAILED ? mmc : NULL; +} +/* }}} */ + +void mmc_standard_add_server(void *s, mmc_t *mmc, unsigned int weight) /* {{{ */ +{ + mmc_standard_state_t *state = s; + int i; + + /* add weight number of buckets for this server */ + if (state->num_buckets) { + state->buckets = erealloc(state->buckets, sizeof(mmc_t *) * (state->num_buckets + weight)); + } + else { + state->buckets = emalloc(sizeof(mmc_t *) * (weight)); + } + + for (i=0; i<weight; i++) { + state->buckets[state->num_buckets + i] = mmc; + } + + state->num_buckets += weight; + state->num_servers++; +} +/* }}} */ + +mmc_hash_t mmc_standard_hash = { + mmc_standard_create_state, + mmc_standard_free_state, + mmc_standard_find_server, + mmc_standard_add_server +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Added | memcache-2.2.7.tgz/memcache-2.2.7/php_memcache.h ^ |
@@ -0,0 +1,235 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Antony Dovgal <tony@daylessday.org> | + | Mikael Johansson <mikael AT synd DOT info> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: php_memcache.h 323682 2012-03-01 00:04:17Z rasmus $ */ + +#ifndef PHP_MEMCACHE_H +#define PHP_MEMCACHE_H + +extern zend_module_entry memcache_module_entry; +#define phpext_memcache_ptr &memcache_module_entry + +#ifdef PHP_WIN32 +#define PHP_MEMCACHE_API __declspec(dllexport) +#else +#define PHP_MEMCACHE_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +#include "ext/standard/php_smart_str_public.h" + +PHP_MINIT_FUNCTION(memcache); +PHP_MSHUTDOWN_FUNCTION(memcache); +PHP_RINIT_FUNCTION(memcache); +PHP_MINFO_FUNCTION(memcache); + +PHP_FUNCTION(memcache_connect); +PHP_FUNCTION(memcache_pconnect); +PHP_FUNCTION(memcache_add_server); +PHP_FUNCTION(memcache_set_server_params); +PHP_FUNCTION(memcache_get_server_status); +PHP_FUNCTION(memcache_get_version); +PHP_FUNCTION(memcache_add); +PHP_FUNCTION(memcache_set); +PHP_FUNCTION(memcache_replace); +PHP_FUNCTION(memcache_get); +PHP_FUNCTION(memcache_delete); +PHP_FUNCTION(memcache_debug); +PHP_FUNCTION(memcache_get_stats); +PHP_FUNCTION(memcache_get_extended_stats); +PHP_FUNCTION(memcache_set_compress_threshold); +PHP_FUNCTION(memcache_increment); +PHP_FUNCTION(memcache_decrement); +PHP_FUNCTION(memcache_close); +PHP_FUNCTION(memcache_flush); +PHP_FUNCTION(memcache_setoptimeout); + +#define PHP_MEMCACHE_VERSION "2.2.7" + +#define MMC_BUF_SIZE 4096 +#define MMC_SERIALIZED 1 +#define MMC_COMPRESSED 2 +#define MMC_DEFAULT_TIMEOUT 1 /* seconds */ +#define MMC_KEY_MAX_SIZE 250 /* stoled from memcached sources =) */ +#define MMC_DEFAULT_RETRY 15 /* retry failed server after x seconds */ +#define MMC_DEFAULT_SAVINGS 0.2 /* minimum 20% savings for compression to be used */ +#define MMC_DEFAULT_CACHEDUMP_LIMIT 100 /* number of entries */ + +#define MMC_STATUS_FAILED 0 +#define MMC_STATUS_DISCONNECTED 1 +#define MMC_STATUS_UNKNOWN 2 +#define MMC_STATUS_CONNECTED 3 + +#define MMC_OK 0 +#define MMC_REQUEST_FAILURE -1 + +#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 */ + +typedef struct mmc { + php_stream *stream; + char inbuf[MMC_BUF_SIZE]; + smart_str outbuf; + char *host; + unsigned short port; + long timeout; + long timeoutms; /* takes precedence over timeout */ + long connect_timeoutms; /* takes precedence over timeout */ + long failed; + long retry_interval; + int persistent; + int status; + char *error; /* last error message */ + int errnum; /* last error code */ + zval *failure_callback; + zend_bool in_free; +} mmc_t; + +/* hashing strategy */ +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); + +#define mmc_pool_find(pool, key, key_len) \ + pool->hash->find_server(pool->hash_state, key, key_len) + +typedef struct mmc_hash { + mmc_hash_create_state create_state; + mmc_hash_free_state free_state; + mmc_hash_find_server find_server; + mmc_hash_add_server add_server; +} mmc_hash_t; + +/* 32 bit magic FNV-1a prime and init */ +#define FNV_32_PRIME 0x01000193 +#define FNV_32_INIT 0x811c9dc5 + +typedef struct mmc_pool { + mmc_t **servers; + int num_servers; + mmc_t **requests; + int compress_threshold; + double min_compress_savings; + zend_bool in_free; + mmc_hash_t *hash; + void *hash_state; +} mmc_pool_t; + +/* our globals */ +ZEND_BEGIN_MODULE_GLOBALS(memcache) + long debug_mode; + long default_port; + long num_persistent; + long compression_level; + long allow_failover; + long chunk_size; + long max_failover_attempts; + long hash_strategy; + long hash_function; + long default_timeout_ms; +ZEND_END_MODULE_GLOBALS(memcache) + +#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3) +# define MEMCACHE_IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp) TSRMLS_CC) +#else +# define MEMCACHE_IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp)) +#endif + +#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 4) +# define MEMCACHE_LIST_INSERT(item, list) zend_list_insert(item, list TSRMLS_CC); +#else +# define MEMCACHE_LIST_INSERT(item, list) zend_list_insert(item, list); +#endif + +/* internal functions */ +mmc_t *mmc_server_new(char *, int, unsigned short, int, int, int TSRMLS_DC); +mmc_t *mmc_find_persistent(char *, int, int, int, int TSRMLS_DC); +int mmc_server_failure(mmc_t * TSRMLS_DC); +void mmc_server_deactivate(mmc_t * TSRMLS_DC); + +int mmc_prepare_key(zval *, char *, unsigned int * TSRMLS_DC); +int mmc_prepare_key_ex(const char *, unsigned int, char *, unsigned int * TSRMLS_DC); + +mmc_pool_t *mmc_pool_new(TSRMLS_D); +void mmc_pool_free(mmc_pool_t * TSRMLS_DC); +void mmc_pool_add(mmc_pool_t *, mmc_t *, unsigned int); +int mmc_pool_store(mmc_pool_t *, const char *, int, const char *, int, int, int, const char *, int TSRMLS_DC); +int mmc_open(mmc_t *, int, char **, int * TSRMLS_DC); +int mmc_exec_retrieval_cmd(mmc_pool_t *, const char *, int, zval **, zval * TSRMLS_DC); +int mmc_delete(mmc_t *, const char *, int, int TSRMLS_DC); + +/* session handler struct */ +#if HAVE_MEMCACHE_SESSION +#include "ext/session/php_session.h" + +extern ps_module ps_mod_memcache; +#define ps_memcache_ptr &ps_mod_memcache + +PS_FUNCS(memcache); +#endif + +/* {{{ macros */ +#if ZEND_DEBUG + +void mmc_debug(const char *format, ...); + +#define MMC_DEBUG(info) \ +{\ + mmc_debug info; \ +}\ + +#else + +#define MMC_DEBUG(info) \ +{\ +}\ + +#endif +/* }}} */ + +#ifdef ZTS +#define MEMCACHE_G(v) TSRMG(memcache_globals_id, zend_memcache_globals *, v) +#else +#define MEMCACHE_G(v) (memcache_globals.v) +#endif + +#ifndef ZSTR +#define ZSTR +#endif + +#endif /* PHP_MEMCACHE_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Changed | memcache-2.2.7.tgz/package.xml ^ |
@@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<package packagerversion="1.7.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd"> +<package packagerversion="1.9.4" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd"> <name>memcache</name> <channel>pecl.php.net</channel> <summary>memcached extension</summary> @@ -20,36 +20,46 @@ <email>mikael@synd.info</email> <active>yes</active> </lead> - <date>2009-02-27</date> - <time>18:45:12</time> + <lead> + <name>Herman Radtke</name> + <user>hradtke</user> + <email>hradtke@php.net</email> + <active>yes</active> + </lead> + <date>2012-09-23</date> + <time>01:51:08</time> <version> - <release>2.2.5</release> - <api>2.2.5</api> + <release>2.2.7</release> + <api>2.2.7</api> </version> <stability> <release>stable</release> <api>stable</api> </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)</notes> + <notes> +- PHP 5.4 compatibility +- Fixed return value error get_host_port_from_server(). +- Fixed PECL Bug #16672 (memcache.php doesn't support unix socket) +- Fixed pecl bug #19374 (memcache.php throws Notice: Undefined index: VALUE when viewing expired items) + </notes> <contents> <dir name="/"> - <file md5sum="a35c3d4407a9f946e6ea8f26e75ef72b" name="config.m4" role="src" /> - <file md5sum="2775fadca560939d9c7fd23d2e7c879c" name="config9.m4" role="src" /> - <file md5sum="c682769a4b07803f4aa1b720f9405dc0" name="config.w32" role="src" /> + <file md5sum="d66273f5302ef861f5df379ef65d2744" name="config.m4" role="src" /> + <file md5sum="eccdb5e667a8b9cfb3e10546cbb18e75" name="config9.m4" role="src" /> + <file md5sum="abdff1cdc257531a30a8057d52e7e029" name="config.w32" role="src" /> <file md5sum="f818c8af5b84d8c936eca307b63aafec" name="CREDITS" role="doc" /> <file md5sum="5b6b03aebb60f141416489a527b2c9be" name="example.php" role="doc" /> - <file md5sum="11446147307e9ddaf295c8ec9246fdd6" name="memcache.c" role="src" /> - <file md5sum="0350aa61e87683e1792872dcfcd71adb" name="memcache_queue.c" role="src" /> - <file md5sum="3a5c09354b70e043bb1a488741229980" name="memcache_session.c" role="src" /> - <file md5sum="7c916d43ebdc89e0f652f16ca7aea0bb" name="memcache_standard_hash.c" role="src" /> - <file md5sum="2f5a52b45b7afe43b116b662a1cf1e64" name="memcache_consistent_hash.c" role="src" /> + <file md5sum="c65b20eb11e892a430dceaaa6694223a" name="memcache.c" role="src" /> + <file md5sum="08bcc27523479dd1cd79b0116116a30a" name="memcache_queue.c" role="src" /> + <file md5sum="a956b2a3834989ae5400b289289c7a2c" name="memcache_session.c" role="src" /> + <file md5sum="797a8c134e32d8730a09b14345176acb" name="memcache_standard_hash.c" role="src" /> + <file md5sum="1359bd655888b379c035b75f9909fafa" name="memcache_consistent_hash.c" role="src" /> <file md5sum="a0904f003d7ae14ff22c15fd0c417ceb" name="memcache.dsp" role="src" /> - <file md5sum="7c3938a3c084eaffa6dd9e0a8d8ae778" name="php_memcache.h" role="src" /> - <file md5sum="cb82650330e3fabd5706caaf7d17e959" name="memcache_queue.h" role="src" /> + <file md5sum="515fe1000ecf06cf0ebb7cfcd1e78e0a" name="php_memcache.h" role="src" /> + <file md5sum="041ef6076023d98abd357002ce0ee9e3" name="memcache_queue.h" role="src" /> <file md5sum="9b003fbed1a7f05c96154fb7b13fce2d" name="README" role="doc" /> - <file md5sum="ae6c0a18eabaae995ba84d915f7c404a" name="memcache.php" role="doc" /> + <file md5sum="11989aca389e375b3efae0a9438c0296" name="memcache.php" role="doc" /> </dir> </contents> <dependencies> @@ -68,6 +78,39 @@ </extsrcrelease> <changelog> <release> + <date>2010-10-03</date> + <version> + <release>2.2.6</release> + <api>2.2.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.php.net/license">PHP License</license> + <notes> +- Fixed pecl bug #16536 (Weight of 0 causes SegFault on memcache_add_server) +- Fixed pecl bug #17130 (Uninitialized tv.tv_usec causing PHP to loop endlessly) +- Fixed pecl bug #13623 (Memcache-client makes php segfault in semi-related code) + </notes> + </release> + <release> + <date>2009-02-27</date> + <version> + <release>2.2.5</release> + <api>2.2.5</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </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) + </notes> + </release> + <release> <date>2008-09-11</date> <version> <release>2.2.4</release> @@ -78,13 +121,15 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Added memcached stats script from Harun Yayli (http://livebookmark.net/memcachephp) + <notes> +- Added memcached stats script from Harun Yayli (http://livebookmark.net/memcachephp) - Fixed server weight not being used in the session handler - Fixed PECL bug #13343 (compilation breaks with CodeWarrior compiler) - Fixed PECL bug #13546 (Session handler through unix socket) - Fixed PECL bug #14239 (Memcache::set() modifies value parameter) - Fixed PECL request #13725 (unnecessary allocations in mmc_consistent_add_server) -- Changed behaviour when unserialize/uncompress fail to return false instead of failing the server</notes> +- Changed behaviour when unserialize/uncompress fail to return false instead of failing the server + </notes> </release> <release> <date>2008-02-05</date> @@ -97,9 +142,11 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Fixed PECL bug #12883 (Breaks UTF-8 in keys) + <notes> +- Fixed PECL bug #12883 (Breaks UTF-8 in keys) - Fixed PECL bug #13060 (make problems, due to role="doc" instead of role="src") -- Added package version to phpinfo()</notes> +- Added package version to phpinfo() + </notes> </release> <release> <date>2008-01-10</date> @@ -112,10 +159,12 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Fixed PECL bug 12494 (Segmentation fault when Exception thrown in the callback function) + <notes> +- Fixed PECL bug 12494 (Segmentation fault when Exception thrown in the callback function) - Fixed PECL bug #12834 (segfault when getting duplicate array values on 64-bit system) - Changed behaviour of close() to actually remove all servers from pool (PECL bug #12555) -- Added configure option for PEAR installer to disable session handler support</notes> +- Added configure option for PEAR installer to disable session handler support + </notes> </release> <release> <date>2007-11-01</date> @@ -128,10 +177,12 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Added argument to Memcache::get() that receives the flags for retrieved value(s) + <notes> +- Added argument to Memcache::get() that receives the flags for retrieved value(s) - Fixed PECL bug 11369 ("nested" get calls in __wakeup() functions breaks) - Fixed problem with keys being modified in-place and empty keys (PECL Bug #11236) -- Fixed incompatibility with standard hash strategy in previous versions</notes> +- Fixed incompatibility with standard hash strategy in previous versions + </notes> </release> <release> <date>2007-09-21</date> @@ -144,7 +195,8 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Added support for consistent hash strategy + <notes> +- Added support for consistent hash strategy - New INI directives "memcache.hash_strategy" = {standard, consistent} "memcache.hash_function" = {crc32, fnv} @@ -152,7 +204,8 @@ - Fixed PECL bug #11221 (Double free when returning cached object with __sleep) - Fixed PECL bug #10607 (Segfault on array key retrieval when array key is not IS_STRING) - Don't failover on "object to large" errors -- Use $phpincludedir for finding php_session.h</notes> +- Use $phpincludedir for finding php_session.h + </notes> </release> <release> <date>2007-03-27</date> @@ -165,7 +218,9 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Added missing files to the package.</notes> + <notes> +- Added missing files to the package. + </notes> </release> <release> <date>2007-03-27</date> @@ -178,9 +233,11 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Added experimental session storage support. You can use memcached as session storage. + <notes> +- Added experimental session storage support. You can use memcached as session storage. - Fixed PECL bug #9486 (empty keys should not be allowed in memcache_set/add()) -- Fixed PECL bug #9854 (get() changes the datatype of variable of given as key)</notes> +- Fixed PECL bug #9854 (get() changes the datatype of variable of given as key) + </notes> </release> <release> <date>2006-10-09</date> @@ -193,13 +250,15 @@ <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Servers may be flagged up/down and the user may specify a error callback + <notes> +- Servers may be flagged up/down and the user may specify a error callback - Individual server params and up/down status may be changed at runtime - New methods: setServerParams(), getServerStatus() - Statistics methods support fetching other kinds of stats (slabs, items, cachedump, ...) - Fixed PECL bugs #7631, #8117 (erroneous line feeds in config.m4) - Added memcache.max_failover_attempts ini directive, which can be used to configure max number of - servers to try when setting and getting data.</notes> + servers to try when setting and getting data. + </notes> </release> <release> <version> @@ -212,8 +271,10 @@ </stability> <date>2006-05-16</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Redefined retry_interval as long to fix no-automatic-reconnect behaviour - - Fixed PECL bugs #7635, #7637 (OnUpdateInt: referenced symbol not found)</notes> + <notes> +- Redefined retry_interval as long to fix no-automatic-reconnect behaviour + - Fixed PECL bugs #7635, #7637 (OnUpdateInt: referenced symbol not found) + </notes> </release> <release> <version> @@ -226,8 +287,10 @@ </stability> <date>2006-05-15</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Display ini entries in phpinfo() output - - Fixed Zend2 compat</notes> + <notes> +- Display ini entries in phpinfo() output + - Fixed Zend2 compat + </notes> </release> <release> <version> @@ -240,11 +303,13 @@ </stability> <date>2006-05-14</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Added "memcache.default_port" ini directive (default 11211) + <notes> +- Added "memcache.default_port" ini directive (default 11211) - Added "memcache.allow_failover" ini directive (default On) - Added "memcache.chunk_size" ini directive (default 8192 bytes) - Setting retry_interval parameter to -1 disables automatic reconnect -- Fixed PECL bug #7331 (NULL pointer freeing causes memcache to segfault)</notes> +- Fixed PECL bug #7331 (NULL pointer freeing causes memcache to segfault) + </notes> </release> <release> <version> @@ -257,11 +322,13 @@ </stability> <date>2006-02-01</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Fixed PECL bug #6595 (segfault in addServer()) + <notes> +- Fixed PECL bug #6595 (segfault in addServer()) - Fixed PECL bug #6512 (buffer overrun in getVersion()) - Fixed PECL bug #6460 (lacking include of php_smart_str_public.h) - Fixed PECL bug #6370 (incorrect failover on out-of-memory server errors) -- Improved zlib detection</notes> +- Improved zlib detection + </notes> </release> <release> <version> @@ -274,9 +341,11 @@ </stability> <date>2005-12-21</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Multiple servers with loadbalancing and failover + <notes> +- Multiple servers with loadbalancing and failover - Automatic compress threshold setting -- New methods: addServer(), getExtendedStats(), setCompressThreshold()</notes> +- New methods: addServer(), getExtendedStats(), setCompressThreshold() + </notes> </release> <release> <version> @@ -289,8 +358,10 @@ </stability> <date>2005-10-12</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>- Fixed minor leak appeared when connect fails. -- Fixed PECL bug #5626 (segfault when trying to use previously closed connection).</notes> + <notes> +- Fixed minor leak appeared when connect fails. +- Fixed PECL bug #5626 (segfault when trying to use previously closed connection). + </notes> </release> <release> <version> @@ -303,8 +374,10 @@ </stability> <date>2005-08-05</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>1) Fixed minor leak. -2) Class Memcache made inheritable.</notes> + <notes> +1) Fixed minor leak. +2) Class Memcache made inheritable. + </notes> </release> <release> <version> @@ -317,8 +390,10 @@ </stability> <date>2004-12-02</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>1) Added multi get support (i.e. you're now able to get multiple items with one get() call, -just pass array of keys to get() and it will return associative array of found items).</notes> + <notes> +1) Added multi get support (i.e. you're now able to get multiple items with one get() call, +just pass array of keys to get() and it will return associative array of found items). + </notes> </release> <release> <version> @@ -331,8 +406,10 @@ </stability> <date>2004-08-29</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>1) Fixed potential problem with empty datasets (yet another patch from Andrey Nigmatulin [anight at monamour dot ru]). -2) Fixed bug #2167 (thanks to [pbnadeau at gmail dot com] for noticing, testing and patching).</notes> + <notes> +1) Fixed potential problem with empty datasets (yet another patch from Andrey Nigmatulin [anight at monamour dot ru]). +2) Fixed bug #2167 (thanks to [pbnadeau at gmail dot com] for noticing, testing and patching). + </notes> </release> <release> <version> @@ -345,10 +422,12 @@ </stability> <date>2004-07-20</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>1) Fixed typo, preventing to use set() with flags and expire in the same time (thanks to Troy Hakala [troy at recipezaar dot com] for noticing). + <notes> +1) Fixed typo, preventing to use set() with flags and expire in the same time (thanks to Troy Hakala [troy at recipezaar dot com] for noticing). 2) Added possibility to store objects and arrays compressed. 3) Hopefully fixed all possible problems with persistent connections (thanks to [anight at monamour dot ru]). -4) Some uncritical impovements.</notes> +4) Some uncritical impovements. + </notes> </release> <release> <version> @@ -361,8 +440,10 @@ </stability> <date>2004-06-08</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>1) Fixed couple of possible segfaults and one error (many thanks to Anight). -2) Minor improvements.</notes> + <notes> +1) Fixed couple of possible segfaults and one error (many thanks to Anight). +2) Minor improvements. + </notes> </release> <release> <version> @@ -375,9 +456,11 @@ </stability> <date>2004-05-21</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>1) Ifdef'ed debug routines, so they are available only in debug mode. + <notes> +1) Ifdef'ed debug routines, so they are available only in debug mode. This should add more speed to extension. -2) Minor code decorations.</notes> +2) Minor code decorations. + </notes> </release> <release> <version> @@ -390,9 +473,11 @@ </stability> <date>2004-xx-xx</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>1) Added on-the-fly data (de)compression support. + <notes> +1) Added on-the-fly data (de)compression support. 2) Added procedural API. -3) Extension was fairly refactored and accelerated.</notes> +3) Extension was fairly refactored and accelerated. + </notes> </release> <release> <version> @@ -405,8 +490,10 @@ </stability> <date>2004-02-26</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>New methods: getStats(), increment(), decrement(). -Extension should be rather stable.</notes> + <notes> +New methods: getStats(), increment(), decrement(). +Extension should be rather stable. + </notes> </release> <release> <version> @@ -419,7 +506,9 @@ </stability> <date>2004-02-08</date> <license uri="http://www.php.net/license">PHP License</license> - <notes>Initial release in PECL</notes> + <notes> +Initial release in PECL + </notes> </release> </changelog> </package> |