[-]
[+]
|
Changed |
php5-pecl-memcache.changes
|
|
[-]
[+]
|
Changed |
php5-pecl-memcache.spec
^
|
|
[-]
[+]
|
Deleted |
memcache-3.0.1.tgz/memcache-3.0.1/README
^
|
@@ -1,130 +0,0 @@
-memcached module for PHP
-------------------------
-This module requires zlib library, used for on-the-fly data (de)compression.
-Also, you'll need memcached to use it =)
-
-The memcached website is here:
- http://www.danga.com/memcached/
-
-You will probably need libevent to install memcached:
-You can download it here: http://www.monkey.org/~provos/libevent/
-
-
-New API in 3.0
-------------------------
-
- Version 3 introduces a new class "MemcachePool" which implements the new API, the
- old class "Memcache" is still retained (but is deprecated) with the same interface
- for backwards compatibility. Please note that you need a new memcached version to
- use the CAS, default value to increment/decrement, append and prepend, and binary
- protocol features.
-
- New INI directives are available to allow control over protocol, redundancy and hash
- strategy selection. These are
-
- # The binary protocol results in less traffic and is more efficient
- # for the client and server to generate/parse
-
- memcache.protocol = {ascii, binary} # default ascii
-
- # When enabled the client sends requests to N servers in parallel, resulting in
- # a somewhat crude reduncancy or mirroring, suitable when used as a session
- # storage.
- #
- # If data integrity is of greater importance a real replicating memcached
- # backend such as "repcached" (http://sourceforge.net/projects/repcached/) is
- # recommended
-
- memcache.redundancy = <int> # default 1
- memcache.session_redundancy = <int> # default 2
-
- # Hash strategy and function selection. The consistent hashing strategy
- # is now the default as it allows servers to be added and removed from
- # the pool without resulting in all or most keys being re-mapped to
- # other server (ie. voiding the cache)
-
- memcache.hash_strategy = {standard, consistent} # default consistent
- memcache.hash_function = {crc32, fnv} # default crc32
-
-
- The directives are used by the MemcachePool constructor so you can instantiate
- several pools with different settings by using ini_set() creativly. For example
-
- ini_set('memcache.protocol', 'binary');
-
- $binarypool = new MemcachePool();
- $binarypool->addServer(...)
-
- ini_set('memcache.protocol', 'ascii');
- ini_set('memcache.redundancy', '2');
-
- $redundantpool = new MemcachePool();
- $redundantpool->addServer(...)
-
- ini_set('memcache.redundancy', '1');
-
-
- The new interface looks like
-
-class MemcachePool() {
- bool connect(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15)
- bool addServer(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15, bool status = true)
- bool setServerParams(string host, int tcp_port = 11211, int timeout = 1, int retry_interval = 15, bool status = true)
-
- /**
- * Supports fetching flags and CAS values
- */
- mixed get(mixed key, mixed &flags = null, mixed &cas = null)
-
- /**
- * Supports multi-set, for example
- * $memcache->set(array('key1' => 'val1', 'key2' => 'val1'), null, 0, 60)
- */
- bool add(mixed key, mixed var = null, int flag = 0, int exptime = 0)
- bool set(mixed key, mixed var = null, int flag = 0, int exptime = 0)
- bool replace(mixed key, mixed var = null, int flag = 0, int exptime = 0)
-
- /**
- * Compare-and-Swap, uses the CAS param from MemcachePool::get()
- */
- bool cas(mixed key, mixed var = null, int flag = 0, int exptime = 0, int cas = 0)
-
- /**
- * Prepends/appends a value to an existing one
- */
- bool append(mixed key, mixed var = null, int flag = 0, int exptime = 0)
- bool prepend(mixed key, mixed var = null, int flag = 0, int exptime = 0)
-
- /**
- * Supports multi-key operations, for example
- * $memcache->delete(array('key1', 'key2'))
- */
- bool delete(mixed key, int exptime = 0)
-
- /**
- * Supports multi-key operations, for example
- * $memcache->increment(array('key1', 'key2'), 1, 0, 0)
- *
- * The new defval (default value) and exptime (expiration time) are used
- * if the key doesn't already exist. They must be supplied (even if 0) for
- * this to be enabled.
- */
- mixed increment(mixed key, int value = 1, int defval = 0, int exptime = 0)
- mixed decrement(mixed key, int value = 1, int defval = 0, int exptime = 0)
-
- /**
- * Assigns a pool-specific failure callback which will be called when
- * a request fails. May be null in order to disable callbacks. The callback
- * receive arguments like
- *
- * function mycallback($host, $tcp_port, $udp_port, $error, $errnum)
- *
- * Where $host and $error are strings or null, the other params are integers.
- */
- bool setFailureCallback(function callback)
-}
-
-
-Maintainers:
-Mikael Johansson mikael at synd dot info
-Antony Dovgal tony2001 at phpclub dot net
|
[-]
[+]
|
Deleted |
memcache-3.0.1.tgz/memcache-3.0.1/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-3.0.1.tgz/memcache-3.0.1/config.w32
^
|
@@ -1,14 +0,0 @@
-// $Id: config.w32,v 1.6.2.2 2007/11/26 20:11: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_pool.c memcache_queue.c memcache_ascii_protocol.c memcache_binary_protocol.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-3.0.1.tgz/memcache-3.0.1/config9.m4
^
|
@@ -1,112 +0,0 @@
-dnl
-dnl $Id: config9.m4,v 1.3.2.7 2007/11/03 09:19:05 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_pool.c memcache_queue.c memcache_ascii_protocol.c memcache_binary_protocol.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_pool.c memcache_queue.c memcache_ascii_protocol.c memcache_binary_protocol.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-3.0.1.tgz/memcache-3.0.1/memcache.c
^
|
@@ -1,1882 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache.c,v 1.83.2.24 2008/02/05 19:59:42 mikl Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/standard/php_string.h"
-#include "php_memcache.h"
-
-#ifndef ZEND_ENGINE_2
-#define OnUpdateLong OnUpdateInt
-#endif
-
-/* True global resources - no need for thread safety here */
-static int le_memcache_pool, le_memcache_server;
-static zend_class_entry *memcache_pool_ce;
-static zend_class_entry *memcache_ce;
-
-ZEND_EXTERN_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_set_failure_callback, 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_cas, NULL)
- PHP_FE(memcache_append, NULL)
- PHP_FE(memcache_prepend, 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)
- {NULL, NULL, NULL}
-};
-
-static zend_function_entry php_memcache_pool_class_functions[] = {
- PHP_NAMED_FE(connect, zif_memcache_pool_connect, NULL)
- PHP_NAMED_FE(addserver, zif_memcache_pool_addserver, NULL)
- PHP_FALIAS(setserverparams, memcache_set_server_params, NULL)
- PHP_FALIAS(setfailurecallback, memcache_set_failure_callback, 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(cas, memcache_cas, NULL)
- PHP_FALIAS(append, memcache_append, NULL)
- PHP_FALIAS(prepend, memcache_prepend, 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)
- {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)
- {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),
- NULL,
- 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(OnUpdateProtocol) /* {{{ */
-{
- if (!strcasecmp(new_value, "ascii")) {
- MEMCACHE_G(protocol) = MMC_ASCII_PROTOCOL;
- }
- else if (!strcasecmp(new_value, "binary")) {
- MEMCACHE_G(protocol) = MMC_BINARY_PROTOCOL;
- }
- else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.protocol must be in set {ascii, binary} ('%s' given)", new_value);
- return FAILURE;
- }
-
- return SUCCESS;
-}
-/* }}} */
-
-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(OnUpdateRedundancy) /* {{{ */
-{
- long int lval;
-
- lval = strtol(new_value, NULL, 10);
- if (lval <= 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.redundancy 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);
-}
-/* }}} */
-
-/* {{{ 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", "32768", PHP_INI_ALL, OnUpdateChunkSize, chunk_size, zend_memcache_globals, memcache_globals)
- STD_PHP_INI_ENTRY("memcache.protocol", "ascii", PHP_INI_ALL, OnUpdateProtocol, protocol, zend_memcache_globals, memcache_globals)
- STD_PHP_INI_ENTRY("memcache.hash_strategy", "consistent", 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.redundancy", "1", PHP_INI_ALL, OnUpdateRedundancy, redundancy, zend_memcache_globals, memcache_globals)
- STD_PHP_INI_ENTRY("memcache.session_redundancy", "2", PHP_INI_ALL, OnUpdateRedundancy, session_redundancy, zend_memcache_globals, memcache_globals)
-PHP_INI_END()
-/* }}} */
-
-/* {{{ macros */
-#define MMC_PREPARE_KEY(key, key_len) \
- php_strtr(key, key_len, "\t\r\n ", "____", 4); \
-/* }}} */
-
-/* {{{ internal function protos */
-static void _mmc_pool_list_dtor(zend_rsrc_list_entry * TSRMLS_DC);
-static void _mmc_server_list_dtor(zend_rsrc_list_entry * TSRMLS_DC);
-static void php_mmc_set_failure_callback(mmc_pool_t *, zval *, zval * TSRMLS_DC);
-static void php_mmc_failure_callback(mmc_pool_t *, mmc_t *, void * TSRMLS_DC);
-/* }}} */
-
-/* {{{ php_memcache_init_globals()
-*/
-static void php_memcache_init_globals(zend_memcache_globals *memcache_globals_p TSRMLS_DC)
-{
- MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH;
- MEMCACHE_G(hash_function) = MMC_HASH_CRC32;
-}
-/* }}} */
-
-/* {{{ PHP_MINIT_FUNCTION
- */
-PHP_MINIT_FUNCTION(memcache)
-{
- zend_class_entry ce;
-
- INIT_CLASS_ENTRY(ce, "MemcachePool", php_memcache_pool_class_functions);
- memcache_pool_ce = zend_register_internal_class(&ce TSRMLS_CC);
-
- INIT_CLASS_ENTRY(ce, "Memcache", php_memcache_class_functions);
- memcache_ce = zend_register_internal_class_ex(&ce, memcache_pool_ce, NULL TSRMLS_CC);
-
- le_memcache_pool = zend_register_list_destructors_ex(_mmc_pool_list_dtor, NULL, "memcache connection", module_number);
- le_memcache_server = zend_register_list_destructors_ex(NULL, _mmc_server_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_MINFO_FUNCTION
- */
-PHP_MINFO_FUNCTION(memcache)
-{
- php_info_print_table_start();
- php_info_print_table_header(2, "memcache support", "enabled");
- php_info_print_table_row(2, "Version", PHP_MEMCACHE_VERSION);
- php_info_print_table_row(2, "Revision", "$Revision: 1.83.2.24 $");
- php_info_print_table_end();
-
- DISPLAY_INI_ENTRIES();
-}
-/* }}} */
-
-/* ------------------
- internal functions
- ------------------ */
-
-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_server_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
-{
- mmc_server_free((mmc_t *)rsrc->ptr TSRMLS_CC);
-}
-/* }}} */
-
-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, "Failed to extract 'connection' variable from object");
- 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, "Unknown connection identifier");
- return 0;
- }
-
- return Z_LVAL_PP(connection);
-}
-/* }}} */
-
-int mmc_stored_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- handles SET/ADD/REPLACE response, param is a zval pointer to store result into {{{ */
-{
- if (response == MMC_OK) {
- if (param != NULL && Z_TYPE_P((zval *)param) == IS_NULL) {
- ZVAL_TRUE((zval *)param);
- }
- return MMC_REQUEST_DONE;
- }
-
- /* return FALSE or catch memory errors without failover */
- if (response == MMC_RESPONSE_EXISTS || response == MMC_RESPONSE_OUT_OF_MEMORY || response == MMC_RESPONSE_TOO_LARGE) {
- if (param != NULL) {
- ZVAL_FALSE((zval *)param);
- }
- return MMC_REQUEST_DONE;
- }
-
- return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
-}
-/* }}} */
-
-static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, int op) /* {{{ */
-{
- mmc_pool_t *pool;
- mmc_request_t *request;
- zval *keys, *value, *mmc_object = getThis();
- long flags = 0, exptime = 0, cas = 0;
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zlll", &mmc_object, memcache_pool_ce, &keys, &value, &flags, &exptime, &cas) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|zlll", &keys, &value, &flags, &exptime, &cas) == FAILURE) {
- return;
- }
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
- RETURN_FALSE;
- }
-
- RETVAL_NULL();
-
- if (Z_TYPE_P(keys) == IS_ARRAY) {
- zstr key;
- char keytmp[MAX_LENGTH_OF_LONG + 1];
- unsigned int key_len;
- unsigned long index;
- int key_type;
-
- zval **arrval;
- HashPosition pos;
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
-
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&arrval, &pos) == SUCCESS) {
- key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(keys), &key, &key_len, &index, 0, &pos);
- zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
-
- switch (key_type) {
- case HASH_KEY_IS_STRING:
- key_len--;
- break;
-
- case HASH_KEY_IS_LONG:
- key_len = sprintf(keytmp, "%lu", index);
- key = ZSTR(keytmp);
- break;
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
- continue;
- }
-
- /* allocate request */
- if (return_value_used) {
- request = mmc_pool_request(pool, MMC_PROTO_TCP,
- mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
- }
- else {
- request = mmc_pool_request(pool, MMC_PROTO_TCP,
- mmc_stored_handler, NULL, mmc_pool_failover_handler, NULL TSRMLS_CC);
- }
-
- if (mmc_prepare_key_ex(ZSTR_VAL(key), key_len, request->key, &(request->key_len)) != MMC_OK) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
- mmc_pool_release(pool, request);
- continue;
- }
-
- /* assemble command */
- if (pool->protocol->store(pool, request, op, ZSTR_VAL(key), key_len, flags, exptime, cas, *arrval TSRMLS_CC) != MMC_OK) {
- mmc_pool_release(pool, request);
- continue;
- }
-
- /* schedule request */
- if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
- continue;
- }
-
- /* begin sending requests immediatly */
- mmc_pool_select(pool, 0 TSRMLS_CC);
- }
- }
- else {
- /* allocate request */
- request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
-
- if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
- mmc_pool_release(pool, request);
- RETURN_FALSE;
- }
-
- /* assemble command */
- if (pool->protocol->store(pool, request, op, request->key, request->key_len, flags, exptime, cas, value TSRMLS_CC) != MMC_OK) {
- mmc_pool_release(pool, request);
- RETURN_FALSE;
- }
-
- /* schedule request */
- if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
- RETURN_FALSE;
- }
- }
-
- /* execute all requests */
- mmc_pool_run(pool TSRMLS_CC);
-
- if (Z_TYPE_P(return_value) == IS_NULL) {
- RETVAL_FALSE;
- }
-}
-/* }}} */
-
-static int mmc_deleted_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- parses a DELETED response line, param is a zval pointer to store result into {{{ */
-{
- if (response == MMC_OK) {
- if (param != NULL && Z_TYPE_P((zval *)param) == IS_NULL) {
- ZVAL_TRUE((zval *)param);
- }
- return MMC_REQUEST_DONE;
- }
-
- if (response == MMC_RESPONSE_NOT_FOUND) {
- if (param != NULL) {
- ZVAL_FALSE((zval *)param);
- }
- return MMC_REQUEST_DONE;
- }
-
- return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
-}
-/* }}} */
-
-static int mmc_numeric_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- parses a numeric response line, param is a zval pointer to store result into {{{ */
-{
- /* must contain digit(s) */
- if (message_len < 1) {
- return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
- }
-
- /* append return value to result array */
- if (param != NULL) {
- if (Z_TYPE_P((zval *)param) == IS_NULL) {
- array_init((zval *)param);
- }
-
- if (Z_TYPE_P((zval *)param) == IS_ARRAY) {
- zval *result;
- MAKE_STD_ZVAL(result);
- ZVAL_LONG(result, atol(message));
- add_assoc_zval_ex((zval *)param, request->key, request->key_len + 1, result);
- }
- else {
- ZVAL_LONG((zval *)param, atol(message));
- }
- }
-
- return MMC_REQUEST_DONE;
-}
-/* }}} */
-
-static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int invert) /*
- sends one or several commands which have a single optional numeric parameter (incr, decr, delete) {{{ */
-{
- mmc_pool_t *pool;
- zval *mmc_object = getThis();
-
- zval *keys;
- long value = 1, defval = 0, exptime = 0;
- mmc_request_t *request;
- mmc_request_response_handler response_handler;
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|lll", &mmc_object, memcache_pool_ce, &keys, &value, &defval, &exptime) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|lll", &keys, &value, &defval, &exptime) == FAILURE) {
- return;
- }
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
- RETURN_FALSE;
- }
-
- if (deleted) {
- response_handler = mmc_deleted_handler;
- }
- else {
- response_handler = mmc_numeric_handler;
- }
-
- if (Z_TYPE_P(keys) == IS_ARRAY) {
- zval **key;
- HashPosition pos;
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
-
- RETVAL_NULL();
-
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
- zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
-
- /* allocate request */
- if (return_value_used) {
- request = mmc_pool_request(
- pool, MMC_PROTO_TCP, response_handler, return_value,
- mmc_pool_failover_handler, NULL TSRMLS_CC);
- }
- else {
- request = mmc_pool_request(
- pool, MMC_PROTO_TCP, response_handler, NULL,
- mmc_pool_failover_handler, NULL TSRMLS_CC);
- }
-
- if (mmc_prepare_key(*key, request->key, &(request->key_len)) != MMC_OK) {
- mmc_pool_release(pool, request);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
- continue;
- }
-
- if (deleted) {
- pool->protocol->delete(request, request->key, request->key_len, value);
- }
- else {
- pool->protocol->mutate(request, request->key, request->key_len, invert ? -value : value, defval, exptime);
- }
-
- /* schedule request */
- if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
- continue;
- }
-
- /* begin sending requests immediatly */
- mmc_pool_select(pool, 0 TSRMLS_CC);
- }
- }
- else {
- if (deleted) {
- RETVAL_NULL();
- }
- else {
- RETVAL_FALSE;
- }
-
- /* allocate request */
- request = mmc_pool_request(pool, MMC_PROTO_TCP,
- response_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
-
- if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
- mmc_pool_release(pool, request);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
- RETURN_FALSE;
- }
-
- if (deleted) {
- pool->protocol->delete(request, request->key, request->key_len, value);
- }
- else {
- pool->protocol->mutate(request, request->key, request->key_len, invert ? -value : value, defval, exptime);
- }
-
- /* schedule request */
- if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
- RETURN_FALSE;
- }
- }
-
- /* execute all requests */
- mmc_pool_run(pool TSRMLS_CC);
-}
-/* }}} */
-
-mmc_t *mmc_find_persistent(const char *host, int host_len, unsigned short port, unsigned short udp_port, int timeout, int retry_interval TSRMLS_DC) /* {{{ */
-{
- mmc_t *mmc;
- zend_rsrc_list_entry *le;
- char *key;
- int key_len;
-
- key_len = spprintf(&key, 0, "memcache:server:%s:%u:%u", host, port, udp_port);
-
- if (zend_hash_find(&EG(persistent_list), key, key_len+1, (void **)&le) == FAILURE) {
- zend_rsrc_list_entry new_le;
-
- mmc = mmc_server_new(host, host_len, port, udp_port, 1, timeout, retry_interval TSRMLS_CC);
- new_le.type = le_memcache_server;
- new_le.ptr = mmc;
-
- /* register new persistent connection */
- if (zend_hash_update(&EG(persistent_list), key, 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_memcache_server);
- }
- }
- else if (le->type != le_memcache_server || le->ptr == NULL) {
- zend_rsrc_list_entry new_le;
- zend_hash_del(&EG(persistent_list), key, key_len+1);
-
- mmc = mmc_server_new(host, host_len, port, udp_port, 1, timeout, retry_interval TSRMLS_CC);
- new_le.type = le_memcache_server;
- new_le.ptr = mmc;
-
- /* register new persistent connection */
- if (zend_hash_update(&EG(persistent_list), key, 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_memcache_server);
- }
- }
- else {
- mmc = (mmc_t *)le->ptr;
- mmc->timeout = timeout;
- mmc->tcp.retry_interval = retry_interval;
-
- /* attempt to reconnect this node before failover in case connection has gone away */
- if (mmc->tcp.status == MMC_STATUS_CONNECTED) {
- mmc->tcp.status = MMC_STATUS_UNKNOWN;
- }
- if (mmc->udp.status == MMC_STATUS_CONNECTED) {
- mmc->udp.status = MMC_STATUS_UNKNOWN;
- }
- }
-
- efree(key);
- return mmc;
-}
-/* }}} */
-
-static mmc_t *php_mmc_pool_addserver(
- zval *mmc_object, const char *host, int host_len, long tcp_port, long udp_port, long weight,
- zend_bool persistent, long timeout, long retry_interval, zend_bool status, mmc_pool_t **pool_result TSRMLS_DC) /* {{{ */
-{
- zval **connection;
- mmc_pool_t *pool;
- mmc_t *mmc;
- int list_id, resource_type;
-
- if (weight < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "weight must be a positive integer");
- return NULL;
- }
-
- /* lazy initialization of server struct */
- if (persistent && status) {
- mmc = mmc_find_persistent(host, host_len, tcp_port, udp_port, timeout, retry_interval TSRMLS_CC);
- }
- else {
- mmc = mmc_server_new(host, host_len, tcp_port, udp_port, 0, timeout, retry_interval TSRMLS_CC);
- }
-
- /* add server in failed mode */
- if (!status) {
- mmc->tcp.status = MMC_STATUS_FAILED;
- mmc->udp.status = MMC_STATUS_FAILED;
- }
-
- /* 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);
- pool->failure_callback = &php_mmc_failure_callback;
- 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, "Unknown connection identifier");
- return NULL;
- }
- }
-
- mmc_pool_add(pool, mmc, weight);
-
- if (pool_result != NULL) {
- *pool_result = pool;
- }
-
- return mmc;
-}
-/* }}} */
-
-static void php_mmc_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool persistent) /* {{{ */
-{
- zval *mmc_object = getThis();
- mmc_pool_t *pool;
- mmc_t *mmc;
-
- char *host;
- int host_len;
- long tcp_port = MEMCACHE_G(default_port), timeout = MMC_DEFAULT_TIMEOUT;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &host, &host_len, &tcp_port, &timeout) == FAILURE) {
- return;
- }
-
- /* initialize pool and object if need be */
- if (!mmc_object) {
- int list_id;
- mmc_pool_t *pool = mmc_pool_new(TSRMLS_C);
- pool->failure_callback = &php_mmc_failure_callback;
- list_id = zend_list_insert(pool, le_memcache_pool);
- mmc_object = return_value;
- object_init_ex(mmc_object, memcache_ce);
- add_property_resource(mmc_object, "connection", list_id);
- }
- else {
- RETVAL_TRUE;
- }
-
- mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, 0, 1, persistent, timeout, MMC_DEFAULT_RETRY, 1, NULL TSRMLS_CC);
- if (mmc == NULL) {
- RETURN_FALSE;
- }
-
- /* force a reconnect attempt if stream EOF */
- if (mmc->tcp.stream != NULL && php_stream_eof(mmc->tcp.stream)) {
- mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
- RETURN_FALSE;
- }
-
- /* force a tcp connect (if not persistently connected) */
- if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) != MMC_OK) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%d, %s (%d)", host, mmc->tcp.port, mmc->error ? mmc->error : "Unknown error", mmc->errnum);
- RETURN_FALSE;
- }
-}
-/* }}} */
-
-/*
- * 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;
-
- if (Z_TYPE_P(result) != IS_ARRAY) {
- array_init(result);
- }
-
- /* 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;
-
- if (Z_TYPE_P(result) != IS_ARRAY) {
- array_init(result);
- }
-
- /* 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;
-
- if (Z_TYPE_P(result) != IS_ARRAY) {
- array_init(result);
- }
-
- 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);
- }
- }
- else {
- return 0;
- }
-
- return 1;
-}
-/* }}} */
-
-static void php_mmc_failure_callback(mmc_pool_t *pool, mmc_t *mmc, void *param TSRMLS_DC) /* {{{ */
-{
- zval **callback;
-
- /* check for userspace callback */
- if (param != NULL && zend_hash_find(Z_OBJPROP_P((zval *)param), "_failureCallback", sizeof("_failureCallback"), (void **)&callback) == SUCCESS && Z_TYPE_PP(callback) != IS_NULL) {
- if (zend_is_callable(*callback, 0, NULL)) {
- zval *retval = NULL;
- zval *host, *tcp_port, *udp_port, *error, *errnum;
- zval **params[5] = {&host, &tcp_port, &udp_port, &error, &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->tcp.port); ZVAL_LONG(udp_port, mmc->udp.port);
-
- 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, *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_mmc_set_failure_callback(pool, (zval *)param, NULL TSRMLS_CC);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
- }
- }
- else {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d, udp %d) failed with: %s (%d)",
- mmc->host, mmc->tcp.port, mmc->udp.port, mmc->error, mmc->errnum);
- }
-}
-/* }}} */
-
-static void php_mmc_set_failure_callback(mmc_pool_t *pool, zval *mmc_object, zval *callback TSRMLS_DC) /* {{{ */
-{
- if (callback != NULL) {
- zval *callback_tmp;
- ALLOC_ZVAL(callback_tmp);
-
- *callback_tmp = *callback;
- zval_copy_ctor(callback_tmp);
- INIT_PZVAL(callback_tmp);
-
- add_property_zval(mmc_object, "_failureCallback", callback_tmp);
- pool->failure_callback_param = mmc_object;
-
- INIT_PZVAL(callback_tmp);
- }
- else {
- add_property_null(mmc_object, "_failureCallback");
- pool->failure_callback_param = NULL;
- }
-}
-/* }}} */
-
-/* ----------------
- module functions
- ---------------- */
-
-/* {{{ proto bool MemcachePool::connect(string host [, int tcp_port [, int udp_port [, bool persistent [, int weight [, int timeout [, int retry_interval] ] ] ] ] ])
- Connects to server and returns a Memcache object */
-PHP_NAMED_FUNCTION(zif_memcache_pool_connect)
-{
- zval *mmc_object = getThis();
- mmc_pool_t *pool;
- mmc_t *mmc;
-
- char *host;
- int host_len;
- long tcp_port = MEMCACHE_G(default_port), udp_port = 0, weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY;
- zend_bool persistent = 1;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|llblll",
- &host, &host_len, &tcp_port, &udp_port, &persistent, &weight, &timeout, &retry_interval) == FAILURE) {
- return;
- }
-
- mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, udp_port, weight, persistent, timeout, retry_interval, 1, NULL TSRMLS_CC);
- if (mmc == NULL) {
- RETURN_FALSE;
- }
-
- /* force a reconnect attempt if stream EOF */
- if (mmc->tcp.stream != NULL && php_stream_eof(mmc->tcp.stream)) {
- mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
- RETURN_FALSE;
- }
-
- /* force a tcp connect (if not persistently connected) */
- if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) != MMC_OK) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%d, %s (%d)", host, mmc->tcp.port, mmc->error ? mmc->error : "Unknown error", mmc->errnum);
- RETURN_FALSE;
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ 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 MemcachePool::addServer(string host [, int tcp_port [, int udp_port [, bool persistent [, int weight [, int timeout [, int retry_interval [, bool status] ] ] ] ])
- Adds a server to the pool */
-PHP_NAMED_FUNCTION(zif_memcache_pool_addserver)
-{
- zval *mmc_object = getThis();
- mmc_t *mmc;
-
- char *host;
- int host_len;
- long tcp_port = MEMCACHE_G(default_port), udp_port = 0, weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY;
- zend_bool persistent = 1, status = 1;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|llblllb",
- &host, &host_len, &tcp_port, &udp_port, &persistent, &weight, &timeout, &retry_interval, &status) == FAILURE) {
- return;
- }
-
- mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, udp_port, weight, persistent, timeout, retry_interval, status, NULL TSRMLS_CC);
- if (mmc == NULL) {
- RETURN_FALSE;
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ 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 *mmc_object = getThis(), *failure_callback = NULL;
- mmc_pool_t *pool;
- mmc_t *mmc;
-
- char *host;
- int host_len;
- long tcp_port = MEMCACHE_G(default_port), weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY;
- zend_bool persistent = 1, status = 1;
-
- if (mmc_object) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lblllbz",
- &host, &host_len, &tcp_port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lblllbz", &mmc_object, memcache_ce,
- &host, &host_len, &tcp_port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
- return;
- }
- }
-
- if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) {
- if (!zend_is_callable(failure_callback, 0, NULL)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
- RETURN_FALSE;
- }
- }
-
- mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, 0, weight, persistent, timeout, retry_interval, status, &pool TSRMLS_CC);
- if (mmc == NULL) {
- RETURN_FALSE;
- }
-
- if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) {
- php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
- }
-
- 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 tcp_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, &tcp_port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lllbz", &mmc_object, memcache_pool_ce,
- &host, &host_len, &tcp_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]->tcp.port == tcp_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 (!zend_is_callable(failure_callback, 0, NULL)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
- RETURN_FALSE;
- }
- }
-
- mmc->timeout = timeout;
- mmc->tcp.retry_interval = retry_interval;
-
- if (!status) {
- mmc->tcp.status = MMC_STATUS_FAILED;
- mmc->udp.status = MMC_STATUS_FAILED;
- }
- else {
- if (mmc->tcp.status == MMC_STATUS_FAILED) {
- mmc->tcp.status = MMC_STATUS_DISCONNECTED;
- }
- if (mmc->udp.status == MMC_STATUS_FAILED) {
- mmc->udp.status = MMC_STATUS_DISCONNECTED;
- }
- }
-
- if (failure_callback != NULL) {
- if (Z_TYPE_P(failure_callback) != IS_NULL) {
- php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
- }
- else {
- php_mmc_set_failure_callback(pool, mmc_object, NULL TSRMLS_CC);
- }
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool memcache_set_failure_callback( callback failure_callback )
- Changes the failover callback */
-PHP_FUNCTION(memcache_set_failure_callback)
-{
- zval *mmc_object = getThis(), *failure_callback;
- mmc_pool_t *pool;
-
- if (mmc_object) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",
- &failure_callback) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz", &mmc_object, memcache_pool_ce,
- &failure_callback) == FAILURE) {
- return;
- }
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
- RETURN_FALSE;
- }
-
- if (Z_TYPE_P(failure_callback) != IS_NULL) {
- if (!zend_is_callable(failure_callback, 0, NULL)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
- RETURN_FALSE;
- }
- }
-
- if (Z_TYPE_P(failure_callback) != IS_NULL) {
- php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
- }
- else {
- php_mmc_set_failure_callback(pool, mmc_object, NULL TSRMLS_CC);
- }
-
- 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 tcp_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, &tcp_port) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_pool_ce, &host, &host_len, &tcp_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]->tcp.port == tcp_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->tcp.status > MMC_STATUS_FAILED ? 1 : 0);
-}
-/* }}} */
-
-static int mmc_version_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- parses the VERSION response line, param is a zval pointer to store version into {{{ */
-{
- if (response != MMC_RESPONSE_ERROR) {
- char *version = emalloc(message_len + 1);
-
- if (sscanf(message, "VERSION %s", version) == 1) {
- ZVAL_STRING((zval *)param, version, 0);
- }
- else {
- efree(version);
- ZVAL_STRINGL((zval *)param, (char *)message, message_len, 1);
- }
-
- return MMC_REQUEST_DONE;
- }
-
- return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ proto string memcache_get_version( object memcache )
- Returns server's version */
-PHP_FUNCTION(memcache_get_version)
-{
- mmc_pool_t *pool;
- zval *mmc_object = getThis();
- int i;
- mmc_request_t *request;
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_pool_ce) == FAILURE) {
- return;
- }
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
- RETURN_FALSE;
- }
-
- RETVAL_FALSE;
- for (i=0; i<pool->num_servers; i++) {
- /* run command and check for valid return value */
- request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_version_handler, return_value, NULL, NULL TSRMLS_CC);
- pool->protocol->version(request);
-
- if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
- mmc_pool_run(pool TSRMLS_CC);
-
- if (Z_TYPE_P(return_value) == IS_STRING) {
- break;
- }
- }
- }
-}
-/* }}} */
-
-/* {{{ proto bool memcache_add(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
- Adds new item. Item with such key should not exist. */
-PHP_FUNCTION(memcache_add)
-{
- php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_ADD);
-}
-/* }}} */
-
-/* {{{ proto bool memcache_set(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
- Sets the value of an item. Item may exist or not */
-PHP_FUNCTION(memcache_set)
-{
- php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_SET);
-}
-/* }}} */
-
-/* {{{ proto bool memcache_replace(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] )
- Replaces existing item. Returns false if item doesn't exist */
-PHP_FUNCTION(memcache_replace)
-{
- php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_REPLACE);
-}
-/* }}} */
-
-/* {{{ proto bool memcache_cas(object memcache, mixed key [, mixed var [, int flag [, int exptime [, long cas ] ] ] ])
- Sets the value of an item if the CAS value is the same (Compare-And-Swap) */
-PHP_FUNCTION(memcache_cas)
-{
- php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_CAS);
-}
-/* }}} */
-
-/* {{{ proto bool memcache_prepend(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
- Appends a value to the stored value, value must exist */
-PHP_FUNCTION(memcache_append)
-{
- php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_APPEND);
-}
-/* }}} */
-
-/* {{{ proto bool memcache_prepend(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
- Prepends a value to the stored value, value must exist */
-PHP_FUNCTION(memcache_prepend)
-{
- php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_PREPEND);
-}
-/* }}} */
-
-static int mmc_value_handler_multi(
- const char *key, unsigned int key_len, void *value, unsigned int value_len,
- unsigned int flags, unsigned long cas, void *param TSRMLS_DC) /*
- receives a multiple values, param is a zval** array to store value and flags in {{{ */
-{
- zval *arrval, **result = (zval **)param;
- ALLOC_ZVAL(arrval);
- *((zval *)arrval) = *((zval *)value);
-
- /* add value to result */
- if (Z_TYPE_P(result[0]) != IS_ARRAY) {
- array_init(result[0]);
- }
- add_assoc_zval_ex(result[0], (char *)key, key_len + 1, arrval);
-
- /* add flags to result */
- if (result[1] != NULL) {
- if (Z_TYPE_P(result[1]) != IS_ARRAY) {
- array_init(result[1]);
- }
- add_assoc_long_ex(result[1], (char *)key, key_len + 1, flags);
- }
-
- /* add CAS value to result */
- if (result[2] != NULL) {
- if (Z_TYPE_P(result[2]) != IS_ARRAY) {
- array_init(result[2]);
- }
- add_assoc_long_ex(result[2], (char *)key, key_len + 1, cas);
- }
-
- /* request more data (more values or END line) */
- return MMC_REQUEST_AGAIN;
-}
-/* }}} */
-
-int mmc_value_handler_single(
- const char *key, unsigned int key_len, void *value, unsigned int value_len,
- unsigned int flags, unsigned long cas, void *param TSRMLS_DC) /*
- receives a single value, param is a zval pointer to store value to {{{ */
-{
- zval **result = (zval **)param;
- *(result[0]) = *((zval *)value);
-
- if (result[1] != NULL) {
- ZVAL_LONG(result[1], flags);
- }
-
- if (result[2] != NULL) {
- ZVAL_LONG(result[2], cas);
- }
-
- /* request more data (END line) */
- return MMC_REQUEST_AGAIN;
-}
-/* }}} */
-
-static int mmc_value_failover_handler(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC) /*
- uses keys and return value to reschedule requests to other servers, param is a zval ** pointer {{{ */
-{
- zval **key, *keys = ((zval **)param)[0], **value_handler_param = (zval **)((void **)param)[1];
- HashPosition pos;
-
- if (!MEMCACHE_G(allow_failover) || request->failed_servers.len >= MEMCACHE_G(max_failover_attempts)) {
- mmc_pool_release(pool, request);
- return MMC_REQUEST_FAILURE;
- }
-
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
-
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
- zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
-
- /* re-schedule key if it does not exist in return value array */
- if (Z_TYPE_P(value_handler_param[0]) != IS_ARRAY ||
- !zend_hash_exists(Z_ARRVAL_P(value_handler_param[0]), Z_STRVAL_PP(key), Z_STRLEN_PP(key) + 1))
- {
- mmc_pool_schedule_get(pool, MMC_PROTO_UDP,
- value_handler_param[2] != NULL ? MMC_OP_GETS : MMC_OP_GET, *key,
- request->value_handler, request->value_handler_param,
- request->failover_handler, request->failover_handler_param, request TSRMLS_CC);
- }
- }
-
- mmc_pool_release(pool, request);
- return MMC_OK;
-}
-/* }}}*/
-
-/* {{{ proto mixed memcache_get( object memcache, mixed key [, mixed &flags [, mixed &cas ] ] )
- Returns value of existing item or false */
-PHP_FUNCTION(memcache_get)
-{
- mmc_pool_t *pool;
- zval *keys, *flags = NULL, *cas = NULL, *mmc_object = getThis();
- void *value_handler_param[3], *failover_handler_param[2];
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zz", &mmc_object, memcache_pool_ce, &keys, &flags, &cas) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|zz", &keys, &flags, &cas) == FAILURE) {
- return;
- }
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
- RETURN_FALSE;
- }
-
- ZVAL_FALSE(return_value);
- value_handler_param[0] = return_value;
- value_handler_param[1] = flags;
- value_handler_param[2] = cas;
-
- if (Z_TYPE_P(keys) == IS_ARRAY) {
- zval **key;
- HashPosition pos;
-
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
-
- failover_handler_param[0] = keys;
- failover_handler_param[1] = value_handler_param;
-
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
- zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
-
- /* schedule request */
- mmc_pool_schedule_get(pool, MMC_PROTO_UDP,
- cas != NULL ? MMC_OP_GETS : MMC_OP_GET, *key,
- mmc_value_handler_multi, value_handler_param,
- mmc_value_failover_handler, failover_handler_param, NULL TSRMLS_CC);
- }
- }
- else {
- mmc_request_t *request;
-
- /* allocate request */
- request = mmc_pool_request_get(
- pool, MMC_PROTO_UDP,
- mmc_value_handler_single, value_handler_param,
- mmc_pool_failover_handler, NULL TSRMLS_CC);
-
- if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
- mmc_pool_release(pool, request);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
- return;
- }
-
- pool->protocol->get(request, cas != NULL ? MMC_OP_GETS : MMC_OP_GET, keys, request->key, request->key_len);
-
- /* schedule request */
- if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, 1 TSRMLS_CC) != MMC_OK) {
- return;
- }
- }
-
- /* execute all requests */
- mmc_pool_run(pool TSRMLS_CC);
-}
-/* }}} */
-
-static int mmc_stats_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- parses the stats response line, param is a zval pointer to store stats into {{{ */
-{
- if (response != MMC_RESPONSE_ERROR)
- {
- char *line = (char *)message;
-
- if (mmc_str_left(line, "RESET", message_len, sizeof("RESET")-1)) {
- ZVAL_TRUE((zval *)param);
- return MMC_REQUEST_DONE;
- }
- else if (mmc_str_left(line, "STAT ", message_len, sizeof("STAT ")-1)) {
- if (mmc_stats_parse_stat(line + sizeof("STAT ")-1, line + message_len - 1, (zval *)param TSRMLS_CC)) {
- return MMC_REQUEST_AGAIN;
- }
- }
- else if (mmc_str_left(line, "ITEM ", message_len, sizeof("ITEM ")-1)) {
- if (mmc_stats_parse_item(line + sizeof("ITEM ")-1, line + message_len - 1, (zval *)param TSRMLS_CC)) {
- return MMC_REQUEST_AGAIN;
- }
- }
- else if (mmc_str_left(line, "END", message_len, sizeof("END")-1)) {
- return MMC_REQUEST_DONE;
- }
- else if (mmc_stats_parse_generic(line, line + message_len, (zval *)param TSRMLS_CC)) {
- return MMC_REQUEST_AGAIN;
- }
-
- zval_dtor((zval *)param);
- ZVAL_FALSE((zval *)param);
- return MMC_REQUEST_FAILURE;
- }
-
- return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
-}
-/* }}} */
-
-static int mmc_stats_checktype(const char *type) { /* {{{ */
- return type == NULL ||
- !strcmp(type, "reset") ||
- !strcmp(type, "malloc") ||
- !strcmp(type, "slabs") ||
- !strcmp(type, "cachedump") ||
- !strcmp(type, "items") ||
- !strcmp(type, "sizes");
-}
-/* }}} */
-
-/* {{{ 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;
- zval *mmc_object = getThis();
-
- char *type = NULL;
- int i, type_len = 0;
- long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT;
- mmc_request_t *request;
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_pool_ce, &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) || !pool->num_servers) {
- RETURN_FALSE;
- }
-
- if (!mmc_stats_checktype(type)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stats type");
- RETURN_FALSE;
- }
-
- ZVAL_FALSE(return_value);
-
- for (i=0; i<pool->num_servers; i++) {
- request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stats_handler, return_value, NULL, NULL TSRMLS_CC);
- pool->protocol->stats(request, type, slabid, limit);
-
- /* run command and check for valid return value */
- if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
- mmc_pool_run(pool TSRMLS_CC);
-
- if (Z_TYPE_P(return_value) != IS_BOOL || Z_BVAL_P(return_value)) {
- break;
- }
- }
- }
-
- /* execute all requests */
- mmc_pool_run(pool TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ 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;
- zval *mmc_object = getThis(), *stats;
-
- char *host, *type = NULL;
- int i, host_len, type_len = 0;
- long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT;
- mmc_request_t *request;
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_pool_ce, &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) || !pool->num_servers) {
- RETURN_FALSE;
- }
-
- if (!mmc_stats_checktype(type)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stats type");
- RETURN_FALSE;
- }
-
- array_init(return_value);
-
- for (i=0; i<pool->num_servers; i++) {
- MAKE_STD_ZVAL(stats);
- ZVAL_FALSE(stats);
-
- host_len = spprintf(&host, 0, "%s:%u", pool->servers[i]->host, pool->servers[i]->tcp.port);
- add_assoc_zval_ex(return_value, host, host_len + 1, stats);
- efree(host);
-
- request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stats_handler, stats, NULL, NULL TSRMLS_CC);
- pool->protocol->stats(request, type, slabid, limit);
-
- mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC);
- }
-
- /* execute all requests */
- mmc_pool_run(pool TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ 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_pool_ce, &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 bool memcache_delete(object memcache, mixed key [, int exptime ])
- Deletes existing item */
-PHP_FUNCTION(memcache_delete)
-{
- php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
-}
-/* }}} */
-
-/* {{{ proto mixed memcache_increment(object memcache, mixed key [, int value [, int defval [, int exptime ] ] ])
- Increments existing variable */
-PHP_FUNCTION(memcache_increment)
-{
- php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
-}
-/* }}} */
-
-/* {{{ proto mixed memcache_decrement(object memcache, mixed key [, int value [, int defval [, int exptime ] ] ])
- Decrements existing variable */
-PHP_FUNCTION(memcache_decrement)
-{
- php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
-}
-/* }}} */
-
-/* {{{ proto bool memcache_close( object memcache )
- Closes connection to memcached */
-PHP_FUNCTION(memcache_close)
-{
- mmc_pool_t *pool;
- zval *mmc_object = getThis();
- int i;
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_pool_ce) == FAILURE) {
- return;
- }
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
- RETURN_FALSE;
- }
-
- mmc_pool_close(pool TSRMLS_CC);
- RETURN_TRUE;
-}
-/* }}} */
-
-static int mmc_flush_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- parses the OK response line, param is an int pointer to increment on success {{{ */
-{
- if (response == MMC_OK) {
- (*((int *)param))++;
- return MMC_REQUEST_DONE;
- }
-
- return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ proto bool memcache_flush( object memcache [, int delay ] )
- Flushes cache, optionally at after the specified delay */
-PHP_FUNCTION(memcache_flush)
-{
- mmc_pool_t *pool;
- zval *mmc_object = getThis();
-
- mmc_request_t *request;
- unsigned int i, responses = 0;
- long delay = 0;
-
- if (mmc_object == NULL) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &mmc_object, memcache_pool_ce, &delay) == FAILURE) {
- return;
- }
- }
- else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &delay) == FAILURE) {
- return;
- }
- }
-
- if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
- RETURN_FALSE;
- }
-
- for (i=0; i<pool->num_servers; i++) {
- request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_flush_handler, &responses, NULL, NULL TSRMLS_CC);
- pool->protocol->flush(request, delay);
-
- if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
- /* begin sending requests immediatly */
- mmc_pool_select(pool, 0 TSRMLS_CC);
- }
- }
-
- /* execute all requests */
- mmc_pool_run(pool TSRMLS_CC);
-
- if (responses < pool->num_servers) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool memcache_debug( bool onoff ) */
-PHP_FUNCTION(memcache_debug)
-{
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache_debug() is deprecated, please use a debugger (like Eclipse + CDT)");
-}
-/* }}} */
-
-/*
- * 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-3.0.1.tgz/memcache-3.0.1/memcache_ascii_protocol.c
^
|
@@ -1,374 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_ascii_protocol.c,v 1.1.2.4 2007/11/04 13:56:13 mikl Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "memcache_pool.h"
-#include "ext/standard/php_smart_str.h"
-
-typedef struct mmc_ascii_request {
- mmc_request_t base; /* enable cast to mmc_request_t */
- struct { /* stores value info while the body is being read */
- char key[MMC_MAX_KEY_LEN + 1]; /* key buffer to use on failover of single-key requests */
- unsigned int flags;
- unsigned long length;
- unsigned long cas; /* CAS counter */
- } value;
-} mmc_ascii_request_t;
-
-static int mmc_server_read_value(mmc_t *, mmc_request_t * TSRMLS_DC);
-
-static int mmc_stream_get_line(mmc_stream_t *io, char **line TSRMLS_DC) /*
- attempts to read a line from server, returns the line size or 0 if no complete line was available {{{ */
-{
- size_t returned_len = 0;
- io->readline(io, io->input.value + io->input.idx, MMC_BUFFER_SIZE - io->input.idx, &returned_len TSRMLS_CC);
- io->input.idx += returned_len;
-
- if (io->input.idx && io->input.value[io->input.idx - 1] == '\n') {
- int result = io->input.idx;
- *line = io->input.value;
- io->input.idx = 0;
- return result;
- }
-
- return 0;
-}
-/* }}} */
-
-static int mmc_request_parse_response(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- reads a generic response header and delegates it to response_handler {{{ */
-{
- char *line;
- int line_len = mmc_stream_get_line(request->io, &line TSRMLS_CC);
-
- if (line_len > 0) {
- int response;
-
- if (mmc_str_left(line, "OK", line_len, sizeof("OK")-1) ||
- mmc_str_left(line, "STORED", line_len, sizeof("STORED")-1) ||
- mmc_str_left(line, "DELETED", line_len, sizeof("DELETED")-1))
- {
- response = MMC_OK;
- }
- else if (mmc_str_left(line, "NOT_FOUND", line_len, sizeof("NOT_FOUND")-1)) {
- response = MMC_RESPONSE_NOT_FOUND;
- }
- else if (
- mmc_str_left(line, "NOT_STORED", line_len, sizeof("NOT_STORED")-1) ||
- mmc_str_left(line, "EXISTS", line_len, sizeof("EXISTS")-1))
- {
- response = MMC_RESPONSE_EXISTS;
- }
- else if (mmc_str_left(line, "SERVER_ERROR out of memory", line_len, sizeof("SERVER_ERROR out of memory")-1)) {
- response = MMC_RESPONSE_OUT_OF_MEMORY;
- }
- else if (mmc_str_left(line, "SERVER_ERROR object too large", line_len, sizeof("SERVER_ERROR object too large")-1)) {
- response = MMC_RESPONSE_TOO_LARGE;
- }
- else if (
- mmc_str_left(line, "ERROR", line_len, sizeof("ERROR")-1) ||
- mmc_str_left(line, "SERVER_ERROR", line_len, sizeof("SERVER_ERROR")-1) ||
- mmc_str_left(line, "CLIENT_ERROR", line_len, sizeof("CLIENT_ERROR")-1))
- {
- response = MMC_RESPONSE_ERROR;
- }
- else {
- response = MMC_RESPONSE_UNKNOWN;
- }
-
- return request->response_handler(mmc, request, response, line, line_len - (sizeof("\r\n")-1), request->response_handler_param TSRMLS_CC);
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static int mmc_request_parse_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- reads and parses the VALUE <key> <flags> <size> <cas> header and then reads the value body {{{ */
-{
- char *line;
- int line_len;
- mmc_ascii_request_t *req = (mmc_ascii_request_t *)request;
-
- line_len = mmc_stream_get_line(request->io, &line TSRMLS_CC);
- if (line_len > 0) {
- if (mmc_str_left(line, "END", line_len, sizeof("END")-1)) {
- return MMC_REQUEST_DONE;
- }
-
- if (sscanf(line, MMC_VALUE_HEADER, req->value.key, &(req->value.flags), &(req->value.length), &(req->value.cas)) < 3) {
- return mmc_server_failure(mmc, request->io, "Malformed VALUE header", 0 TSRMLS_CC);
- }
-
- /* memory for data + \r\n */
- mmc_buffer_alloc(&(request->readbuf), req->value.length + 2);
-
- /* allow read_value handler to read the value body */
- request->parse = mmc_server_read_value;
-
- /* read more, php streams buffer input which must be read if available */
- return MMC_REQUEST_AGAIN;
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static int mmc_server_read_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- read the value body into the buffer {{{ */
-{
- mmc_ascii_request_t *req = (mmc_ascii_request_t *)request;
- request->readbuf.idx +=
- request->io->read(request->io, request->readbuf.value.c + request->readbuf.idx, req->value.length + 2 - request->readbuf.idx TSRMLS_CC);
-
- /* done reading? */
- if (request->readbuf.idx >= req->value.length + 2) {
- /* allow parse_value to read next VALUE or END line */
- request->parse = mmc_request_parse_value;
- mmc_buffer_reset(&(request->readbuf));
-
- int result = mmc_unpack_value(
- mmc, request, &(request->readbuf), req->value.key, strlen(req->value.key),
- req->value.flags, req->value.cas, req->value.length TSRMLS_CC);
-
- return result;
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static mmc_request_t *mmc_ascii_create_request() /* {{{ */
-{
- mmc_ascii_request_t *request = emalloc(sizeof(mmc_ascii_request_t));
- memset(request, 0, sizeof(*request));
- return (mmc_request_t *)request;
-}
-/* }}} */
-
-static void mmc_ascii_reset_request(mmc_request_t *request) /* {{{ */
-{
- mmc_ascii_request_t *req = (mmc_ascii_request_t *)request;
- req->value.cas = 0;
- mmc_request_reset(request);
-}
-/* }}} */
-
-static void mmc_ascii_begin_get(mmc_request_t *request, int op) /* {{{ */
-{
- request->parse = mmc_request_parse_value;
-
- if (op == MMC_OP_GETS) {
- smart_str_appendl(&(request->sendbuf.value), "gets", sizeof("gets")-1);
- }
- else {
- smart_str_appendl(&(request->sendbuf.value), "get", sizeof("get")-1);
- }
-}
-/* }}} */
-
-static void mmc_ascii_append_get(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
-{
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
-}
-/* }}} */
-
-static void mmc_ascii_end_get(mmc_request_t *request) /* {{{ */
-{
- smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
-}
-/* }}} */
-
-static void mmc_ascii_get(mmc_request_t *request, int op, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
-{
- mmc_ascii_begin_get(request, op);
- mmc_ascii_append_get(request, zkey, key, key_len);
- mmc_ascii_end_get(request);
-}
-/* }}} */
-
-static int mmc_ascii_store(
- mmc_pool_t *pool, mmc_request_t *request, int op, const char *key, unsigned int key_len,
- unsigned int flags, unsigned int exptime, unsigned long cas, zval *value TSRMLS_DC) /* {{{ */
-{
- int status;
- mmc_buffer_t buffer;
- request->parse = mmc_request_parse_response;
-
- memset(&buffer, 0, sizeof(buffer));
- status = mmc_pack_value(pool, &buffer, value, &flags TSRMLS_CC);
-
- if (status != MMC_OK) {
- return status;
- }
-
- switch (op) {
- case MMC_OP_SET:
- smart_str_appendl(&(request->sendbuf.value), "set", sizeof("set")-1);
- break;
- case MMC_OP_ADD:
- smart_str_appendl(&(request->sendbuf.value), "add", sizeof("add")-1);
- break;
- case MMC_OP_REPLACE:
- smart_str_appendl(&(request->sendbuf.value), "replace", sizeof("replace")-1);
- break;
- case MMC_OP_CAS:
- smart_str_appendl(&(request->sendbuf.value), "cas", sizeof("cas")-1);
- break;
- case MMC_OP_APPEND:
- smart_str_appendl(&(request->sendbuf.value), "append", sizeof("append")-1);
- break;
- case MMC_OP_PREPEND:
- smart_str_appendl(&(request->sendbuf.value), "prepend", sizeof("prepend")-1);
- break;
- default:
- return MMC_REQUEST_FAILURE;
- }
-
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_append_unsigned(&(request->sendbuf.value), flags);
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_append_unsigned(&(request->sendbuf.value), exptime);
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_append_unsigned(&(request->sendbuf.value), buffer.value.len);
-
- if (op == MMC_OP_CAS) {
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_append_unsigned(&(request->sendbuf.value), cas);
- }
-
- smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
- smart_str_appendl(&(request->sendbuf.value), buffer.value.c, buffer.value.len);
- smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
-
- mmc_buffer_free(&buffer);
- return MMC_OK;
-}
-/* }}} */
-
-static void mmc_ascii_delete(mmc_request_t *request, const char *key, unsigned int key_len, unsigned int exptime) /* {{{ */
-{
- request->parse = mmc_request_parse_response;
-
- smart_str_appendl(&(request->sendbuf.value), "delete", sizeof("delete")-1);
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
-
- if (exptime > 0) {
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_append_unsigned(&(request->sendbuf.value), exptime);
- }
-
- smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
-}
-/* }}} */
-
-static void mmc_ascii_mutate(mmc_request_t *request, const char *key, unsigned int key_len, long value, long defval, unsigned int exptime) /* {{{ */
-{
- request->parse = mmc_request_parse_response;
-
- if (value >= 0) {
- smart_str_appendl(&(request->sendbuf.value), "incr", sizeof("incr")-1);
- }
- else {
- smart_str_appendl(&(request->sendbuf.value), "decr", sizeof("decr")-1);
- }
-
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_append_unsigned(&(request->sendbuf.value), value >= 0 ? value : -value);
- smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
-}
-/* }}} */
-
-static void mmc_ascii_flush(mmc_request_t *request, unsigned int exptime) /* {{{ */
-{
- request->parse = mmc_request_parse_response;
- smart_str_appendl(&(request->sendbuf.value), "flush_all", sizeof("flush_all")-1);
-
- if (exptime > 0) {
- smart_str_appendl(&(request->sendbuf.value), " ", 1);
- smart_str_append_unsigned(&(request->sendbuf.value), exptime);
- }
-
- smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
-}
-/* }}} */
-
-static void mmc_ascii_version(mmc_request_t *request) /* {{{ */
-{
- request->parse = mmc_request_parse_response;
- smart_str_appendl(&(request->sendbuf.value), "version\r\n", sizeof("version\r\n")-1);
-}
-/* }}} */
-
-static void mmc_ascii_stats(mmc_request_t *request, const char *type, long slabid, long limit) /* {{{ */
-{
- char *cmd;
- unsigned int cmd_len;
- request->parse = mmc_request_parse_response;
-
- if (slabid) {
- cmd_len = spprintf(&cmd, 0, "stats %s %ld %ld\r\n", type, slabid, limit);
- }
- else if (type) {
- cmd_len = spprintf(&cmd, 0, "stats %s\r\n", type);
- }
- else {
- cmd_len = spprintf(&cmd, 0, "stats\r\n");
- }
-
- smart_str_appendl(&(request->sendbuf.value), cmd, cmd_len);
- efree(cmd);
-}
-/* }}} */
-
-mmc_protocol_t mmc_ascii_protocol = {
- mmc_ascii_create_request,
- mmc_ascii_reset_request,
- mmc_request_free,
- mmc_ascii_get,
- mmc_ascii_begin_get,
- mmc_ascii_append_get,
- mmc_ascii_end_get,
- mmc_ascii_store,
- mmc_ascii_delete,
- mmc_ascii_mutate,
- mmc_ascii_flush,
- mmc_ascii_version,
- mmc_ascii_stats
-};
-
-/*
- * 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-3.0.1.tgz/memcache-3.0.1/memcache_binary_protocol.c
^
|
@@ -1,537 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_binary_protocol.c,v 1.1.2.3 2007/11/04 13:56:13 mikl Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdint.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include "memcache_pool.h"
-#include "ext/standard/php_smart_str.h"
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-# define ntohll(x) (x)
-# define htonll(x) (x)
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-# include <byteswap.h>
-# define ntohll(x) bswap_64(x)
-# define htonll(x) bswap_64(x)
-#else
-# error "Could not determine byte order: __BYTE_ORDER uncorrectly defined"
-#endif
-
-#define MMC_REQUEST_MAGIC 0x0f
-#define MMC_RESPONSE_MAGIC 0xf0
-
-#define MMC_OP_DELETE 0x04
-#define MMC_OP_MUTATE 0x05
-#define MMC_OP_FLUSH 0x07
-#define MMC_OP_GETQ 0x08
-#define MMC_OP_NOOP 0x09
-#define MMC_OP_VERSION 0x0a
-
-typedef struct mmc_binary_request {
- mmc_request_t base; /* enable cast to mmc_request_t */
- mmc_queue_t keys; /* mmc_queue_t<zval *>, reqid -> key mappings */
- struct {
- uint8_t cmdid;
- uint8_t error; /* error received in current request */
- uint32_t reqid; /* current reqid being processed */
- } command;
- struct { /* stores value info while the body is being read */
- unsigned int flags;
- unsigned long length;
- uint64_t cas; /* CAS counter */
- } value;
-} mmc_binary_request_t;
-
-typedef struct mmc_request_header {
- uint8_t magic;
- uint8_t cmdid;
- uint8_t key_len;
- uint8_t _reserved;
- uint32_t reqid; /* opaque request id */
- uint32_t length; /* trailing body length (not including this header) */
-} mmc_request_header_t;
-
-typedef struct mmc_store_request_header {
- mmc_request_header_t base;
- uint32_t flags;
- uint32_t exptime;
-} mmc_store_request_header_t;
-
-typedef struct mmc_cas_request_header {
- mmc_store_request_header_t base;
- uint64_t cas;
-} mmc_cas_request_header_t;
-
-typedef struct mmc_delete_request_header {
- mmc_request_header_t base;
- uint32_t exptime;
-} mmc_delete_request_header_t;
-
-typedef struct mmc_mutate_request_header {
- mmc_request_header_t base;
- int64_t value;
- int64_t defval;
- uint32_t exptime;
-} mmc_mutate_request_header_t;
-
-typedef struct mmc_flush_request_header {
- mmc_request_header_t base;
- uint32_t exptime;
-} mmc_flush_request_header_t;
-
-typedef struct mmc_response_header {
- uint8_t magic;
- uint8_t cmdid;
- uint8_t error;
- uint8_t _reserved;
- uint32_t reqid; /* echo'ed from request */
- uint32_t length; /* trailing body length (not including this header) */
-} mmc_response_header_t;
-
-typedef struct mmc_get_response_header {
- uint32_t flags;
-} mmc_get_response_header_t;
-
-typedef struct mmc_gets_response_header {
- uint32_t flags;
- uint64_t cas;
-} mmc_gets_response_header_t;
-
-static int mmc_request_read_response(mmc_t *, mmc_request_t * TSRMLS_DC);
-static int mmc_request_parse_value(mmc_t *, mmc_request_t * TSRMLS_DC);
-static int mmc_request_parse_value_cas(mmc_t *, mmc_request_t * TSRMLS_DC);
-static int mmc_request_read_value(mmc_t *, mmc_request_t * TSRMLS_DC);
-
-static inline char *mmc_stream_get(mmc_stream_t *io, size_t bytes TSRMLS_DC) /*
- attempts to read a number of bytes from server, returns the a pointer to the buffer on success, NULL if the complete number of bytes could not be read {{{ */
-{
- io->input.idx += io->read(io, io->input.value + io->input.idx, bytes - io->input.idx TSRMLS_CC);
-
- if (io->input.idx >= bytes) {
- io->input.idx = 0;
- return io->input.value;
- }
-
- return NULL;
-}
-/* }}} */
-
-static inline void mmc_decode_response_header(mmc_response_header_t *header) /* {{{ */
-{
- header->reqid = ntohl(header->reqid);
- header->length = ntohl(header->length);
-}
-/* }}} */
-
-static int mmc_request_parse_response(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- reads a generic response header and reads the response body {{{ */
-{
- mmc_response_header_t *header;
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
- header = (mmc_response_header_t *)mmc_stream_get(request->io, sizeof(*header) TSRMLS_CC);
-
- if (header != NULL) {
- mmc_decode_response_header(header);
- if (header->magic != MMC_RESPONSE_MAGIC) {
- return mmc_server_failure(mmc, request->io, "Malformed server response (invalid magic byte)", 0 TSRMLS_CC);
- }
-
- if (header->length == 0) {
- return request->response_handler(mmc, request, header->error, "", 0, request->response_handler_param TSRMLS_CC);
- }
-
- req->command.error = header->error;
- req->value.length = header->length;
-
- /* memory for data + \0 */
- mmc_buffer_alloc(&(request->readbuf), req->value.length + 1);
-
- /* allow read_response handler to read the response body */
- request->parse = mmc_request_read_response;
-
- /* read more, php streams buffer input which must be read if available */
- return MMC_REQUEST_AGAIN;
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static int mmc_request_read_response(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- read the response body into the buffer {{{ */
-{
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
- request->readbuf.idx +=
- request->io->read(request->io, request->readbuf.value.c + request->readbuf.idx, req->value.length - request->readbuf.idx TSRMLS_CC);
-
- /* done reading? */
- if (request->readbuf.idx >= req->value.length) {
- return request->response_handler(mmc, request, req->command.error, request->readbuf.value.c, req->value.length, request->response_handler_param TSRMLS_CC);
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static int mmc_request_parse_value_header(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- reads and parses the header and then reads the value header {{{ */
-{
- mmc_response_header_t *header;
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
-
- header = (mmc_response_header_t *)mmc_stream_get(request->io, sizeof(*header) TSRMLS_CC);
- if (header != NULL) {
- mmc_decode_response_header(header);
- if (header->magic != MMC_RESPONSE_MAGIC) {
- return mmc_server_failure(mmc, request->io, "Malformed server response (invalid magic byte)", 0 TSRMLS_CC);
- }
-
- /* read response body in case of error */
- if (header->error != 0) {
- if (header->length == 0) {
- return request->response_handler(mmc, request, header->error, "", 0, request->response_handler_param TSRMLS_CC);
- }
-
- req->command.error = header->error;
- req->value.length = header->length;
-
- /* memory for data + \0 */
- mmc_buffer_alloc(&(request->readbuf), req->value.length + 1);
-
- /* allow read_response handler to read the response body */
- request->parse = mmc_request_read_response;
- }
- else {
- /* last command in multi-get */
- if (header->cmdid == MMC_OP_NOOP) {
- return MMC_REQUEST_DONE;
- }
-
- req->command.reqid = header->reqid;
-
- /* allow parse_value_ handler to read the value specific header */
- if (header->cmdid == MMC_OP_GETS) {
- request->parse = mmc_request_parse_value_cas;
- req->value.length = header->length - sizeof(mmc_gets_response_header_t);
- }
- else {
- request->parse = mmc_request_parse_value;
- req->value.length = header->length - sizeof(mmc_get_response_header_t);
- }
- }
-
- /* read more, php streams buffer input which must be read if available */
- return MMC_REQUEST_AGAIN;
- }
-
- return MMC_REQUEST_MORE;
-}
-
-static int mmc_request_parse_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- reads and parses the value header and then reads the value body {{{ */
-{
- mmc_get_response_header_t *header;
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
-
- header = (mmc_get_response_header_t *)mmc_stream_get(request->io, sizeof(*header) TSRMLS_CC);
- if (header != NULL) {
- req->value.flags = ntohl(header->flags);
-
- /* memory for data + \0 */
- mmc_buffer_alloc(&(request->readbuf), req->value.length + 1);
-
- /* allow read_value handler to read the value body */
- request->parse = mmc_request_read_value;
-
- /* read more, php streams buffer input which must be read if available */
- return MMC_REQUEST_AGAIN;
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static int mmc_request_parse_value_cas(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- reads and parses the value header and then reads the value body {{{ */
-{
- mmc_gets_response_header_t *header;
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
-
- header = (mmc_gets_response_header_t *)mmc_stream_get(request->io, sizeof(*header) TSRMLS_CC);
- if (header != NULL) {
- req->value.flags = ntohl(header->flags);
- req->value.cas = ntohll(header->cas);
-
- /* memory for data + \0 */
- mmc_buffer_alloc(&(request->readbuf), req->value.length + 1);
-
- /* allow read_value handler to read the value body */
- request->parse = mmc_request_read_value;
-
- /* read more, php streams buffer input which must be read if available */
- return MMC_REQUEST_AGAIN;
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static int mmc_request_read_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- read the value body into the buffer {{{ */
-{
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
- request->readbuf.idx +=
- request->io->read(request->io, request->readbuf.value.c + request->readbuf.idx, req->value.length - request->readbuf.idx TSRMLS_CC);
-
- /* done reading? */
- if (request->readbuf.idx >= req->value.length) {
- zval *key;
- int result;
-
- /* allow parse_value to read next VALUE or NOOP */
- request->parse = mmc_request_parse_value_header;
- mmc_buffer_reset(&(request->readbuf));
-
- key = (zval *)mmc_queue_item(&(req->keys), req->command.reqid);
- result = mmc_unpack_value(
- mmc, request, &(request->readbuf), Z_STRVAL_P(key), Z_STRLEN_P(key),
- req->value.flags, req->value.cas, req->value.length TSRMLS_CC);
-
- if (result == MMC_REQUEST_AGAIN && req->command.reqid >= req->keys.len) {
- return MMC_REQUEST_DONE;
- }
-
- return result;
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}}*/
-
-static inline void mmc_pack_header(mmc_request_header_t *header, uint8_t cmdid, unsigned int key_len, unsigned int reqid, unsigned int length) /* {{{ */
-{
- header->magic = MMC_REQUEST_MAGIC;
- header->cmdid = cmdid;
- header->key_len = key_len & 0xff;
- header->_reserved = 0;
- header->reqid = htonl(reqid);
- header->length = htonl(length);
-}
-/* }}} */
-
-static mmc_request_t *mmc_binary_create_request() /* {{{ */
-{
- mmc_binary_request_t *request = emalloc(sizeof(mmc_binary_request_t));
- memset(request, 0, sizeof(*request));
- return (mmc_request_t *)request;
-}
-/* }}} */
-
-static void mmc_binary_reset_request(mmc_request_t *request) /* {{{ */
-{
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
- mmc_queue_reset(&(req->keys));
- req->value.cas = 0;
- mmc_request_reset(request);
-}
-/* }}} */
-
-static void mmc_binary_free_request(mmc_request_t *request) /* {{{ */
-{
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
- mmc_queue_free(&(req->keys));
- mmc_request_free(request);
-}
-/* }}} */
-
-static void mmc_binary_begin_get(mmc_request_t *request, int op) /* {{{ */
-{
- request->parse = mmc_request_parse_value_header;
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
- req->command.cmdid = (op == MMC_OP_GET ? MMC_OP_GETQ : MMC_OP_GETS);
-}
-/* }}} */
-
-static void mmc_binary_append_get(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
-{
- mmc_request_header_t header;
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
-
- /* reqid/opaque is the index into the collection of key pointers */
- mmc_pack_header(&header, req->command.cmdid, key_len, req->keys.len, key_len);
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
-
- /* store key to be used by the response handler */
- mmc_queue_push(&(req->keys), zkey);
-}
-/* }}} */
-
-static void mmc_binary_end_get(mmc_request_t *request) /* {{{ */
-{
- mmc_request_header_t header;
- mmc_binary_request_t *req = (mmc_binary_request_t *)request;
- mmc_pack_header(&header, MMC_OP_NOOP, 0, req->keys.len, 0);
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
-}
-/* }}} */
-
-static void mmc_binary_get(mmc_request_t *request, int op, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
-{
- mmc_binary_begin_get(request, op);
- mmc_binary_append_get(request, zkey, key, key_len);
- mmc_binary_end_get(request);
-}
-/* }}} */
-
-static int mmc_binary_store(
- mmc_pool_t *pool, mmc_request_t *request, int op, const char *key, unsigned int key_len,
- unsigned int flags, unsigned int exptime, unsigned long cas, zval *value TSRMLS_DC) /* {{{ */
-{
- int status, prevlen;
- mmc_store_request_header_t *header;
-
- request->parse = mmc_request_parse_response;
- prevlen = request->sendbuf.value.len;
-
- /* allocate space for header */
- if (op == MMC_OP_CAS) {
- mmc_buffer_alloc(&(request->sendbuf), sizeof(mmc_cas_request_header_t));
- request->sendbuf.value.len += sizeof(mmc_cas_request_header_t);
- }
- else {
- mmc_buffer_alloc(&(request->sendbuf), sizeof(*header));
- request->sendbuf.value.len += sizeof(*header);
- }
-
- /* append key and data */
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
- status = mmc_pack_value(pool, &(request->sendbuf), value, &flags TSRMLS_CC);
-
- if (status != MMC_OK) {
- return status;
- }
-
- /* initialize header */
- header = (mmc_store_request_header_t *)(request->sendbuf.value.c + prevlen);
- mmc_pack_header(&(header->base), op, key_len, 0, request->sendbuf.value.len - prevlen - sizeof(header->base));
-
- header->flags = htonl(flags);
- header->exptime = htonl(exptime);
-
- if (op == MMC_OP_CAS) {
- ((mmc_cas_request_header_t *)header)->cas = htonll(cas);
- }
-
- return MMC_OK;
-}
-/* }}} */
-
-static void mmc_binary_delete(mmc_request_t *request, const char *key, unsigned int key_len, unsigned int exptime) /* {{{ */
-{
- mmc_delete_request_header_t header;
- request->parse = mmc_request_parse_response;
-
- mmc_pack_header(&(header.base), MMC_OP_DELETE, key_len, 0, sizeof(header) - sizeof(header.base) + key_len);
- header.exptime = htonl(exptime);
-
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
-}
-/* }}} */
-
-static void mmc_binary_mutate(mmc_request_t *request, const char *key, unsigned int key_len, long value, long defval, unsigned int exptime) /* {{{ */
-{
- mmc_mutate_request_header_t header;
- request->parse = mmc_request_parse_response;
-
- mmc_pack_header(&(header.base), MMC_OP_MUTATE, key_len, 0, sizeof(header) - sizeof(header.base) + key_len);
- header.value = htonll(value);
- header.defval = htonll(defval);
- header.exptime = htonl(exptime);
-
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
- smart_str_appendl(&(request->sendbuf.value), key, key_len);
-}
-/* }}} */
-
-static void mmc_binary_flush(mmc_request_t *request, unsigned int exptime) /* {{{ */
-{
- mmc_flush_request_header_t header;
- request->parse = mmc_request_parse_response;
-
- mmc_pack_header(&(header.base), MMC_OP_FLUSH, 0, 0, sizeof(header) - sizeof(header.base));
- header.exptime = htonl(exptime);
-
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
-}
-/* }}} */
-
-static void mmc_binary_version(mmc_request_t *request) /* {{{ */
-{
- mmc_request_header_t header;
- request->parse = mmc_request_parse_response;
-
- mmc_pack_header(&header, MMC_OP_VERSION, 0, 0, 0);
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
-}
-/* }}} */
-
-static void mmc_binary_stats(mmc_request_t *request, const char *type, long slabid, long limit) /* {{{ */
-{
- /* stats not supported */
- mmc_request_header_t header;
- request->parse = mmc_request_parse_response;
-
- mmc_pack_header(&header, MMC_OP_NOOP, 0, 0, 0);
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
-}
-/* }}} */
-
-mmc_protocol_t mmc_binary_protocol = {
- mmc_binary_create_request,
- mmc_binary_reset_request,
- mmc_binary_free_request,
- mmc_binary_get,
- mmc_binary_begin_get,
- mmc_binary_append_get,
- mmc_binary_end_get,
- mmc_binary_store,
- mmc_binary_delete,
- mmc_binary_mutate,
- mmc_binary_flush,
- mmc_binary_version,
- mmc_binary_stats
-};
-
-/*
- * 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-3.0.1.tgz/memcache-3.0.1/memcache_consistent_hash.c
^
|
@@ -1,174 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_consistent_hash.c,v 1.2.2.6 2007/11/03 09:19:05 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;
- }
-
- /* best guess with random distribution, distance between lowpoint and point scaled down to lo-hi interval */
- mid = lo + (hi - lo) * (point - state->points[lo].point) / (state->points[hi].point - state->points[lo].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_pupulate_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, unsigned int key_len TSRMLS_DC) /* {{{ */
-{
- mmc_consistent_state_t *state = s;
-
- if (state->num_servers > 1) {
- if (!state->buckets_populated) {
- mmc_consistent_pupulate_buckets(state);
- }
- return state->buckets[state->hash(key, key_len) % MMC_CONSISTENT_BUCKETS];
- }
-
- return state->points[0].server;
-}
-/* }}} */
-
-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;
- char *key;
-
- /* add weight * MMC_CONSISTENT_POINTS number of points for this server */
- state->points = erealloc(state->points, sizeof(*state->points) * (state->num_points + points));
-
- for (i=0; i<points; i++) {
- key_len = spprintf(&key, 0, "%s:%d-%d", mmc->host, mmc->tcp.port, i);
- state->points[state->num_points + i].server = mmc;
- state->points[state->num_points + i].point = state->hash(key, key_len);
- efree(key);
- }
-
- state->num_points += points;
- state->num_servers++;
-
- state->buckets_populated = 0;
-}
-/* }}} */
-
-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-3.0.1.tgz/memcache-3.0.1/memcache_pool.c
^
|
@@ -1,1554 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_pool.c,v 1.1.2.23 2008/01/11 21:33:56 mikl Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <zlib.h>
-#include <arpa/inet.h>
-
-#include "php.h"
-#include "php_network.h"
-#include "ext/standard/crc32.h"
-#include "ext/standard/php_var.h"
-#include "ext/standard/php_string.h"
-#include "ext/standard/php_smart_str.h"
-#include "memcache_pool.h"
-
-ZEND_DECLARE_MODULE_GLOBALS(memcache)
-
-inline void mmc_buffer_alloc(mmc_buffer_t *buffer, unsigned int size) /*
- ensures space for an additional size bytes {{{ */
-{
- register size_t newlen;
- smart_str_alloc((&(buffer->value)), size, 0);
-}
-/* }}} */
-
-inline void mmc_buffer_free(mmc_buffer_t *buffer) /* {{{ */
-{
- if (buffer->value.c != NULL) {
- smart_str_free(&(buffer->value));
- }
- memset(buffer, 0, sizeof(*buffer));
-}
-/* }}} */
-
-static unsigned int mmc_hash_crc32(const char *key, unsigned int key_len) /*
- CRC32 hash {{{ */
-{
- unsigned int i, crc = ~0;
-
- for (i=0; i<key_len; i++) {
- CRC32(crc, key[i]);
- }
-
- return ~crc;
-}
-/* }}} */
-
-static unsigned int mmc_hash_fnv1a(const char *key, unsigned int key_len) /*
- FNV-1a hash {{{ */
-{
- unsigned int i, hval = FNV_32_INIT;
-
- for (i=0; i<key_len; i++) {
- hval ^= (unsigned int)key[i];
- hval *= FNV_32_PRIME;
- }
-
- return hval;
-}
-/* }}} */
-
-static size_t mmc_stream_read_buffered(mmc_stream_t *io, char *buf, size_t count TSRMLS_DC) /*
- attempts to reads count bytes from the stream buffer {{{ */
-{
- size_t toread = io->buffer.value.len - io->buffer.idx < count ? io->buffer.value.len - io->buffer.idx : count;
- memcpy(buf, io->buffer.value.c + io->buffer.idx, toread);
- io->buffer.idx += toread;
- return toread;
-}
-/* }}} */
-
-static char *mmc_stream_readline_buffered(mmc_stream_t *io, char *buf, size_t maxlen, size_t *retlen TSRMLS_DC) /*
- reads count bytes from the stream buffer, this implementation only detects \r\n (like memcached sends) {{{ */
-{
- char *eol;
-
- eol = memchr(io->buffer.value.c + io->buffer.idx, '\n', io->buffer.value.len - io->buffer.idx);
- if (eol != NULL) {
- *retlen = eol - io->buffer.value.c - io->buffer.idx + 1;
- }
- else {
- *retlen = io->buffer.value.len - io->buffer.idx;
- }
-
- /* ensure space for data + \0 */
- if (*retlen >= maxlen) {
- *retlen = maxlen - 1;
- }
-
- memcpy(buf, io->buffer.value.c + io->buffer.idx, *retlen);
- io->buffer.idx += *retlen;
- buf[*retlen] = '\0';
-
- return buf;
-}
-/* }}} */
-
-static size_t mmc_stream_read_wrapper(mmc_stream_t *io, char *buf, size_t count TSRMLS_DC) /* {{{ */
-{
- return php_stream_read(io->stream, buf, count);
-}
-/* }}} */
-
-static char *mmc_stream_readline_wrapper(mmc_stream_t *io, char *buf, size_t maxlen, size_t *retlen TSRMLS_DC) /* {{{ */
-{
- return php_stream_get_line(io->stream, ZSTR(buf), maxlen, retlen);
-}
-/* }}} */
-
-void mmc_request_reset(mmc_request_t *request) /* {{{ */
-{
- request->key_len = 0;
- mmc_buffer_reset(&(request->sendbuf));
- mmc_queue_reset(&(request->failed_servers));
- request->failed_index = 0;
-}
-/* }}} */
-
-void mmc_request_free(mmc_request_t *request) /* {{{ */
-{
- mmc_buffer_free(&(request->sendbuf));
- mmc_buffer_free(&(request->readbuf));
- mmc_queue_free(&(request->failed_servers));
- efree(request);
-}
-/* }}} */
-
-static inline int mmc_request_send(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /* {{{ */
-{
- /* send next chunk of buffer */
- request->sendbuf.idx += php_stream_write(
- request->io->stream, request->sendbuf.value.c + request->sendbuf.idx,
- request->sendbuf.value.len - request->sendbuf.idx);
-
- /* done sending? */
- if (request->sendbuf.idx >= request->sendbuf.value.len) {
- return MMC_REQUEST_DONE;
- }
-
- if (php_stream_eof(request->io->stream)) {
- return mmc_server_failure(mmc, request->io, "Write failed (socket was unexpectedly closed)", 0 TSRMLS_CC);
- }
-
- return MMC_REQUEST_MORE;
-}
-/* }}} */
-
-static int mmc_request_read_udp(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- reads an entire datagram into buffer and validates the udp header {{{ */
-{
- size_t bytes;
- mmc_udp_header_t *header;
-
- /* reset buffer if completely consumed */
- if (request->io->buffer.idx >= request->io->buffer.value.len) {
- mmc_buffer_reset(&(request->io->buffer));
- }
-
- /* attempt to read datagram + sentinel-byte */
- mmc_buffer_alloc(&(request->io->buffer), MMC_MAX_UDP_LEN + 1);
- bytes = php_stream_read(request->io->stream, request->io->buffer.value.c + request->io->buffer.value.len, MMC_MAX_UDP_LEN + 1);
-
- if (bytes < sizeof(mmc_udp_header_t)) {
- return mmc_server_failure(mmc, request->io, "Failed te read complete UDP header from stream", 0 TSRMLS_CC);
- }
- if (bytes > MMC_MAX_UDP_LEN) {
- return mmc_server_failure(mmc, request->io, "Server sent packet larger than MMC_MAX_UDP_LEN bytes", 0 TSRMLS_CC);
- }
-
- header = (mmc_udp_header_t *)(request->io->buffer.value.c + request->io->buffer.value.len);
-
- /* initialize udp header fields */
- if (!request->udp.total) {
- request->udp.seqid = ntohs(header->seqid);
- request->udp.total = ntohs(header->total);
- }
-
- /* detect dropped packets and reschedule for tcp delivery */
- if (request->udp.reqid != ntohs(header->reqid) || request->udp.seqid != ntohs(header->seqid)) {
- /* ensure that no more udp requests are scheduled for a while */
- request->io->status = MMC_STATUS_FAILED;
- request->io->failed = (long)time(NULL);
-
- /* discard packets for previous requests */
- if (ntohs(header->reqid) < request->udp.reqid) {
- return MMC_REQUEST_MORE;
- }
-
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "UDP packet loss, expected %d:%d got %d:%d",
- (int)request->udp.reqid, (int)request->udp.seqid, (int)ntohs(header->reqid), (int)ntohs(header->seqid));
- return MMC_REQUEST_RETRY;
- }
-
- request->udp.seqid++;
-
- /* skip udp header */
- if (request->io->buffer.idx > 0) {
- memmove(
- request->io->buffer.value.c + request->io->buffer.value.len,
- request->io->buffer.value.c + request->io->buffer.value.len + sizeof(mmc_udp_header_t),
- bytes - sizeof(mmc_udp_header_t));
- }
- else {
- request->io->buffer.idx += sizeof(mmc_udp_header_t);
- }
-
- request->io->buffer.value.len += bytes;
- return MMC_OK;
-}
-/* }}} */
-
-static void mmc_compress(mmc_pool_t *pool, mmc_buffer_t *buffer, const char *value, int value_len, unsigned int *flags, int copy TSRMLS_DC) /* {{{ */
-{
- /* autocompress large values */
- if (pool->compress_threshold && value_len >= pool->compress_threshold) {
- *flags |= MMC_COMPRESSED;
- }
-
- if (*flags & MMC_COMPRESSED) {
- int status;
- mmc_buffer_t prev;
- unsigned long result_len = value_len * (1 - pool->min_compress_savings);
-
- if (copy) {
- /* value is already in output buffer */
- prev = *buffer;
-
- /* allocate space for prev header + result */
- memset(buffer, 0, sizeof(*buffer));
- mmc_buffer_alloc(buffer, prev.value.len + result_len);
-
- /* append prev header */
- smart_str_appendl(&(buffer->value), prev.value.c, prev.value.len - value_len);
- buffer->idx = prev.idx;
- }
- else {
- /* allocate space directly in buffer */
- mmc_buffer_alloc(buffer, result_len);
- }
-
- if (MMC_COMPRESSION_LEVEL >= 0) {
- status = compress2((unsigned char *)buffer->value.c + buffer->value.len, &result_len, (unsigned const char *)value, value_len, MMC_COMPRESSION_LEVEL);
- } else {
- status = compress((unsigned char *)buffer->value.c + buffer->value.len, &result_len, (unsigned const char *)value, value_len);
- }
-
- if (status == Z_OK) {
- buffer->value.len += result_len;
- }
- else {
- smart_str_appendl(&(buffer->value), value, value_len);
- *flags &= ~MMC_COMPRESSED;
- }
-
- if (copy) {
- mmc_buffer_free(&prev);
- }
- }
- else if (!copy) {
- smart_str_appendl(&(buffer->value), value, value_len);
- }
-}
-/* }}}*/
-
-static int mmc_uncompress(const char *data, unsigned long data_len, char **result, unsigned long *result_len) /* {{{ */
-{
- int status, factor = 1;
-
- do {
- *result_len = data_len * (1 << factor++);
- *result = (char *)erealloc(*result, *result_len + 1);
- status = uncompress((unsigned char *)*result, result_len, (unsigned const char *)data, data_len);
- } while (status == Z_BUF_ERROR && factor < 16);
-
- if (status == Z_OK) {
- return MMC_OK;
- }
-
- efree(*result);
- return MMC_REQUEST_FAILURE;
-}
-/* }}}*/
-
-int mmc_pack_value(mmc_pool_t *pool, mmc_buffer_t *buffer, zval *value, unsigned int *flags TSRMLS_DC) /*
- does serialization and compression to pack a zval into the buffer {{{ */
-{
- switch (Z_TYPE_P(value)) {
- case IS_STRING:
- *flags &= ~MMC_SERIALIZED;
- mmc_compress(pool, buffer, Z_STRVAL_P(value), Z_STRLEN_P(value), flags, 0 TSRMLS_CC);
- break;
-
- case IS_LONG:
- case IS_DOUBLE:
- case IS_BOOL:
- *flags &= ~MMC_SERIALIZED;
- convert_to_string(value);
- mmc_compress(pool, buffer, Z_STRVAL_P(value), Z_STRLEN_P(value), flags, 0 TSRMLS_CC);
- break;
-
- default: {
- php_serialize_data_t value_hash;
- zval value_copy, *value_copy_ptr;
- size_t prev_len = buffer->value.len;
-
- /* 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(&(buffer->value), &value_copy_ptr, &value_hash TSRMLS_CC);
- PHP_VAR_SERIALIZE_DESTROY(value_hash);
-
- /* trying to save null or something went really wrong */
- if (buffer->value.c == NULL || buffer->value.len == prev_len) {
- zval_dtor(&value_copy);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to serialize value");
- return MMC_REQUEST_FAILURE;
- }
-
- *flags |= MMC_SERIALIZED;
- zval_dtor(&value_copy);
-
- mmc_compress(pool, buffer, buffer->value.c + prev_len, buffer->value.len - prev_len, flags, 1 TSRMLS_CC);
- }
- }
-
- return MMC_OK;
-}
-/* }}} */
-
-int mmc_unpack_value(
- mmc_t *mmc, mmc_request_t *request, mmc_buffer_t *buffer, const char *key, unsigned int key_len,
- unsigned int flags, unsigned long cas, unsigned int bytes TSRMLS_DC) /*
- does uncompression and unserializing to reconstruct a zval {{{ */
-{
- char *data = NULL;
- unsigned long data_len;
-
- zval value;
- INIT_ZVAL(value);
-
- if (flags & MMC_COMPRESSED) {
- if (mmc_uncompress(buffer->value.c, bytes, &data, &data_len) != MMC_OK) {
- return mmc_server_failure(mmc, request->io, "Failed to uncompress data", 0 TSRMLS_CC);
- }
- }
- else {
- data = buffer->value.c;
- data_len = bytes;
- }
-
- if (flags & MMC_SERIALIZED) {
- php_unserialize_data_t var_hash;
- const unsigned char *p = (unsigned char *)data;
- zval *object = &value;
-
- char key_tmp[MMC_MAX_KEY_LEN];
- mmc_request_value_handler value_handler;
- void *value_handler_param;
- mmc_buffer_t buffer_tmp;
-
- /* make copies of data to ensure re-entrancy */
- memcpy(key_tmp, key, key_len);
- value_handler = request->value_handler;
- value_handler_param = request->value_handler_param;
-
- if (!(flags & MMC_COMPRESSED)) {
- buffer_tmp = *buffer;
- mmc_buffer_release(buffer);
- }
-
- PHP_VAR_UNSERIALIZE_INIT(var_hash);
- if (!php_var_unserialize(&object, &p, p + data_len, &var_hash TSRMLS_CC)) {
- PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
-
- if (flags & MMC_COMPRESSED) {
- efree(data);
- }
- else if (buffer->value.c == NULL) {
- *buffer = buffer_tmp;
- }
- else {
- mmc_buffer_free(&buffer_tmp);
- }
-
- return mmc_server_failure(mmc, request->io, "Failed to unserialize data", 0 TSRMLS_CC);
- }
-
- PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
-
- if (flags & MMC_COMPRESSED) {
- efree(data);
- }
- else if (buffer->value.c == NULL) {
- *buffer = buffer_tmp;
- }
- else {
- mmc_buffer_free(&buffer_tmp);
- }
-
- /* delegate to value handler */
- return value_handler(key_tmp, key_len, object, 0, flags, cas, value_handler_param TSRMLS_CC);
- }
- else {
- /* room for \0 since buffer contains trailing \r\n and uncompress allocates + 1 */
- data[data_len] = '\0';
- ZVAL_STRINGL(&value, data, data_len, 0);
-
- if (!(flags & MMC_COMPRESSED)) {
- mmc_buffer_release(buffer);
- }
-
- /* delegate to value handler */
- return request->value_handler(key, key_len, &value, 0, flags, cas, request->value_handler_param TSRMLS_CC);
- }
-}
-/* }}}*/
-
-
-mmc_t *mmc_server_new(
- const char *host, int host_len, unsigned short tcp_port, unsigned short udp_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->tcp.port = tcp_port;
- mmc->tcp.status = MMC_STATUS_DISCONNECTED;
- mmc->udp.port = udp_port;
- mmc->udp.status = MMC_STATUS_DISCONNECTED;
-
- mmc->persistent = persistent;
- mmc->timeout = timeout;
-
- mmc->tcp.retry_interval = retry_interval;
- mmc->tcp.chunk_size = MEMCACHE_G(chunk_size);
- mmc->udp.retry_interval = retry_interval;
- mmc->udp.chunk_size = MEMCACHE_G(chunk_size); /* = MMC_MAX_UDP_LEN;*/
-
- return mmc;
-}
-/* }}} */
-
-static void _mmc_server_disconnect(mmc_t *mmc, mmc_stream_t *io, int close_persistent_stream TSRMLS_DC) /* {{{ */
-{
- mmc_buffer_free(&(io->buffer));
-
- if (io->stream != NULL) {
- if (mmc->persistent) {
- if (close_persistent_stream) {
- php_stream_pclose(io->stream);
- }
- }
- else {
- php_stream_close(io->stream);
- }
- io->stream = NULL;
- }
-
- io->status = MMC_STATUS_DISCONNECTED;
-}
-/* }}} */
-
-void mmc_server_disconnect(mmc_t *mmc, mmc_stream_t *io TSRMLS_DC) /* {{{ */
-{
- _mmc_server_disconnect(mmc, io, 1 TSRMLS_CC);
-}
-/* }}} */
-
-static void mmc_server_seterror(mmc_t *mmc, const char *error, int errnum) /* {{{ */
-{
- if (error != NULL) {
- if (mmc->error != NULL) {
- efree(mmc->error);
- }
-
- mmc->error = estrdup(error);
- mmc->errnum = errnum;
- }
-}
-/* }}} */
-
-static void mmc_server_deactivate(mmc_pool_t *pool, mmc_t *mmc TSRMLS_DC) /*
- disconnect and marks the server as down, failovers all queued requests {{{ */
-{
- mmc_queue_t readqueue;
- mmc_request_t *request;
-
- mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
- mmc_server_disconnect(mmc, &(mmc->udp) TSRMLS_CC);
-
- mmc->tcp.status = MMC_STATUS_FAILED;
- mmc->udp.status = MMC_STATUS_FAILED;
- mmc->tcp.failed = (long)time(NULL);
- mmc->udp.failed = mmc->tcp.failed;
-
- mmc_queue_remove(pool->sending, mmc);
- mmc_queue_remove(pool->reading, mmc);
-
- /* failover queued requests, sendque can be ignored since
- * readque + readreq + buildreq will always contain all active requests */
- mmc_queue_reset(&(mmc->sendqueue));
- mmc->sendreq = NULL;
-
- readqueue = mmc->readqueue;
- mmc_queue_release(&(mmc->readqueue));
-
- if (mmc->readreq != NULL) {
- mmc_queue_push(&readqueue, mmc->readreq);
- mmc->readreq = NULL;
- }
-
- if (mmc->buildreq != NULL) {
- mmc_queue_push(&readqueue, mmc->buildreq);
- mmc->buildreq = NULL;
- }
-
- /* delegate to failover handlers */
- while ((request = mmc_queue_pop(&readqueue)) != NULL) {
- request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
- }
-
- mmc_queue_free(&readqueue);
-
- /* fire userspace failure event */
- if (pool->failure_callback != NULL) {
- pool->failure_callback(pool, mmc, pool->failure_callback_param TSRMLS_CC);
- }
-}
-/* }}} */
-
-int mmc_server_failure(mmc_t *mmc, mmc_stream_t *io, const char *error, int errnum TSRMLS_DC) /*
- determines if a request should be retried or is a hard network failure {{{ */
-{
- switch (io->status) {
- case MMC_STATUS_DISCONNECTED:
- return MMC_REQUEST_RETRY;
-
- /* attempt reconnect of sockets in unknown state */
- case MMC_STATUS_UNKNOWN:
- io->status = MMC_STATUS_DISCONNECTED;
- return MMC_REQUEST_RETRY;
- }
-
- mmc_server_seterror(mmc, error, errnum);
- return MMC_REQUEST_FAILURE;
-}
-/* }}} */
-
-int mmc_request_failure(mmc_t *mmc, mmc_stream_t *io, const char *message, unsigned int message_len, int errnum TSRMLS_DC) /*
- checks for a valid server generated error message and calls mmc_server_failure() {{{ */
-{
- if (mmc_str_left(message, "ERROR", message_len, sizeof("ERROR")-1) ||
- mmc_str_left(message, "CLIENT_ERROR", message_len, sizeof("CLIENT_ERROR")-1) ||
- mmc_str_left(message, "SERVER_ERROR", message_len, sizeof("SERVER_ERROR")-1))
- {
- return mmc_server_failure(mmc, io, message, errnum TSRMLS_CC);
- }
-
- return mmc_server_failure(mmc, io, "Malformed server response", errnum TSRMLS_CC);
-}
-/* }}} */
-
-static int mmc_server_connect(mmc_pool_t *pool, mmc_t *mmc, mmc_stream_t *io, int udp TSRMLS_DC) /*
- connects a stream, calls mmc_server_deactivate() on failure {{{ */
-{
- char *host, *hash_key = NULL, *errstr = NULL;
- int host_len, errnum = 0;
- struct timeval tv;
-
- /* close open stream */
- if (io->stream != NULL) {
- mmc_server_disconnect(mmc, io TSRMLS_CC);
- }
-
- if (mmc->persistent) {
- spprintf(&hash_key, 0, "memcache:stream:%s:%u:%d", mmc->host, io->port, udp);
- }
-
- tv.tv_sec = mmc->timeout;
- tv.tv_usec = 0;
-
-#if PHP_API_VERSION > 20020918
-
- if (udp) {
- host_len = spprintf(&host, 0, "udp://%s:%u", mmc->host, io->port);
- }
- else if (io->port) {
- host_len = spprintf(&host, 0, "%s:%u", mmc->host, io->port);
- }
- else {
- host_len = spprintf(&host, 0, "%s", mmc->host);
- }
-
- io->stream = php_stream_xport_create(
- host, host_len,
- ENFORCE_SAFE_MODE | (mmc->persistent ? STREAM_OPEN_PERSISTENT : 0),
- STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
- hash_key, &tv, NULL, &errstr, &errnum);
-
- efree(host);
-
-#else
-
- if (mmc->persistent) {
- switch (php_stream_from_persistent_id(hash_key, &(io->stream) TSRMLS_CC)) {
- case PHP_STREAM_PERSISTENT_SUCCESS:
- if (php_stream_eof(io->stream)) {
- php_stream_pclose(io->stream);
- io->stream = NULL;
- break;
- }
- case PHP_STREAM_PERSISTENT_FAILURE:
- break;
- }
- }
-
- if (io->stream == NULL) {
- if (io->port) {
- io->stream = php_stream_sock_open_host(mmc->host, io->port, udp ? SOCK_DGRAM : SOCK_STREAM, &tv, hash_key);
- }
- else if (strncasecmp("unix://", mmc->host, sizeof("unix://")-1) == 0 && strlen(mmc->host) > sizeof("unix://")-1) {
- io->stream = php_stream_sock_open_unix(mmc->host + sizeof("unix://")-1, strlen(mmc->host + sizeof("unix://")-1), hash_key, &tv);
- }
- else {
- io->stream = php_stream_sock_open_unix(mmc->host, strlen(mmc->host), hash_key, &tv);
- }
- }
-
-#endif
-
- if (hash_key != NULL) {
- efree(hash_key);
- }
-
- /* check connection and extract socket for select() purposes */
- if (!io->stream || php_stream_cast(io->stream, PHP_STREAM_AS_FD_FOR_SELECT, (void **)&(io->fd), 1) != SUCCESS) {
- mmc_server_seterror(mmc, errstr != NULL ? errstr : "Connection failed", errnum);
- mmc_server_deactivate(pool, mmc TSRMLS_CC);
-
- if (errstr != NULL) {
- efree(errstr);
- }
-
- return MMC_REQUEST_FAILURE;
- }
-
- io->status = MMC_STATUS_CONNECTED;
-
- php_stream_auto_cleanup(io->stream);
- php_stream_set_option(io->stream, PHP_STREAM_OPTION_BLOCKING, 0, NULL);
- php_stream_set_option(io->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
-
- /* php_stream buffering prevent us from detecting datagram boundaries when using udp */
- if (udp) {
- io->read = mmc_stream_read_buffered;
- io->readline = mmc_stream_readline_buffered;
- php_stream_set_option(io->stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
- }
- else {
- io->read = mmc_stream_read_wrapper;
- io->readline = mmc_stream_readline_wrapper;
- }
-
- php_stream_set_option(io->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
- php_stream_set_chunk_size(io->stream, io->chunk_size);
-
- if (mmc->error != NULL) {
- efree(mmc->error);
- mmc->error = NULL;
- }
-
- return MMC_OK;
-}
-/* }}} */
-
-int mmc_server_valid(mmc_t *mmc TSRMLS_DC) /*
- checks if a server should be considered valid to serve requests {{{ */
-{
- if (mmc != NULL) {
- if (mmc->tcp.status >= MMC_STATUS_DISCONNECTED) {
- return 1;
- }
-
- if (mmc->tcp.status == MMC_STATUS_FAILED &&
- mmc->tcp.retry_interval >= 0 && (long)time(NULL) >= mmc->tcp.failed + mmc->tcp.retry_interval) {
- return 1;
- }
- }
-
- return 0;
-}
-/* }}} */
-
-void mmc_server_sleep(mmc_t *mmc TSRMLS_DC) /*
- prepare server struct for persistent sleep {{{ */
-{
- mmc_buffer_free(&(mmc->tcp.buffer));
- mmc_buffer_free(&(mmc->udp.buffer));
-
- mmc->sendreq = NULL;
- mmc->readreq = NULL;
- mmc->buildreq = NULL;
-
- mmc_queue_free(&(mmc->sendqueue));
- mmc_queue_free(&(mmc->readqueue));
-
- if (mmc->error != NULL) {
- efree(mmc->error);
- mmc->error = NULL;
- }
-}
-/* }}} */
-
-void mmc_server_free(mmc_t *mmc TSRMLS_DC) /* {{{ */
-{
- mmc_server_sleep(mmc TSRMLS_CC);
- _mmc_server_disconnect(mmc, &(mmc->tcp), 0 TSRMLS_CC);
- _mmc_server_disconnect(mmc, &(mmc->udp), 0 TSRMLS_CC);
-
- pefree(mmc->host, mmc->persistent);
- pefree(mmc, mmc->persistent);
-}
-/* }}} */
-
-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));
- memset(pool, 0, sizeof(*pool));
-
- switch (MEMCACHE_G(protocol)) {
- case MMC_BINARY_PROTOCOL:
- pool->protocol = &mmc_binary_protocol;
- break;
- default:
- pool->protocol = &mmc_ascii_protocol;
- }
-
- mmc_pool_init_hash(pool TSRMLS_CC);
- pool->min_compress_savings = MMC_DEFAULT_SAVINGS;
-
- pool->sending = &(pool->_sending1);
- pool->reading = &(pool->_reading1);
-
- return pool;
-}
-/* }}} */
-
-void mmc_pool_free(mmc_pool_t *pool TSRMLS_DC) /* {{{ */
-{
- int i;
- mmc_request_t *request;
-
- for (i=0; i<pool->num_servers; i++) {
- if (pool->servers[i] != NULL) {
- if (pool->servers[i]->persistent) {
- mmc_server_sleep(pool->servers[i] TSRMLS_CC);
- } else {
- mmc_server_free(pool->servers[i] TSRMLS_CC);
- }
- pool->servers[i] = NULL;
- }
- }
-
- if (pool->num_servers) {
- efree(pool->servers);
- }
-
- pool->hash->free_state(pool->hash_state);
-
- mmc_queue_free(&(pool->_sending1));
- mmc_queue_free(&(pool->_sending2));
- mmc_queue_free(&(pool->_reading1));
- mmc_queue_free(&(pool->_reading2));
- mmc_queue_free(&(pool->pending));
-
- /* requests are owned by us so free them */
- while ((request = mmc_queue_pop(&(pool->free_requests))) != NULL) {
- pool->protocol->free_request(request);
- }
- mmc_queue_free(&(pool->free_requests));
-
- efree(pool);
-}
-/* }}} */
-
-void mmc_pool_add(mmc_pool_t *pool, mmc_t *mmc, unsigned int weight) /*
- adds a server to the pool and hash strategy {{{ */
-{
- pool->hash->add_server(pool->hash_state, mmc, weight);
- pool->servers = erealloc(pool->servers, sizeof(*pool->servers) * (pool->num_servers + 1));
- pool->servers[pool->num_servers] = mmc;
- pool->num_servers++;
-}
-/* }}} */
-
-void 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) {
- mmc_server_sleep(pool->servers[i] TSRMLS_CC);
- } else {
- mmc_server_free(pool->servers[i] TSRMLS_CC);
- }
- }
-
- efree(pool->servers);
- pool->servers = NULL;
- pool->num_servers = 0;
-
- /* reallocate the hash strategy state */
- pool->hash->free_state(pool->hash_state);
- mmc_pool_init_hash(pool TSRMLS_CC);
- }
-}
-/* }}} */
-
-int mmc_pool_open(mmc_pool_t *pool, mmc_t *mmc, mmc_stream_t *io, int udp TSRMLS_DC) /*
- connects if the stream is not already connected {{{ */
-{
- switch (io->status) {
- case MMC_STATUS_CONNECTED:
- case MMC_STATUS_UNKNOWN:
- return MMC_OK;
-
- case MMC_STATUS_DISCONNECTED:
- case MMC_STATUS_FAILED:
- return mmc_server_connect(pool, mmc, io, udp TSRMLS_CC);
- }
-
- return MMC_REQUEST_FAILURE;
-}
-/* }}} */
-
-mmc_t *mmc_pool_find_next(mmc_pool_t *pool, const char *key, unsigned int key_len, mmc_queue_t *skip_servers, unsigned int *last_index TSRMLS_DC) /*
- finds the next server in the failover sequence {{{ */
-{
- mmc_t *mmc;
- char keytmp[MMC_MAX_KEY_LEN + MAX_LENGTH_OF_LONG + 1];
- unsigned int keytmp_len;
-
- /* find the next server not present in the skip-list */
- do {
- keytmp_len = sprintf(keytmp, "%s-%d", key, (*last_index)++);
- mmc = pool->hash->find_server(pool->hash_state, keytmp, keytmp_len TSRMLS_CC);
- } while (mmc_queue_contains(skip_servers, mmc) && *last_index < MEMCACHE_G(max_failover_attempts));
-
- return mmc;
-}
-
-mmc_t *mmc_pool_find(mmc_pool_t *pool, const char *key, unsigned int key_len TSRMLS_DC) /*
- maps a key to a non-failed server {{{ */
-{
- mmc_t *mmc = pool->hash->find_server(pool->hash_state, key, key_len TSRMLS_CC);
-
- /* check validity and try to failover otherwise */
- if (!mmc_server_valid(mmc TSRMLS_CC) && MEMCACHE_G(allow_failover)) {
- unsigned int last_index = 0;
-
- do {
- mmc = mmc_pool_find_next(pool, key, key_len, NULL, &last_index TSRMLS_CC);
- } while (!mmc_server_valid(mmc TSRMLS_CC) && last_index < MEMCACHE_G(max_failover_attempts));
- }
-
- return mmc;
-}
-/* }}} */
-
-int mmc_pool_failover_handler(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC) /*
- uses request->key to reschedule request to other server {{{ */
-{
- if (MEMCACHE_G(allow_failover) && request->failed_index < MEMCACHE_G(max_failover_attempts) && request->failed_servers.len < pool->num_servers) {
- do {
- mmc_queue_push(&(request->failed_servers), mmc);
- mmc = mmc_pool_find_next(pool, request->key, request->key_len, &(request->failed_servers), &(request->failed_index) TSRMLS_CC);
- } while (!mmc_server_valid(mmc TSRMLS_CC) && request->failed_index < MEMCACHE_G(max_failover_attempts) && request->failed_servers.len < pool->num_servers);
-
- return mmc_pool_schedule(pool, mmc, request TSRMLS_CC);
- }
-
- mmc_pool_release(pool, request);
- return MMC_REQUEST_FAILURE;
-}
-/* }}}*/
-
-static int mmc_pool_failover_handler_null(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC) /*
- always returns failure {{{ */
-{
- mmc_pool_release(pool, request);
- return MMC_REQUEST_FAILURE;
-}
-/* }}}*/
-
-static int mmc_pool_response_handler_null(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- always returns failure {{{ */
-{
- return MMC_REQUEST_DONE;
-}
-/* }}}*/
-
-static inline mmc_request_t *mmc_pool_request_alloc(mmc_pool_t *pool, int protocol,
- mmc_request_failover_handler failover_handler, void *failover_handler_param TSRMLS_DC) /* {{{ */
-{
- mmc_request_t *request = mmc_queue_pop(&(pool->free_requests));
- if (request == NULL) {
- request = pool->protocol->create_request();
- }
- else {
- pool->protocol->reset_request(request);
- }
-
- request->protocol = protocol;
-
- if (protocol == MMC_PROTO_UDP) {
- mmc_udp_header_t header = {0};
- smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
- }
-
- request->failover_handler = failover_handler != NULL ? failover_handler : mmc_pool_failover_handler_null;
- request->failover_handler_param = failover_handler_param;
-
- return request;
-}
-/* }}} */
-
-mmc_request_t *mmc_pool_request(mmc_pool_t *pool, int protocol,
- mmc_request_response_handler response_handler, void *response_handler_param,
- mmc_request_failover_handler failover_handler, void *failover_handler_param TSRMLS_DC) /*
- allocates a request, must be added to pool using mmc_pool_schedule or released with mmc_pool_release {{{ */
-{
- mmc_request_t *request = mmc_pool_request_alloc(pool, protocol, failover_handler, failover_handler_param TSRMLS_CC);
- request->response_handler = response_handler;
- request->response_handler_param = response_handler_param;
- return request;
-}
-/* }}} */
-
-mmc_request_t *mmc_pool_request_get(mmc_pool_t *pool, int protocol,
- mmc_request_value_handler value_handler, void *value_handler_param,
- mmc_request_failover_handler failover_handler, void *failover_handler_param TSRMLS_DC) /*
- allocates a request, must be added to pool using mmc_pool_schedule or released with mmc_pool_release {{{ */
-{
- mmc_request_t *request = mmc_pool_request(
- pool, protocol,
- mmc_pool_response_handler_null, NULL,
- failover_handler, failover_handler_param TSRMLS_CC);
-
- request->value_handler = value_handler;
- request->value_handler_param = value_handler_param;
- return request;
-}
-/* }}} */
-
-mmc_request_t *mmc_pool_clone_request(mmc_pool_t *pool, mmc_request_t *request TSRMLS_DC) /*
- clones a request, must be added to pool using mmc_pool_schedule or released with mmc_pool_release {{{ */
-{
- mmc_request_t *clone = mmc_pool_request_alloc(pool, request->protocol, NULL, NULL TSRMLS_CC);
-
- clone->response_handler = request->response_handler;
- clone->response_handler_param = request->response_handler_param;
- clone->value_handler = request->value_handler;
- clone->value_handler_param = request->value_handler_param;
-
- /* copy payload parser */
- clone->parse = request->parse;
-
- /* copy key */
- memcpy(clone->key, request->key, request->key_len);
- clone->key_len = request->key_len;
-
- /* copy sendbuf */
- mmc_buffer_alloc(&(clone->sendbuf), request->sendbuf.value.len);
- memcpy(clone->sendbuf.value.c, request->sendbuf.value.c, request->sendbuf.value.len);
- clone->sendbuf.value.len = request->sendbuf.value.len;
-
- return clone;
-}
-/* }}} */
-
-static int mmc_pool_slot_send(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, int handle_failover TSRMLS_DC) /* {{{ */
-{
- if (request != NULL) {
- /* select protocol strategy and open connection */
- if (request->protocol == MMC_PROTO_UDP && mmc->udp.port &&
- request->sendbuf.value.len <= mmc->udp.chunk_size &&
- mmc_pool_open(pool, mmc, &(mmc->udp), 1 TSRMLS_CC) == MMC_OK)
- {
- request->io = &(mmc->udp);
- request->read = mmc_request_read_udp;
-
- /* initialize udp header */
- request->udp.reqid = mmc->reqid++;
- request->udp.seqid = 0;
- request->udp.total = 0;
-
- ((mmc_udp_header_t *)request->sendbuf.value.c)->reqid = htons(request->udp.reqid);
- ((mmc_udp_header_t *)request->sendbuf.value.c)->total = htons(1);
- }
- else if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) == MMC_OK) {
- /* skip udp header */
- if (request->protocol == MMC_PROTO_UDP) {
- request->sendbuf.idx += sizeof(mmc_udp_header_t);
- }
-
- request->io = &(mmc->tcp);
- request->read = NULL;
- }
- else {
- mmc->sendreq = NULL;
- if (handle_failover) {
- return request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
- }
- return MMC_REQUEST_FAILURE;
- }
- }
-
- mmc->sendreq = request;
- return MMC_OK;
-}
-/* }}} */
-
-int mmc_pool_schedule(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- schedules a request against a server, return MMC_OK on success {{{ */
-{
- if (!mmc_server_valid(mmc TSRMLS_CC)) {
- /* delegate to failover handler if connect fails */
- return request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
- }
-
- /* reset sendbuf to start position */
- request->sendbuf.idx = 0;
- /* reset readbuf entirely */
- mmc_buffer_reset(&(request->readbuf));
-
- /* push request into sendreq slot if available */
- if (mmc->sendreq == NULL) {
- if (mmc_pool_slot_send(pool, mmc, request, 0 TSRMLS_CC) != MMC_OK) {
- return request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
- }
- mmc_queue_push(pool->sending, mmc);
- }
- else {
- mmc_queue_push(&(mmc->sendqueue), request);
- }
-
- /* push request into readreq slot if available */
- if (mmc->readreq == NULL) {
- mmc->readreq = request;
- mmc_queue_push(pool->reading, mmc);
- }
- else {
- mmc_queue_push(&(mmc->readqueue), request);
- }
-
- return MMC_OK;
-}
-/* }}} */
-
-int mmc_pool_schedule_key(mmc_pool_t *pool, const char *key, unsigned int key_len, mmc_request_t *request, unsigned int redundancy TSRMLS_DC) /*
- schedules a request against a server selected by the provided key, return MMC_OK on success {{{ */
-{
- if (redundancy > 1) {
- int i, result;
- mmc_t *mmc;
-
- unsigned int last_index = 0;
- mmc_queue_t skip_servers = {0};
-
- /* schedule the first request */
- mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC);
- result = mmc_pool_schedule(pool, mmc, request TSRMLS_CC);
-
- /* clone and schedule redundancy-1 additional requests */
- for (i=0; i < redundancy-1 && i < pool->num_servers-1; i++) {
- mmc_queue_push(&skip_servers, mmc);
- mmc = mmc_pool_find_next(pool, key, key_len, &skip_servers, &last_index TSRMLS_CC);
-
- if (mmc_server_valid(mmc TSRMLS_CC)) {
- mmc_pool_schedule(pool, mmc, mmc_pool_clone_request(pool, request TSRMLS_CC) TSRMLS_CC);
- }
- }
-
- mmc_queue_free(&skip_servers);
- return result;
- }
-
- return mmc_pool_schedule(pool, mmc_pool_find(pool, key, key_len TSRMLS_CC), request TSRMLS_CC);
-}
-/* }}} */
-
-int mmc_pool_schedule_get(
- mmc_pool_t *pool, int protocol, int op, zval *zkey,
- mmc_request_value_handler value_handler, void *value_handler_param,
- mmc_request_failover_handler failover_handler, void *failover_handler_param,
- mmc_request_t *failed_request TSRMLS_DC) /*
- schedules a get command against a server {{{ */
-{
- mmc_t *mmc;
- char key[MMC_MAX_KEY_LEN + 1];
- unsigned int key_len;
-
- if (mmc_prepare_key(zkey, key, &key_len) != MMC_OK) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
- return MMC_REQUEST_FAILURE;
- }
-
- mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC);
- if (!mmc_server_valid(mmc TSRMLS_CC)) {
- return MMC_REQUEST_FAILURE;
- }
-
- if (mmc->buildreq == NULL) {
- mmc_queue_push(&(pool->pending), mmc);
-
- mmc->buildreq = mmc_pool_request_get(
- pool, protocol, value_handler, value_handler_param,
- failover_handler, failover_handler_param TSRMLS_CC);
-
- if (failed_request != NULL) {
- mmc_queue_copy(&(failed_request->failed_servers), &(mmc->buildreq->failed_servers));
- mmc->buildreq->failed_index = failed_request->failed_index;
- }
-
- pool->protocol->begin_get(mmc->buildreq, op);
- }
- else if (protocol == MMC_PROTO_UDP && mmc->buildreq->sendbuf.value.len + key_len + 3 > MMC_MAX_UDP_LEN) {
- /* datagram if full, schedule for delivery */
- pool->protocol->end_get(mmc->buildreq);
- mmc_pool_schedule(pool, mmc, mmc->buildreq TSRMLS_CC);
-
- /* begin sending requests immediatly */
- mmc_pool_select(pool, 0 TSRMLS_CC);
-
- mmc->buildreq = mmc_pool_request_get(
- pool, protocol, value_handler, value_handler_param,
- failover_handler, failover_handler_param TSRMLS_CC);
-
- if (failed_request != NULL) {
- mmc_queue_copy(&(failed_request->failed_servers), &(mmc->buildreq->failed_servers));
- mmc->buildreq->failed_index = failed_request->failed_index;
- }
-
- pool->protocol->begin_get(mmc->buildreq, op);
- }
-
- pool->protocol->append_get(mmc->buildreq, zkey, key, key_len);
- return MMC_OK;
-}
-/* }}} */
-
-static inline void mmc_pool_switch(mmc_pool_t *pool) {
- /* switch sending and reading queues */
- if (pool->sending == &(pool->_sending1)) {
- pool->sending = &(pool->_sending2);
- pool->reading = &(pool->_reading2);
- }
- else {
- pool->sending = &(pool->_sending1);
- pool->reading = &(pool->_reading1);
- }
-
- /* reset queues so they can be re-populated */
- mmc_queue_reset(pool->sending);
- mmc_queue_reset(pool->reading);
-}
-
-static void mmc_select_failure(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, int result TSRMLS_DC) /* {{{ */
-{
- if (result == 0) {
- /* timeout expired, non-responsive server */
- if (mmc_server_failure(mmc, request->io, "Network timeout", 0 TSRMLS_CC) != MMC_REQUEST_RETRY) {
- mmc_server_deactivate(pool, mmc TSRMLS_CC);
- }
- }
- else {
- /* hard failure, deactivate connection */
- mmc_server_seterror(mmc, "Unknown select() error", errno);
- mmc_server_deactivate(pool, mmc TSRMLS_CC);
- }
-}
-/* }}} */
-
-static void mmc_select_retry(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
- removes request from send/read queues and calls failover {{{ */
-{
- mmc_queue_remove(&(mmc->sendqueue), request);
- mmc_queue_remove(&(mmc->readqueue), request);
-
- if (mmc->sendreq == request) {
- mmc_pool_slot_send(pool, mmc, mmc_queue_pop(&(mmc->sendqueue)), 1 TSRMLS_CC);
- }
-
- if (mmc->readreq == request) {
- mmc->readreq = mmc_queue_pop(&(mmc->readqueue));
- }
-
- request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
-}
-/* }}} */
-
-void mmc_pool_select(mmc_pool_t *pool, long timeout TSRMLS_DC) /*
- runs one select() round on all scheduled requests {{{ */
-{
- int i, fd, result;
- mmc_t *mmc;
- mmc_queue_t *sending, *reading;
-
- /* help complete previous run */
- if (pool->in_select) {
- if (pool->sending == &(pool->_sending1)) {
- sending = &(pool->_sending2);
- reading = &(pool->_reading2);
- }
- else {
- sending = &(pool->_sending1);
- reading = &(pool->_reading1);
- }
- }
- else {
- struct timeval tv;
- int nfds = 0;
-
- sending = pool->sending;
- reading = pool->reading;
- mmc_pool_switch(pool);
-
- FD_ZERO(&(pool->wfds));
- FD_ZERO(&(pool->rfds));
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- for (i=0; i < sending->len; i++) {
- mmc = mmc_queue_item(sending, i);
- if (mmc->sendreq->io->fd > nfds) {
- nfds = mmc->sendreq->io->fd;
- }
- FD_SET(mmc->sendreq->io->fd, &(pool->wfds));
- }
-
- for (i=0; i < reading->len; i++) {
- mmc = mmc_queue_item(reading, i);
- if (mmc->readreq->io->fd > nfds) {
- nfds = mmc->readreq->io->fd;
- }
- FD_SET(mmc->readreq->io->fd, &(pool->rfds));
- }
-
- result = select(nfds + 1, &(pool->rfds), &(pool->wfds), NULL, &tv);
-
- if (result <= 0) {
- for (i=0; i < sending->len; i++) {
- mmc = (mmc_t *)mmc_queue_item(sending, i);
- if (!FD_ISSET(mmc->sendreq->io->fd, &(pool->wfds))) {
- mmc_queue_remove(sending, mmc);
- mmc_select_failure(pool, mmc, mmc->sendreq, result TSRMLS_CC);
- }
- }
-
- for (i=0; i < reading->len; i++) {
- mmc = (mmc_t *)mmc_queue_item(reading, i);
- if (!FD_ISSET(mmc->readreq->io->fd, &(pool->rfds))) {
- mmc_queue_remove(reading, mmc);
- mmc_select_failure(pool, mmc, mmc->readreq, result TSRMLS_CC);
- }
- }
- }
-
- pool->in_select = 1;
- }
-
- /* until stream buffer is empty */
- for (i=0; i < sending->len; i++) {
- mmc = mmc_queue_item(sending, i);
-
- if (FD_ISSET(mmc->sendreq->io->fd, &(pool->wfds))) {
- fd = mmc->sendreq->io->fd;
-
- do {
- /* delegate to request parse handler */
- result = mmc_request_send(mmc, mmc->sendreq TSRMLS_CC);
-
- /* check if someone has helped complete our run */
- if (!pool->in_select) {
- return;
- }
-
- switch (result) {
- case MMC_REQUEST_FAILURE:
- /* clear readbit for this round */
- FD_CLR(mmc->sendreq->io->fd, &(pool->rfds));
-
- /* take server offline and failover requests */
- mmc_server_deactivate(pool, mmc TSRMLS_CC);
- break;
-
- case MMC_REQUEST_RETRY:
- /* allow request to reschedule itself */
- mmc_select_retry(pool, mmc, mmc->sendreq TSRMLS_CC);
- break;
-
- case MMC_REQUEST_DONE:
- /* shift next request into send slot */
- mmc_pool_slot_send(pool, mmc, mmc_queue_pop(&(mmc->sendqueue)), 1 TSRMLS_CC);
- break;
-
- case MMC_REQUEST_MORE:
- /* send more data to socket */
- break;
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid return value, bailing out");
- }
- } while (mmc->sendreq != NULL && (result == MMC_REQUEST_DONE || result == MMC_REQUEST_AGAIN));
-
- if (result == MMC_REQUEST_MORE) {
- /* add server to read queue once more */
- mmc_queue_push(pool->sending, mmc);
- }
-
- /* clear bit for reentrancy reasons */
- FD_CLR(fd, &(pool->wfds));
- }
- else {
- /* add server to send queue once more */
- mmc_queue_push(pool->sending, mmc);
- }
- }
-
- for (i=0; i < reading->len; i++) {
- mmc = mmc_queue_item(reading, i);
-
- if (FD_ISSET(mmc->readreq->io->fd, &(pool->rfds))) {
- fd = mmc->readreq->io->fd;
-
- /* fill read buffer if needed */
- if (mmc->readreq->read != NULL) {
- result = mmc->readreq->read(mmc, mmc->readreq TSRMLS_CC);
-
- if (result != MMC_OK) {
- switch (result) {
- case MMC_REQUEST_FAILURE:
- /* take server offline and failover requests */
- mmc_server_deactivate(pool, mmc TSRMLS_CC);
- break;
-
- case MMC_REQUEST_RETRY:
- /* allow request to reschedule itself */
- mmc_select_retry(pool, mmc, mmc->readreq TSRMLS_CC);
- break;
-
- case MMC_REQUEST_MORE:
- /* add server to read queue once more */
- mmc_queue_push(pool->reading, mmc);
- break;
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid return value, bailing out");
- }
-
- /* skip to next request */
- continue;
- }
- }
-
- do {
- /* delegate to request response handler */
- result = mmc->readreq->parse(mmc, mmc->readreq TSRMLS_CC);
-
- /* check if someone has helped complete our run */
- if (!pool->in_select) {
- return;
- }
-
- switch (result) {
- case MMC_REQUEST_FAILURE:
- /* take server offline and failover requests */
- mmc_server_deactivate(pool, mmc TSRMLS_CC);
- break;
-
- case MMC_REQUEST_RETRY:
- /* allow request to reschedule itself */
- mmc_select_retry(pool, mmc, mmc->readreq TSRMLS_CC);
- break;
-
- case MMC_REQUEST_DONE:
- /* release completed request */
- mmc_pool_release(pool, mmc->readreq);
-
- /* shift next request into read slot */
- mmc->readreq = mmc_queue_pop(&(mmc->readqueue));
- break;
-
- case MMC_REQUEST_MORE:
- /* read more data from socket */
- if (php_stream_eof(mmc->readreq->io->stream)) {
- result = mmc_server_failure(mmc, mmc->readreq->io, "Read failed (socket was unexpectedly closed)", 0 TSRMLS_CC);
- if (result == MMC_REQUEST_FAILURE) {
- /* take server offline and failover requests */
- mmc_server_deactivate(pool, mmc TSRMLS_CC);
- }
- }
- break;
-
- case MMC_REQUEST_AGAIN:
- /* request wants another loop */
- break;
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid return value, bailing out");
- }
- } while (mmc->readreq != NULL && (result == MMC_REQUEST_DONE || result == MMC_REQUEST_AGAIN));
-
- if (result == MMC_REQUEST_MORE) {
- /* add server to read queue once more */
- mmc_queue_push(pool->reading, mmc);
- }
-
- /* clear bit for reentrancy reasons */
- FD_CLR(fd, &(pool->rfds));
- }
- else {
- /* add server to read queue once more */
- mmc_queue_push(pool->reading, mmc);
- }
- }
-
- pool->in_select = 0;
-}
-/* }}} */
-
-void mmc_pool_run(mmc_pool_t *pool TSRMLS_DC) /*
- runs all scheduled requests to completion {{{ */
-{
- mmc_t *mmc;
- while ((mmc = mmc_queue_pop(&(pool->pending))) != NULL) {
- pool->protocol->end_get(mmc->buildreq);
- mmc_pool_schedule(pool, mmc, mmc->buildreq TSRMLS_CC);
- mmc->buildreq = NULL;
- }
-
- while (pool->reading->len || pool->sending->len) {
- /* TODO: replace 1 with pool->timeout */
- mmc_pool_select(pool, 1 TSRMLS_CC);
- }
-}
-/* }}} */
-
-inline int mmc_prepare_key_ex(const char *key, unsigned int key_len, char *result, unsigned int *result_len) /* {{{ */
-{
- unsigned int i;
- if (key_len == 0) {
- return MMC_REQUEST_FAILURE;
- }
-
- *result_len = key_len < MMC_MAX_KEY_LEN ? key_len : MMC_MAX_KEY_LEN;
- result[*result_len] = '\0';
-
- for (i=0; i<*result_len; i++) {
- result[i] = ((unsigned char)key[i]) > ' ' ? key[i] : '_';
- }
-
- return MMC_OK;
-}
-/* }}} */
-
-inline int mmc_prepare_key(zval *key, char *result, unsigned int *result_len) /* {{{ */
-{
- if (Z_TYPE_P(key) == IS_STRING) {
- return mmc_prepare_key_ex(Z_STRVAL_P(key), Z_STRLEN_P(key), result, result_len);
- } else {
- int res;
- zval *keytmp;
- ALLOC_ZVAL(keytmp);
-
- *keytmp = *key;
- zval_copy_ctor(keytmp);
- INIT_PZVAL(keytmp);
- convert_to_string(keytmp);
-
- res = mmc_prepare_key_ex(Z_STRVAL_P(keytmp), Z_STRLEN_P(keytmp), result, result_len);
-
- zval_dtor(keytmp);
- FREE_ZVAL(keytmp);
-
- return res;
- }
-}
-/* }}} */
-
-
-/*
- * 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-3.0.1.tgz/memcache-3.0.1/memcache_pool.h
^
|
@@ -1,363 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_pool.h,v 1.1.2.16 2008/01/09 21:31:01 mikl Exp $ */
-
-#ifndef MEMCACHE_POOL_H
-#define MEMCACHE_POOL_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdint.h>
-#include <string.h>
-
-#include "php.h"
-#include "ext/standard/php_smart_str_public.h"
-#include "memcache_queue.h"
-
-#ifndef ZSTR
-#define ZSTR
-#define ZSTR_VAL(v) v
-#define zstr char *
-#else
-#define ZSTR_VAL(v) (v).s
-#endif
-
-#define MMC_SERIALIZED 1
-#define MMC_COMPRESSED 2
-
-#define MMC_BUFFER_SIZE 4096
-#define MMC_MAX_UDP_LEN 1400
-#define MMC_MAX_KEY_LEN 250
-#define MMC_VALUE_HEADER "VALUE %250s %u %lu %lu" /* keep in sync with MMC_MAX_KEY_LEN */
-
-#define MMC_COMPRESSION_LEVEL Z_DEFAULT_COMPRESSION
-#define MMC_DEFAULT_SAVINGS 0.2 /* minimum 20% savings for compression to be used */
-
-#define MMC_PROTO_TCP 0
-#define MMC_PROTO_UDP 1
-
-#define MMC_STATUS_FAILED -1 /* server/stream is down */
-#define MMC_STATUS_DISCONNECTED 0 /* stream is disconnected, ie. new connection */
-#define MMC_STATUS_UNKNOWN 1 /* stream is in unknown state, ie. non-validated persistent connection */
-#define MMC_STATUS_CONNECTED 2 /* stream is connected */
-
-#define MMC_OK 0
-
-#define MMC_REQUEST_FAILURE -1 /* operation failed, failover to other server */
-#define MMC_REQUEST_DONE 0 /* ok result, or reading/writing is done */
-#define MMC_REQUEST_MORE 1 /* more data follows in another packet, try select() again */
-#define MMC_REQUEST_AGAIN 2 /* more data follows in this packet, try read/write again */
-#define MMC_REQUEST_RETRY 3 /* retry/reschedule request */
-
-#define MMC_RESPONSE_UNKNOWN -2
-#define MMC_RESPONSE_ERROR -1
-#define MMC_RESPONSE_NOT_FOUND 0x01 /* same as binary protocol */
-#define MMC_RESPONSE_EXISTS 0x02 /* same as binary protocol */
-#define MMC_RESPONSE_TOO_LARGE 0x03 /* same as binary protocol */
-#define MMC_RESPONSE_NOT_STORED 0x05 /* same as binary protocol */
-#define MMC_RESPONSE_OUT_OF_MEMORY 0x82 /* same as binary protocol */
-
-#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 */
-
-/* io buffer */
-typedef struct mmc_buffer {
- smart_str value;
- unsigned int idx; /* current index */
-} mmc_buffer_t;
-
-#define mmc_buffer_release(b) memset((b), 0, sizeof(*(b)))
-#define mmc_buffer_reset(b) (b)->value.len = (b)->idx = 0
-
-inline void mmc_buffer_alloc(mmc_buffer_t *, unsigned int);
-inline void mmc_buffer_free(mmc_buffer_t *);
-
-/* stream handlers */
-typedef struct mmc_stream mmc_stream_t;
-
-typedef size_t (*mmc_stream_read)(mmc_stream_t *stream, char *buf, size_t count TSRMLS_DC);
-typedef char *(*mmc_stream_readline)(mmc_stream_t *stream, char *buf, size_t maxlen, size_t *retlen TSRMLS_DC);
-
-/* stream container */
-struct mmc_stream {
- php_stream *stream;
- int fd; /* file descriptor for select() */
- unsigned short port;
- int chunk_size; /* stream chunk size */
- int status;
- long failed; /* the timestamp the stream was marked as failed */
- long retry_interval; /* seconds to wait before automatic reconnect */
- mmc_buffer_t buffer; /* read buffer (when using udp) */
- mmc_stream_read read; /* handles reading from stream */
- mmc_stream_readline readline; /* handles reading lines from stream */
- struct { /* temporary input buffer, see mmc_server_readline() */
- char value[MMC_BUFFER_SIZE];
- int idx;
- } input;
-};
-
-/* request handlers */
-typedef struct mmc mmc_t;
-typedef struct mmc_pool mmc_pool_t;
-typedef struct mmc_request mmc_request_t;
-
-typedef int (*mmc_request_reader)(mmc_t *mmc, mmc_request_t *request TSRMLS_DC);
-typedef int (*mmc_request_parser)(mmc_t *mmc, mmc_request_t *request TSRMLS_DC);
-typedef int (*mmc_request_value_handler)(
- const char *key, unsigned int key_len, void *value, unsigned int value_len,
- unsigned int flags, unsigned long cas, void *param TSRMLS_DC);
-typedef int (*mmc_request_response_handler)(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC);
-typedef int (*mmc_request_failover_handler)(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC);
-
-void mmc_request_reset(mmc_request_t *);
-void mmc_request_free(mmc_request_t *);
-
-/* server request */
-struct mmc_request {
- mmc_stream_t *io; /* stream this request is sending on */
- mmc_buffer_t sendbuf; /* request buffer */
- mmc_buffer_t readbuf; /* response buffer */
- char key[MMC_MAX_KEY_LEN + 1]; /* key buffer to use on failover of single-key requests */
- unsigned int key_len;
- unsigned int protocol; /* protocol encoding of request {tcp, udp} */
- mmc_queue_t failed_servers; /* mmc_queue_t<mmc_t *>, servers this request has failed at */
- unsigned int failed_index; /* last index probed on failure */
- mmc_request_reader read; /* handles reading (and validating datagrams) */
- mmc_request_parser parse; /* called to parse response payload */
- mmc_request_value_handler value_handler; /* called when result value have been parsed */
- void *value_handler_param;
- mmc_request_response_handler response_handler; /* called when a non-value response has been received */
- void *response_handler_param;
- mmc_request_failover_handler failover_handler; /* called to perform failover of failed request */
- void *failover_handler_param;
- struct {
- uint16_t reqid; /* id of the request, increasing value set by client */
- uint16_t seqid; /* next expected seqid */
- uint16_t total; /* number of datagrams in response */
- } udp;
-};
-
-/* udp protocol header */
-typedef struct mmc_udp_header {
- uint16_t reqid; /* id of the request, increasing value set by client */
- uint16_t seqid; /* index of this datagram in response */
- uint16_t total; /* number of datagrams in response */
- uint16_t _reserved;
-} mmc_udp_header_t;
-
-/* server */
-struct mmc {
- mmc_stream_t tcp; /* main stream, might be tcp or unix socket */
- mmc_stream_t udp; /* auxiliary udp connection */
- mmc_request_t *sendreq; /* currently sending request, NULL if none */
- mmc_request_t *readreq; /* currently reading request, NULL if none */
- mmc_request_t *buildreq; /* request currently being built, NULL if none */
- mmc_queue_t sendqueue; /* mmc_queue_t<mmc_request_t *>, requests waiting to be sent */
- mmc_queue_t readqueue; /* mmc_queue_t<mmc_request_t *>, requests waiting to be read */
- char *host;
- long timeout; /* network timeout */
- int persistent;
- uint16_t reqid; /* next sequential request id */
- char *error; /* last error message */
- int errnum; /* last error code */
-};
-
-/* wire protocol */
-#define MMC_ASCII_PROTOCOL 1
-#define MMC_BINARY_PROTOCOL 2
-
-/* same as in binary protocol */
-#define MMC_OP_GET 0x00
-#define MMC_OP_SET 0x01
-#define MMC_OP_ADD 0x02
-#define MMC_OP_REPLACE 0x03
-#define MMC_OP_GETS 0x32
-#define MMC_OP_CAS 0x33
-#define MMC_OP_APPEND 0x34 /* not supported by binary protocol */
-#define MMC_OP_PREPEND 0x35 /* not supported by binary protocol */
-
-typedef mmc_request_t * (*mmc_protocol_create_request)();
-typedef void (*mmc_protocol_reset_request)(mmc_request_t *request);
-typedef void (*mmc_protocol_free_request)(mmc_request_t *request);
-
-typedef void (*mmc_protocol_get)(mmc_request_t *request, int op, zval *zkey, const char *key, unsigned int key_len);
-typedef void (*mmc_protocol_begin_get)(mmc_request_t *request, int op);
-typedef void (*mmc_protocol_append_get)(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len);
-typedef void (*mmc_protocol_end_get)(mmc_request_t *request);
-
-typedef int (*mmc_protocol_store)(
- mmc_pool_t *pool, mmc_request_t *request, int op, const char *key, unsigned int key_len,
- unsigned int flags, unsigned int exptime, unsigned long cas, zval *value TSRMLS_DC);
-typedef void (*mmc_protocol_delete)(mmc_request_t *request, const char *key, unsigned int key_len, unsigned int exptime);
-typedef void (*mmc_protocol_mutate)(mmc_request_t *request, const char *key, unsigned int key_len, long value, long defval, unsigned int exptime);
-
-typedef void (*mmc_protocol_flush)(mmc_request_t *request, unsigned int exptime);
-typedef void (*mmc_protocol_stats)(mmc_request_t *request, const char *type, long slabid, long limit);
-typedef void (*mmc_protocol_version)(mmc_request_t *request);
-
-typedef struct mmc_protocol {
- mmc_protocol_create_request create_request;
- mmc_protocol_reset_request reset_request;
- mmc_protocol_free_request free_request;
-
- mmc_protocol_get get;
- mmc_protocol_begin_get begin_get;
- mmc_protocol_append_get append_get;
- mmc_protocol_end_get end_get;
-
- mmc_protocol_store store;
- mmc_protocol_delete delete;
- mmc_protocol_mutate mutate;
-
- mmc_protocol_flush flush;
- mmc_protocol_version version;
- mmc_protocol_stats stats;
-} mmc_protocol_t;
-
-extern mmc_protocol_t mmc_ascii_protocol;
-extern mmc_protocol_t mmc_binary_protocol;
-
-/* hashing strategy */
-typedef unsigned int (*mmc_hash_function)(const char *key, unsigned int key_len);
-typedef void * (*mmc_hash_create_state)(mmc_hash_function);
-typedef void (*mmc_hash_free_state)(void *state);
-typedef mmc_t * (*mmc_hash_find_server)(void *state, const char *key, unsigned int key_len TSRMLS_DC);
-typedef void (*mmc_hash_add_server)(void *state, mmc_t *mmc, unsigned int weight);
-
-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;
-
-extern mmc_hash_t mmc_standard_hash;
-extern mmc_hash_t mmc_consistent_hash;
-
-/* 32 bit magic FNV-1a prime and init */
-#define FNV_32_PRIME 0x01000193
-#define FNV_32_INIT 0x811c9dc5
-
-/* failure callback prototype */
-typedef void (*mmc_failure_callback)(mmc_pool_t *pool, mmc_t *mmc, void *param TSRMLS_DC);
-
-/* server pool */
-struct mmc_pool {
- mmc_t **servers;
- int num_servers;
- mmc_protocol_t *protocol; /* wire protocol */
- mmc_hash_t *hash; /* hash strategy */
- void *hash_state; /* strategy specific state */
- fd_set wfds;
- fd_set rfds;
- int in_select;
- mmc_queue_t *sending; /* mmc_queue_t<mmc_t *>, connections that want to send */
- mmc_queue_t *reading; /* mmc_queue_t<mmc_t *>, connections that want to read */
- mmc_queue_t _sending1, _sending2;
- mmc_queue_t _reading1, _reading2;
- mmc_queue_t pending; /* mmc_queue_t<mmc_t *>, connections that have non-finalized requests */
- mmc_queue_t free_requests; /* mmc_queue_t<mmc_request_t *>, request free-list */
- double min_compress_savings;
- unsigned int compress_threshold;
- mmc_failure_callback failure_callback; /* receives notification when a server fails */
- void *failure_callback_param;
-};
-
-/* server functions */
-mmc_t *mmc_server_new(const char *, int, unsigned short, unsigned short, int, int, int TSRMLS_DC);
-void mmc_server_free(mmc_t * TSRMLS_DC);
-void mmc_server_disconnect(mmc_t *mmc, mmc_stream_t *io TSRMLS_DC);
-int mmc_server_valid(mmc_t * TSRMLS_DC);
-int mmc_server_failure(mmc_t *, mmc_stream_t *, const char *, int TSRMLS_DC);
-int mmc_request_failure(mmc_t *, mmc_stream_t *, const char *, unsigned int, int TSRMLS_DC);
-
-/* pool functions */
-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);
-void mmc_pool_close(mmc_pool_t * TSRMLS_DC);
-int mmc_pool_open(mmc_pool_t *, mmc_t *, mmc_stream_t *, int TSRMLS_DC);
-void mmc_pool_select(mmc_pool_t *, long TSRMLS_DC);
-void mmc_pool_run(mmc_pool_t * TSRMLS_DC);
-mmc_t *mmc_pool_find_next(mmc_pool_t *, const char *, unsigned int, mmc_queue_t *, unsigned int * TSRMLS_DC);
-mmc_t *mmc_pool_find(mmc_pool_t *, const char *, unsigned int TSRMLS_DC);
-int mmc_pool_schedule(mmc_pool_t *, mmc_t *, mmc_request_t * TSRMLS_DC);
-int mmc_pool_failover_handler(mmc_pool_t *, mmc_t *, mmc_request_t *, void * TSRMLS_DC);
-
-mmc_request_t *mmc_pool_request(mmc_pool_t *, int,
- mmc_request_response_handler, void *, mmc_request_failover_handler, void * TSRMLS_DC);
-mmc_request_t *mmc_pool_request_get(mmc_pool_t *, int,
- mmc_request_value_handler, void *, mmc_request_failover_handler, void * TSRMLS_DC);
-
-#define mmc_pool_release(p, r) mmc_queue_push(&((p)->free_requests), (r))
-
-int mmc_prepare_store(
- mmc_pool_t *, mmc_request_t *, const char *, unsigned int,
- const char *, unsigned int, unsigned int, unsigned int, zval * TSRMLS_DC);
-
-int mmc_pool_schedule_key(mmc_pool_t *, const char *, unsigned int, mmc_request_t *, unsigned int TSRMLS_DC);
-int mmc_pool_schedule_get(mmc_pool_t *, int, int, zval *,
- mmc_request_value_handler, void *, mmc_request_failover_handler, void *, mmc_request_t * TSRMLS_DC);
-
-/* utility functions */
-int mmc_pack_value(mmc_pool_t *, mmc_buffer_t *, zval *, unsigned int * TSRMLS_DC);
-int mmc_unpack_value(mmc_t *, mmc_request_t *, mmc_buffer_t *, const char *, unsigned int, unsigned int, unsigned long, unsigned int TSRMLS_DC);
-
-inline int mmc_prepare_key_ex(const char *, unsigned int, char *, unsigned int *);
-inline int mmc_prepare_key(zval *, char *, unsigned int *);
-
-#define mmc_str_left(h, n, hlen, nlen) ((hlen) >= (nlen) ? memcmp((h), (n), (nlen)) == 0 : 0)
-
-/* globals */
-ZEND_BEGIN_MODULE_GLOBALS(memcache)
- long default_port;
- long chunk_size;
- long protocol;
- long hash_strategy;
- long hash_function;
- long allow_failover;
- long max_failover_attempts;
- long redundancy;
- long session_redundancy;
-ZEND_END_MODULE_GLOBALS(memcache)
-
-#ifdef ZTS
-#define MEMCACHE_G(v) TSRMG(memcache_globals_id, zend_memcache_globals *, v)
-#else
-#define MEMCACHE_G(v) (memcache_globals.v)
-#endif
-
-#endif /* MEMCACHE_POOL_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-3.0.1.tgz/memcache-3.0.1/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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_queue.c,v 1.1.2.1 2007/09/27 17:54:18 mikl Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "memcache_queue.h"
-
-inline 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++;
-}
-
-inline 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;
-}
-
-inline 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;
-}
-
-inline void mmc_queue_free(mmc_queue_t *queue) {
- if (queue->items != NULL) {
- efree(queue->items);
- }
- memset(queue, 0, sizeof(*queue));
-}
-
-inline 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;
-}
-
-inline 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-3.0.1.tgz/memcache-3.0.1/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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_queue.h,v 1.1.2.1 2007/09/27 17:54:18 mikl 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)])
-
-inline void mmc_queue_push(mmc_queue_t *, void *);
-inline void *mmc_queue_pop(mmc_queue_t *);
-inline int mmc_queue_contains(mmc_queue_t *, void *);
-inline void mmc_queue_free(mmc_queue_t *);
-inline void mmc_queue_copy(mmc_queue_t *, mmc_queue_t *);
-inline 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-3.0.1.tgz/memcache-3.0.1/memcache_session.c
^
|
@@ -1,350 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_session.c,v 1.3.2.9 2007/11/03 16:22:31 mikl 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/php_smart_str.h"
-#include "ext/standard/url.h"
-#include "php_memcache.h"
-
-ZEND_EXTERN_MODULE_GLOBALS(memcache)
-
-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, udp_port = 0, weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY;
- url = php_url_parse_ex(save_path+i, j-i);
-
- /* 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), "udp_port", sizeof("udp_port"), (void **) ¶m) != FAILURE) {
- convert_to_long_ex(param);
- udp_port = Z_LVAL_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->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, udp_port, timeout, retry_interval TSRMLS_CC);
- }
- else {
- mmc = mmc_server_new(url->host, strlen(url->host), url->port, udp_port, 0, timeout, retry_interval TSRMLS_CC);
- }
-
- mmc_pool_add(pool, mmc, 1);
- 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;
-}
-/* }}} */
-
-static mmc_request_t *php_mmc_session_read_request(mmc_pool_t *pool, zval *zkey, zval **param TSRMLS_DC) /* {{{ */
-{
- mmc_request_t *request = mmc_pool_request_get(
- pool, MMC_PROTO_UDP,
- mmc_value_handler_single, param,
- mmc_pool_failover_handler, NULL TSRMLS_CC);
-
- if (mmc_prepare_key_ex(Z_STRVAL_P(zkey), Z_STRLEN_P(zkey), request->key, &(request->key_len)) != MMC_OK) {
- mmc_pool_release(pool, request);
- return NULL;
- }
-
- pool->protocol->get(request, MMC_OP_GET, zkey, request->key, request->key_len);
- return request;
-}
-/* }}} */
-
-/* {{{ PS_READ_FUNC
- */
-PS_READ_FUNC(memcache)
-{
- mmc_pool_t *pool = PS_GET_MOD_DATA();
-
- if (pool != NULL) {
- zval result, zkey;
- zval *value_handler_param[3];
-
- mmc_t *mmc;
- mmc_request_t *request;
- mmc_queue_t skip_servers;
- unsigned int last_index = 0;
-
- ZVAL_FALSE(&result);
- value_handler_param[0] = &result;
- value_handler_param[1] = NULL;
- value_handler_param[2] = NULL;
-
- ZVAL_STRING(&zkey, (char *)key, 0);
- memset(&skip_servers, 0, sizeof(skip_servers));
-
- /* create request */
- request = php_mmc_session_read_request(pool, &zkey, value_handler_param TSRMLS_CC);
- if (request == NULL) {
- return FAILURE;
- }
-
- /* schedule the first request */
- mmc = mmc_pool_find(pool, request->key, request->key_len TSRMLS_CC);
- if (mmc_pool_schedule(pool, mmc, request TSRMLS_CC) != MMC_OK) {
- return FAILURE;
- }
-
- /* execute request */
- mmc_pool_run(pool TSRMLS_CC);
-
- /* retry missing value (possibly due to server restart) */
- while (Z_TYPE(result) != IS_STRING && skip_servers.len < MEMCACHE_G(session_redundancy)-1 && skip_servers.len < pool->num_servers) {
- request = php_mmc_session_read_request(pool, &zkey, value_handler_param TSRMLS_CC);
- if (request == NULL) {
- break;
- }
-
- zval_dtor(&result);
- mmc_queue_push(&skip_servers, mmc);
- mmc = mmc_pool_find_next(pool, request->key, request->key_len, &skip_servers, &last_index TSRMLS_CC);
-
- if (mmc_server_valid(mmc TSRMLS_CC)) {
- mmc_pool_schedule(pool, mmc, request TSRMLS_CC);
- mmc_pool_run(pool TSRMLS_CC);
- }
- }
-
- mmc_queue_free(&skip_servers);
-
- if (Z_TYPE(result) == IS_STRING) {
- *val = Z_STRVAL(result);
- *vallen = Z_STRLEN(result);
- return SUCCESS;
- }
-
- zval_dtor(&result);
- }
-
- return FAILURE;
-}
-/* }}} */
-
-/* {{{ PS_WRITE_FUNC
- */
-PS_WRITE_FUNC(memcache)
-{
- mmc_pool_t *pool = PS_GET_MOD_DATA();
-
- if (pool != NULL) {
- zval result, value;
- mmc_request_t *request;
-
- /* allocate request */
- request = mmc_pool_request(pool, MMC_PROTO_TCP,
- mmc_stored_handler, &result, mmc_pool_failover_handler, NULL TSRMLS_CC);
-
- if (mmc_prepare_key_ex(key, strlen(key), request->key, &(request->key_len)) != MMC_OK) {
- mmc_pool_release(pool, request);
- return FAILURE;
- }
-
- ZVAL_NULL(&result);
- ZVAL_STRINGL(&value, (char *)val, vallen, 0);
-
- /* assemble command */
- if (pool->protocol->store(pool, request, MMC_OP_SET, request->key, request->key_len, 0, INI_INT("session.gc_maxlifetime"), 0, &value TSRMLS_CC) != MMC_OK) {
- mmc_pool_release(pool, request);
- return FAILURE;
- }
-
- /* schedule request */
- if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(session_redundancy) TSRMLS_CC) != MMC_OK) {
- return FAILURE;
- }
-
- /* execute request */
- mmc_pool_run(pool TSRMLS_CC);
-
- if (Z_BVAL(result)) {
- return SUCCESS;
- }
- }
-
- return FAILURE;
-}
-/* }}} */
-
-static int mmc_deleted_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
- parses a DELETED response line, param is a zval pointer to store result into {{{ */
-{
- if (response == MMC_OK || response == MMC_RESPONSE_NOT_FOUND)
- {
- ZVAL_TRUE((zval *)param);
- return MMC_REQUEST_DONE;
- }
-
- return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ PS_DESTROY_FUNC
- */
-PS_DESTROY_FUNC(memcache)
-{
- mmc_pool_t *pool = PS_GET_MOD_DATA();
-
- if (pool != NULL) {
- zval result;
- mmc_request_t *request;
-
- /* allocate request */
- request = mmc_pool_request(pool, MMC_PROTO_TCP,
- mmc_deleted_handler, &result, mmc_pool_failover_handler, NULL TSRMLS_CC);
- ZVAL_FALSE(&result);
-
- if (mmc_prepare_key_ex(key, strlen(key), request->key, &(request->key_len)) != MMC_OK) {
- mmc_pool_release(pool, request);
- return FAILURE;
- }
-
- pool->protocol->delete(request, request->key, request->key_len, 0);
-
- /* schedule request */
- if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(session_redundancy) TSRMLS_CC) != MMC_OK) {
- return FAILURE;
- }
-
- /* execute request */
- mmc_pool_run(pool TSRMLS_CC);
-
- if (Z_BVAL(result)) {
- 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-3.0.1.tgz/memcache-3.0.1/memcache_standard_hash.c
^
|
@@ -1,104 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: memcache_standard_hash.c,v 1.2.2.6 2007/11/03 09:19:05 mikl 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);
- }
-}
-/* }}} */
-
-mmc_t *mmc_standard_find_server(void *s, const char *key, unsigned int key_len TSRMLS_DC) /* {{{ */
-{
- mmc_standard_state_t *state = s;
-
- if (state->num_servers > 1) {
- /* "new-style" hash */
- unsigned int hash = (state->hash(key, key_len) >> 16) & 0x7fff;
- return state->buckets[(hash ? hash : 1) % state->num_buckets];
- }
-
- return state->buckets[0];
-}
-/* }}} */
-
-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 */
- state->buckets = erealloc(state->buckets, sizeof(*state->buckets) * (state->num_buckets + 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-3.0.1.tgz/memcache-3.0.1/php_memcache.h
^
|
@@ -1,97 +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 <tony2001@phpclub.net> |
- | Mikael Johansson <mikael AT synd DOT info> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: php_memcache.h,v 1.27.2.8 2008/02/05 19:59:42 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
-
-#include "memcache_pool.h"
-
-PHP_MINIT_FUNCTION(memcache);
-PHP_MSHUTDOWN_FUNCTION(memcache);
-PHP_MINFO_FUNCTION(memcache);
-
-PHP_NAMED_FUNCTION(zif_memcache_pool_connect);
-PHP_NAMED_FUNCTION(zif_memcache_pool_addserver);
-
-PHP_FUNCTION(memcache_connect);
-PHP_FUNCTION(memcache_pconnect);
-PHP_FUNCTION(memcache_add_server);
-PHP_FUNCTION(memcache_set_server_params);
-PHP_FUNCTION(memcache_set_failure_callback);
-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_cas);
-PHP_FUNCTION(memcache_append);
-PHP_FUNCTION(memcache_prepend);
-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);
-
-#define PHP_MEMCACHE_VERSION "3.0.1"
-
-#define MMC_DEFAULT_TIMEOUT 1 /* seconds */
-#define MMC_DEFAULT_RETRY 15 /* retry failed server after x seconds */
-#define MMC_DEFAULT_CACHEDUMP_LIMIT 100 /* number of entries */
-
-/* internal functions */
-mmc_t *mmc_find_persistent(const char *, int, unsigned short, unsigned short, int, int TSRMLS_DC);
-int mmc_value_handler_single(const char *, unsigned int, void *, unsigned int, unsigned int, unsigned long, void * TSRMLS_DC);
-int mmc_stored_handler(mmc_t *, mmc_request_t *, int, const char *, unsigned int, void * 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
-
-#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-3.0.2.tgz
^
|
|
Deleted |
memcache-3.0.3.tgz
^
|
[-]
[+]
|
Changed |
memcache-3.0.5.tgz/memcache-3.0.5/CREDITS
^
|
(renamed from memcache-3.0.1/CREDITS)
|
[-]
[+]
|
Changed |
memcache-3.0.5.tgz/memcache-3.0.5/CREDITS
^
|
(renamed from memcache-3.0.1/CREDITS)
|
[-]
[+]
|
Added |
memcache-3.0.5.tgz/memcache-3.0.5/README
^
|
@@ -0,0 +1,146 @@
+memcached module for PHP
+------------------------
+This module requires zlib library, used for on-the-fly data (de)compression.
+Also, you'll need memcached to use it =)
+
+The memcached website is here:
+ http://www.danga.com/memcached/
+
+You will probably need libevent to install memcached:
+You can download it here: http://www.monkey.org/~provos/libevent/
+
+
+New API in 3.0
+------------------------
+
+ Version 3 introduces a new class "MemcachePool" which implements the new API, the
+ old class "Memcache" is still retained (but is deprecated) with the same interface
+ for backwards compatibility. Please note that you need a new memcached version to
+ use the CAS, default value to increment/decrement, append and prepend, and binary
+ protocol features.
+
+ New INI directives are available to allow control over protocol, redundancy and hash
+ strategy selection. These are
+
+ # The binary protocol results in less traffic and is more efficient
+ # for the client and server to generate/parse
+
+ memcache.protocol = {ascii, binary} # default ascii
+
+ # When enabled the client sends requests to N servers in parallel, resulting in
+ # a somewhat crude reduncancy or mirroring, suitable when used as a session
+ # storage.
+ #
+ # If data integrity is of greater importance a real replicating memcached
+ # backend such as "repcached" (http://sourceforge.net/projects/repcached/) is
+ # recommended
+
+ memcache.redundancy = <int> # default 1
+ memcache.session_redundancy = <int> # default 2
+
+ # Hash strategy and function selection. The consistent hashing strategy
+ # is now the default as it allows servers to be added and removed from
+ # the pool without resulting in all or most keys being re-mapped to
+ # other server (ie. voiding the cache)
+
+ memcache.hash_strategy = {standard, consistent} # default consistent
+ memcache.hash_function = {crc32, fnv} # default crc32
+
+ # Compression is enabled by default, the threshold which control the minimum
+ # string length which triggers compresssion can be changed as
+
+ memcache.compress_threshold = <int> # default 20000
+
+
+ The directives are used by the MemcachePool constructor so you can instantiate
+ several pools with different settings by using ini_set() creativly. For example
+
+ ini_set('memcache.protocol', 'binary');
+
+ $binarypool = new MemcachePool();
+ $binarypool->addServer(...)
+
+ ini_set('memcache.protocol', 'ascii');
+ ini_set('memcache.redundancy', '2');
+
+ $redundantpool = new MemcachePool();
+ $redundantpool->addServer(...)
+
+ ini_set('memcache.redundancy', '1');
+
+
+ The new interface looks like
+
+class MemcachePool() {
+ bool connect(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15)
+ bool addServer(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15, bool status = true)
+ bool setServerParams(string host, int tcp_port = 11211, int timeout = 1, int retry_interval = 15, bool status = true)
+
+ /**
+ * Supports fetching flags and CAS values
+ */
+ mixed get(mixed key, mixed &flags = null, mixed &cas = null)
+
+ /**
+ * Supports multi-set, for example
+ * $memcache->set(array('key1' => 'val1', 'key2' => 'val1'), null, 0, 60)
+ */
+ bool add(mixed key, mixed var = null, int flag = 0, int exptime = 0)
+ bool set(mixed key, mixed var = null, int flag = 0, int exptime = 0)
+ bool replace(mixed key, mixed var = null, int flag = 0, int exptime = 0)
+
+ /**
+ * Compare-and-Swap, uses the CAS param from MemcachePool::get()
+ */
+ bool cas(mixed key, mixed var = null, int flag = 0, int exptime = 0, int cas = 0)
+
+ /**
+ * Prepends/appends a value to an existing one
+ */
+ bool append(mixed key, mixed var = null, int flag = 0, int exptime = 0)
+ bool prepend(mixed key, mixed var = null, int flag = 0, int exptime = 0)
+
+ /**
+ * Supports multi-key operations, for example
+ * $memcache->delete(array('key1', 'key2'))
+ */
+ bool delete(mixed key, int exptime = 0)
+
+ /**
+ * Supports multi-key operations, for example
+ * $memcache->increment(array('key1', 'key2'), 1, 0, 0)
+ *
+ * The new defval (default value) and exptime (expiration time) are used
+ * if the key doesn't already exist. They must be supplied (even if 0) for
+ * this to be enabled.
+ *
+ * Returns an integer with the new value if key is a string
+ * Returns an array of integers if the key is an array
+ */
+ mixed increment(mixed key, int value = 1, int defval = 0, int exptime = 0)
+ mixed decrement(mixed key, int value = 1, int defval = 0, int exptime = 0)
+
+ /**
+ * Assigns a pool-specific failure callback which will be called when
+ * a request fails. May be null in order to disable callbacks. The callback
+ * receive arguments like
+ *
+ * function mycallback($host, $tcp_port, $udp_port, $error, $errnum)
+ *
+ * Where $host and $error are strings or null, the other params are integers.
+ */
+ bool setFailureCallback(function callback)
+
+ /**
+ * Locates the server a given would be hashed to
+ *
+ * Returns a string "hostname:port" on success
+ * Returns false on failure such as invalid key
+ */
+ string findServer(string key)
+}
+
+
+Maintainers:
+Mikael Johansson mikael at synd dot info
+Antony Dovgal tony2001 at phpclub dot net
|
[-]
[+]
|
Added |
memcache-3.0.5.tgz/memcache-3.0.5/config.m4
^
|
@@ -0,0 +1,4 @@
+dnl $Id: config.m4 303968 2010-10-03 21:38:49Z hradtke $
+dnl this file is required by phpize
+
+sinclude(config9.m4)
|
[-]
[+]
|
Added |
memcache-3.0.5.tgz/memcache-3.0.5/config.w32
^
|
@@ -0,0 +1,14 @@
+// $Id: config.w32 303968 2010-10-03 21:38:49Z hradtke $
+// 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_pool.c memcache_queue.c memcache_ascii_protocol.c memcache_binary_protocol.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");
+ }
+}
|
[-]
[+]
|
Added |
memcache-3.0.5.tgz/memcache-3.0.5/config9.m4
^
|
@@ -0,0 +1,112 @@
+dnl
+dnl $Id: config9.m4 303968 2010-10-03 21:38:49Z hradtke $
+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_pool.c memcache_queue.c memcache_ascii_protocol.c memcache_binary_protocol.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_pool.c memcache_queue.c memcache_ascii_protocol.c memcache_binary_protocol.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-3.0.5.tgz/memcache-3.0.5/example.php
^
|
(renamed from memcache-3.0.1/example.php)
|
[-]
[+]
|
Changed |
memcache-3.0.5.tgz/memcache-3.0.5/example.php
^
|
(renamed from memcache-3.0.1/example.php)
|
[-]
[+]
|
Added |
memcache-3.0.5.tgz/memcache-3.0.5/memcache.c
^
|
@@ -0,0 +1,1986 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_string.h"
+#include "php_memcache.h"
+
+#ifndef ZEND_ENGINE_2
+#define OnUpdateLong OnUpdateInt
+#endif
+
+/* True global resources - no need for thread safety here */
+static int le_memcache_pool, le_memcache_server;
+static zend_class_entry *memcache_pool_ce;
+static zend_class_entry *memcache_ce;
+
+ZEND_EXTERN_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_set_failure_callback, 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_cas, NULL)
+ PHP_FE(memcache_append, NULL)
+ PHP_FE(memcache_prepend, 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)
+ {NULL, NULL, NULL}
+};
+
+static zend_function_entry php_memcache_pool_class_functions[] = {
+ PHP_NAMED_FE(connect, zif_memcache_pool_connect, NULL)
+ PHP_NAMED_FE(addserver, zif_memcache_pool_addserver, NULL)
+ PHP_FALIAS(setserverparams, memcache_set_server_params, NULL)
+ PHP_FALIAS(setfailurecallback, memcache_set_failure_callback, NULL)
+ PHP_FALIAS(getserverstatus, memcache_get_server_status, NULL)
+ PHP_NAMED_FE(findserver, zif_memcache_pool_findserver, 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(cas, memcache_cas, NULL)
+ PHP_FALIAS(append, memcache_append, NULL)
+ PHP_FALIAS(prepend, memcache_prepend, 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)
+ {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)
+ {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),
+ NULL,
+ 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(OnUpdateProtocol) /* {{{ */
+{
+ if (!strcasecmp(new_value, "ascii")) {
+ MEMCACHE_G(protocol) = MMC_ASCII_PROTOCOL;
+ }
+ else if (!strcasecmp(new_value, "binary")) {
+ MEMCACHE_G(protocol) = MMC_BINARY_PROTOCOL;
+ }
+ else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.protocol must be in set {ascii, binary} ('%s' given)", new_value);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+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(OnUpdateRedundancy) /* {{{ */
+{
+ long int lval;
+
+ lval = strtol(new_value, NULL, 10);
+ if (lval <= 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.redundancy 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(OnUpdateCompressThreshold) /* {{{ */
+{
+ long int lval;
+
+ lval = strtol(new_value, NULL, 10);
+ if (lval < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.compress_threshold 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(OnUpdateLockTimeout) /* {{{ */
+{
+ long int lval;
+
+ lval = strtol(new_value, NULL, 10);
+ if (lval <= 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache.lock_timeout 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);
+}
+/* }}} */
+
+/* {{{ 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", "32768", PHP_INI_ALL, OnUpdateChunkSize, chunk_size, zend_memcache_globals, memcache_globals)
+ STD_PHP_INI_ENTRY("memcache.protocol", "ascii", PHP_INI_ALL, OnUpdateProtocol, protocol, zend_memcache_globals, memcache_globals)
+ STD_PHP_INI_ENTRY("memcache.hash_strategy", "consistent", 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.redundancy", "1", PHP_INI_ALL, OnUpdateRedundancy, redundancy, zend_memcache_globals, memcache_globals)
+ STD_PHP_INI_ENTRY("memcache.session_redundancy", "2", PHP_INI_ALL, OnUpdateRedundancy, session_redundancy, zend_memcache_globals, memcache_globals)
+ STD_PHP_INI_ENTRY("memcache.compress_threshold", "20000", PHP_INI_ALL, OnUpdateCompressThreshold, compress_threshold, zend_memcache_globals, memcache_globals)
+ STD_PHP_INI_ENTRY("memcache.lock_timeout", "15", PHP_INI_ALL, OnUpdateLockTimeout, lock_timeout, 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_server_list_dtor(zend_rsrc_list_entry * TSRMLS_DC);
+static void php_mmc_set_failure_callback(mmc_pool_t *, zval *, zval * TSRMLS_DC);
+static void php_mmc_failure_callback(mmc_pool_t *, mmc_t *, void * TSRMLS_DC);
+/* }}} */
+
+/* {{{ php_memcache_init_globals()
+*/
+static void php_memcache_init_globals(zend_memcache_globals *memcache_globals_p TSRMLS_DC)
+{
+ MEMCACHE_G(hash_strategy) = MMC_STANDARD_HASH;
+ MEMCACHE_G(hash_function) = MMC_HASH_CRC32;
+}
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(memcache)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "MemcachePool", php_memcache_pool_class_functions);
+ memcache_pool_ce = zend_register_internal_class(&ce TSRMLS_CC);
+
+ INIT_CLASS_ENTRY(ce, "Memcache", php_memcache_class_functions);
+ memcache_ce = zend_register_internal_class_ex(&ce, memcache_pool_ce, NULL TSRMLS_CC);
+
+ le_memcache_pool = zend_register_list_destructors_ex(_mmc_pool_list_dtor, NULL, "memcache connection", module_number);
+ le_memcache_server = zend_register_list_destructors_ex(NULL, _mmc_server_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_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(memcache)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "memcache support", "enabled");
+ php_info_print_table_row(2, "Version", PHP_MEMCACHE_VERSION);
+ php_info_print_table_row(2, "Revision", "$Revision: 303968 $");
+ php_info_print_table_end();
+
+ DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+
+/* ------------------
+ internal functions
+ ------------------ */
+
+static void _mmc_pool_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+{
+ mmc_pool_t *pool = (mmc_pool_t *)rsrc->ptr;
+
+ if (pool->failure_callback_param) {
+ zval_ptr_dtor((zval **)&pool->failure_callback_param);
+ pool->failure_callback_param = NULL;
+ }
+
+ mmc_pool_free(pool TSRMLS_CC);
+}
+/* }}} */
+
+static void _mmc_server_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+{
+ mmc_server_free((mmc_t *)rsrc->ptr TSRMLS_CC);
+}
+/* }}} */
+
+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 MemcachePool->connection member variable");
+ return 0;
+ }
+
+ return Z_LVAL_PP(connection);
+}
+/* }}} */
+
+int mmc_stored_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
+ handles SET/ADD/REPLACE response, param is a zval pointer to store result into {{{ */
+{
+ zval *result = (zval *)param;
+
+ if (response == MMC_OK) {
+ if (Z_TYPE_P(result) == IS_NULL) {
+ ZVAL_TRUE(result);
+ }
+
+ return MMC_REQUEST_DONE;
+ }
+
+ /* return FALSE or catch memory errors without failover */
+ if (response == MMC_RESPONSE_EXISTS || response == MMC_RESPONSE_OUT_OF_MEMORY || response == MMC_RESPONSE_TOO_LARGE) {
+ ZVAL_FALSE(result);
+
+ if (response != MMC_RESPONSE_EXISTS) {
+ /* trigger notice but no need for failover */
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d, udp %d) failed with: %s (%d)",
+ mmc->host, mmc->tcp.port, mmc->udp.port, message, response);
+ }
+
+ return MMC_REQUEST_DONE;
+ }
+
+ return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
+}
+/* }}} */
+
+static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, int op) /* {{{ */
+{
+ mmc_pool_t *pool;
+ mmc_request_t *request;
+ zval *keys, *value = 0, *mmc_object = getThis();
+ long flags = 0, exptime = 0, cas = 0;
+
+ if (mmc_object == NULL) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zlll", &mmc_object, memcache_pool_ce, &keys, &value, &flags, &exptime, &cas) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|zlll", &keys, &value, &flags, &exptime, &cas) == FAILURE) {
+ return;
+ }
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
+ RETURN_FALSE;
+ }
+
+ RETVAL_NULL();
+
+ if (Z_TYPE_P(keys) == IS_ARRAY) {
+ zstr key;
+ char keytmp[MAX_LENGTH_OF_LONG + 1];
+ unsigned int key_len;
+ unsigned long index;
+ int key_type;
+
+ zval **arrval;
+ HashPosition pos;
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
+
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&arrval, &pos) == SUCCESS) {
+ key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(keys), &key, &key_len, &index, 0, &pos);
+ zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
+
+ switch (key_type) {
+ case HASH_KEY_IS_STRING:
+ key_len--;
+ break;
+
+ case HASH_KEY_IS_LONG:
+ key_len = sprintf(keytmp, "%lu", index);
+ key = ZSTR(keytmp);
+ break;
+
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ continue;
+ }
+
+ /* allocate request */
+ request = mmc_pool_request(pool, MMC_PROTO_TCP,
+ mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
+
+ if (mmc_prepare_key_ex(ZSTR_VAL(key), key_len, request->key, &(request->key_len)) != MMC_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ mmc_pool_release(pool, request);
+ continue;
+ }
+
+ /* assemble command */
+ if (pool->protocol->store(pool, request, op, request->key, request->key_len, flags, exptime, cas, *arrval TSRMLS_CC) != MMC_OK) {
+ mmc_pool_release(pool, request);
+ continue;
+ }
+
+ /* schedule request */
+ if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
+ continue;
+ }
+
+ /* begin sending requests immediatly */
+ mmc_pool_select(pool TSRMLS_CC);
+ }
+ }
+ else if (value) {
+ /* allocate request */
+ request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stored_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
+
+ if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ mmc_pool_release(pool, request);
+ RETURN_FALSE;
+ }
+
+ /* assemble command */
+ if (pool->protocol->store(pool, request, op, request->key, request->key_len, flags, exptime, cas, value TSRMLS_CC) != MMC_OK) {
+ mmc_pool_release(pool, request);
+ RETURN_FALSE;
+ }
+
+ /* schedule request */
+ if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
+ RETURN_FALSE;
+ }
+ }
+ else {
+ WRONG_PARAM_COUNT;
+ }
+
+ /* execute all requests */
+ mmc_pool_run(pool TSRMLS_CC);
+
+ if (Z_TYPE_P(return_value) == IS_NULL) {
+ RETVAL_FALSE;
+ }
+}
+/* }}} */
+
+int mmc_numeric_response_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
+ handles a mutate response line, param is a zval pointer to store result into {{{ */
+{
+ zval *result = (zval *)param;
+
+ if (response == MMC_OK) {
+ if (Z_TYPE_P(result) == IS_ARRAY) {
+ add_assoc_bool_ex(result, request->key, request->key_len + 1, 1);
+ }
+ else if (Z_TYPE_P(result) == IS_NULL) {
+ /* switch only from null to true, not from false to true */
+ ZVAL_TRUE(result);
+ }
+
+ return MMC_REQUEST_DONE;
+ }
+
+ if (response == MMC_RESPONSE_NOT_FOUND) {
+ if (Z_TYPE_P(result) == IS_ARRAY) {
+ add_assoc_bool_ex(result, request->key, request->key_len + 1, 0);
+ }
+ else {
+ ZVAL_FALSE(result);
+ }
+
+ return MMC_REQUEST_DONE;
+ }
+
+ return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
+}
+/* }}} */
+
+static void php_mmc_numeric(INTERNAL_FUNCTION_PARAMETERS, int deleted, int invert) /*
+ sends one or several commands which have a single optional numeric parameter (incr, decr, delete) {{{ */
+{
+ mmc_pool_t *pool;
+ zval *mmc_object = getThis();
+
+ zval *keys;
+ long value = 1, defval = 0, exptime = 0;
+ mmc_request_t *request;
+ void *value_handler_param[3];
+ int defval_used = 0;
+
+ if (mmc_object == NULL) {
+ if (deleted) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|l", &mmc_object, memcache_pool_ce, &keys, &value) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|lll", &mmc_object, memcache_pool_ce, &keys, &value, &defval, &exptime) == FAILURE) {
+ return;
+ }
+
+ defval_used = ZEND_NUM_ARGS() >= 4;
+ }
+ }
+ else {
+ if (deleted) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &keys, &value) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|lll", &keys, &value, &defval, &exptime) == FAILURE) {
+ return;
+ }
+
+ defval_used = ZEND_NUM_ARGS() >= 3;
+ }
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
+ RETURN_FALSE;
+ }
+
+ value_handler_param[0] = return_value;
+ value_handler_param[1] = NULL;
+ value_handler_param[2] = NULL;
+
+ if (Z_TYPE_P(keys) == IS_ARRAY) {
+ zval **key;
+ HashPosition pos;
+
+ if (deleted) {
+ /* changed to true/false by mmc_numeric_response_handler */
+ RETVAL_NULL();
+ }
+ else {
+ /* populated with responses by mmc_numeric_response_handler and mmc_value_handler_multi */
+ array_init(return_value);
+ }
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
+ zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
+
+ /* allocate request */
+ request = mmc_pool_request(
+ pool, MMC_PROTO_TCP, mmc_numeric_response_handler, return_value,
+ mmc_pool_failover_handler, NULL TSRMLS_CC);
+
+ request->value_handler = mmc_value_handler_multi;
+ request->value_handler_param = value_handler_param;
+
+ if (mmc_prepare_key(*key, request->key, &(request->key_len)) != MMC_OK) {
+ mmc_pool_release(pool, request);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ continue;
+ }
+
+ if (deleted) {
+ pool->protocol->delete(request, request->key, request->key_len, exptime);
+ }
+ else {
+ pool->protocol->mutate(request, *key, request->key, request->key_len, invert ? -value : value, defval, defval_used, exptime);
+ }
+
+ /* schedule request */
+ if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
+ continue;
+ }
+
+ /* begin sending requests immediatly */
+ mmc_pool_select(pool TSRMLS_CC);
+ }
+ }
+ else {
+ /* changed to true/false by mmc_numeric_response_handler or set to a value
+ * by mmc_value_handler_single if incr/decr returns one */
+ RETVAL_NULL();
+
+ /* allocate request */
+ request = mmc_pool_request(pool, MMC_PROTO_TCP,
+ mmc_numeric_response_handler, return_value, mmc_pool_failover_handler, NULL TSRMLS_CC);
+
+ request->value_handler = mmc_value_handler_single;
+ request->value_handler_param = value_handler_param;
+
+ if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
+ mmc_pool_release(pool, request);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ RETURN_FALSE;
+ }
+
+ if (deleted) {
+ pool->protocol->delete(request, request->key, request->key_len, exptime);
+ }
+ else {
+ pool->protocol->mutate(request, keys, request->key, request->key_len, invert ? -value : value, defval, defval_used, exptime);
+ }
+
+ /* schedule request */
+ if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, MEMCACHE_G(redundancy) TSRMLS_CC) != MMC_OK) {
+ RETURN_FALSE;
+ }
+ }
+
+ /* execute all requests */
+ mmc_pool_run(pool TSRMLS_CC);
+}
+/* }}} */
+
+mmc_t *mmc_find_persistent(const char *host, int host_len, unsigned short port, unsigned short udp_port, double timeout, int retry_interval TSRMLS_DC) /* {{{ */
+{
+ mmc_t *mmc;
+ zend_rsrc_list_entry *le;
+ char *key;
+ int key_len;
+
+ key_len = spprintf(&key, 0, "memcache:server:%s:%u:%u", host, port, udp_port);
+
+ if (zend_hash_find(&EG(persistent_list), key, key_len+1, (void **)&le) == FAILURE) {
+ zend_rsrc_list_entry new_le;
+
+ mmc = mmc_server_new(host, host_len, port, udp_port, 1, timeout, retry_interval TSRMLS_CC);
+ new_le.type = le_memcache_server;
+ new_le.ptr = mmc;
+
+ /* register new persistent connection */
+ if (zend_hash_update(&EG(persistent_list), key, 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_memcache_server);
+ }
+ }
+ else if (le->type != le_memcache_server || le->ptr == NULL) {
+ zend_rsrc_list_entry new_le;
+ zend_hash_del(&EG(persistent_list), key, key_len+1);
+
+ mmc = mmc_server_new(host, host_len, port, udp_port, 1, timeout, retry_interval TSRMLS_CC);
+ new_le.type = le_memcache_server;
+ new_le.ptr = mmc;
+
+ /* register new persistent connection */
+ if (zend_hash_update(&EG(persistent_list), key, 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_memcache_server);
+ }
+ }
+ else {
+ mmc = (mmc_t *)le->ptr;
+ mmc->timeout = double_to_timeval(timeout);
+ mmc->tcp.retry_interval = retry_interval;
+
+ /* attempt to reconnect this node before failover in case connection has gone away */
+ if (mmc->tcp.status == MMC_STATUS_CONNECTED) {
+ mmc->tcp.status = MMC_STATUS_UNKNOWN;
+ }
+ if (mmc->udp.status == MMC_STATUS_CONNECTED) {
+ mmc->udp.status = MMC_STATUS_UNKNOWN;
+ }
+ }
+
+ efree(key);
+ return mmc;
+}
+/* }}} */
+
+static mmc_t *php_mmc_pool_addserver(
+ zval *mmc_object, const char *host, int host_len, long tcp_port, long udp_port, long weight,
+ zend_bool persistent, double timeout, long retry_interval, zend_bool status, mmc_pool_t **pool_result TSRMLS_DC) /* {{{ */
+{
+ zval **connection;
+ mmc_pool_t *pool;
+ mmc_t *mmc;
+ int list_id, resource_type;
+
+ if (weight < 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "weight must be a positive integer");
+ return NULL;
+ }
+
+ /* 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);
+ pool->failure_callback = &php_mmc_failure_callback;
+ 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, "Unknown connection identifier");
+ return NULL;
+ }
+ }
+
+ /* binary protocol isn't support over UDP yet */
+ if (udp_port && pool->protocol == &mmc_binary_protocol) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "binary protocol isn't support over UDP, defaulting to TCP");
+ udp_port = 0;
+ }
+
+ /* lazy initialization of server struct */
+ if (persistent && status) {
+ mmc = mmc_find_persistent(host, host_len, tcp_port, udp_port, timeout, retry_interval TSRMLS_CC);
+ }
+ else {
+ mmc = mmc_server_new(host, host_len, tcp_port, udp_port, 0, timeout, retry_interval TSRMLS_CC);
+ }
+
+ /* add server in failed mode */
+ if (!status) {
+ mmc->tcp.status = MMC_STATUS_FAILED;
+ mmc->udp.status = MMC_STATUS_FAILED;
+ }
+
+ mmc_pool_add(pool, mmc, weight);
+
+ if (pool_result != NULL) {
+ *pool_result = pool;
+ }
+
+ return mmc;
+}
+/* }}} */
+
+static void php_mmc_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool persistent) /* {{{ */
+{
+ zval *mmc_object = getThis();
+ mmc_pool_t *pool;
+ mmc_t *mmc;
+
+ char *host;
+ int host_len;
+ long tcp_port = MEMCACHE_G(default_port);
+ double timeout = MMC_DEFAULT_TIMEOUT;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ld", &host, &host_len, &tcp_port, &timeout) == FAILURE) {
+ return;
+ }
+
+ /* initialize pool and object if need be */
+ if (!mmc_object) {
+ int list_id;
+ mmc_pool_t *pool = mmc_pool_new(TSRMLS_C);
+ pool->failure_callback = &php_mmc_failure_callback;
+ list_id = zend_list_insert(pool, le_memcache_pool);
+ mmc_object = return_value;
+ object_init_ex(mmc_object, memcache_ce);
+ add_property_resource(mmc_object, "connection", list_id);
+ }
+ else {
+ RETVAL_TRUE;
+ }
+
+ mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, 0, 1, persistent, timeout, MMC_DEFAULT_RETRY, 1, NULL TSRMLS_CC);
+ if (mmc == NULL) {
+ RETURN_FALSE;
+ }
+
+ /* force a reconnect attempt if stream EOF */
+ if (mmc->tcp.stream != NULL && php_stream_eof(mmc->tcp.stream)) {
+ mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ /* force a tcp connect (if not persistently connected) */
+ if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) != MMC_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%d, %s (%d)", host, mmc->tcp.port, mmc->error ? mmc->error : "Unknown error", mmc->errnum);
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/*
+ * 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;
+
+ if (Z_TYPE_P(result) != IS_ARRAY) {
+ array_init(result);
+ }
+
+ /* 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;
+
+ if (Z_TYPE_P(result) != IS_ARRAY) {
+ array_init(result);
+ }
+
+ /* 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;
+
+ if (Z_TYPE_P(result) != IS_ARRAY) {
+ array_init(result);
+ }
+
+ 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);
+ }
+ }
+ else {
+ return 0;
+ }
+
+ return 1;
+}
+/* }}} */
+
+static void php_mmc_failure_callback(mmc_pool_t *pool, mmc_t *mmc, void *param TSRMLS_DC) /* {{{ */
+{
+ zval **callback;
+
+ /* check for userspace callback */
+ if (param != NULL && zend_hash_find(Z_OBJPROP_P((zval *)param), "_failureCallback", sizeof("_failureCallback"), (void **)&callback) == SUCCESS && Z_TYPE_PP(callback) != IS_NULL) {
+ if (IS_CALLABLE(*callback, 0, 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->tcp.port); ZVAL_LONG(udp_port, mmc->udp.port);
+
+ 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, *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_mmc_set_failure_callback(pool, (zval *)param, NULL TSRMLS_CC);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback");
+ }
+ }
+ else {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp %d, udp %d) failed with: %s (%d)",
+ mmc->host, mmc->tcp.port, mmc->udp.port, mmc->error, mmc->errnum);
+ }
+}
+/* }}} */
+
+static void php_mmc_set_failure_callback(mmc_pool_t *pool, zval *mmc_object, zval *callback TSRMLS_DC) /* {{{ */
+{
+ // Decrease refcount of old mmc_object
+ if (pool->failure_callback_param) {
+ zval_ptr_dtor((zval **)&pool->failure_callback_param);
+ }
+
+ if (callback != NULL) {
+ zval *callback_tmp;
+ ALLOC_ZVAL(callback_tmp);
+
+ *callback_tmp = *callback;
+ zval_copy_ctor(callback_tmp);
+ INIT_PZVAL(callback_tmp);
+
+ add_property_zval(mmc_object, "_failureCallback", callback_tmp);
+ pool->failure_callback_param = mmc_object;
+ zval_add_ref(&mmc_object);
+
+ INIT_PZVAL(callback_tmp);
+ }
+ else {
+ add_property_null(mmc_object, "_failureCallback");
+ pool->failure_callback_param = NULL;
+ }
+}
+/* }}} */
+
+/* ----------------
+ module functions
+ ---------------- */
+
+/* {{{ proto bool MemcachePool::connect(string host [, int tcp_port [, int udp_port [, bool persistent [, int weight [, double timeout [, int retry_interval] ] ] ] ] ])
+ Connects to server and returns a Memcache object */
+PHP_NAMED_FUNCTION(zif_memcache_pool_connect)
+{
+ zval *mmc_object = getThis();
+ mmc_pool_t *pool;
+ mmc_t *mmc;
+
+ char *host;
+ int host_len;
+ long tcp_port = MEMCACHE_G(default_port), udp_port = 0, weight = 1, retry_interval = MMC_DEFAULT_RETRY;
+ double timeout = MMC_DEFAULT_TIMEOUT;
+ zend_bool persistent = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|llbldl",
+ &host, &host_len, &tcp_port, &udp_port, &persistent, &weight, &timeout, &retry_interval) == FAILURE) {
+ return;
+ }
+
+ mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, udp_port, weight, persistent, timeout, retry_interval, 1, NULL TSRMLS_CC);
+ if (mmc == NULL) {
+ RETURN_FALSE;
+ }
+
+ /* force a reconnect attempt if stream EOF */
+ if (mmc->tcp.stream != NULL && php_stream_eof(mmc->tcp.stream)) {
+ mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ /* force a tcp connect (if not persistently connected) */
+ if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) != MMC_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't connect to %s:%d, %s (%d)", host, mmc->tcp.port, mmc->error ? mmc->error : "Unknown error", mmc->errnum);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto object memcache_connect(string host [, int port [, double 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 [, double timeout ] ])
+ Connects to server and returns a Memcache object */
+PHP_FUNCTION(memcache_pconnect)
+{
+ php_mmc_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+}
+/* }}} */
+
+/* {{{ proto bool MemcachePool::addServer(string host [, int tcp_port [, int udp_port [, bool persistent [, int weight [, double timeout [, int retry_interval [, bool status] ] ] ] ])
+ Adds a server to the pool */
+PHP_NAMED_FUNCTION(zif_memcache_pool_addserver)
+{
+ zval *mmc_object = getThis();
+ mmc_t *mmc;
+
+ char *host;
+ int host_len;
+ long tcp_port = MEMCACHE_G(default_port), udp_port = 0, weight = 1, retry_interval = MMC_DEFAULT_RETRY;
+ double timeout = MMC_DEFAULT_TIMEOUT;
+ zend_bool persistent = 1, status = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|llbldlb",
+ &host, &host_len, &tcp_port, &udp_port, &persistent, &weight, &timeout, &retry_interval, &status) == FAILURE) {
+ return;
+ }
+
+ mmc = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, udp_port, weight, persistent, timeout, retry_interval, status, NULL TSRMLS_CC);
+ if (mmc == NULL) {
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string MemcachePool::findServer(string key)
+ Returns the server corresponding to a key
+*/
+PHP_NAMED_FUNCTION(zif_memcache_pool_findserver)
+{
+ zval *mmc_object = getThis();
+ mmc_pool_t *pool;
+ mmc_t *mmc;
+
+ zval *zkey;
+ char key[MMC_MAX_KEY_LEN + 1];
+ unsigned int key_len;
+ char *hostname;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zkey) == FAILURE) {
+ return;
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
+ RETURN_FALSE;
+ }
+
+ if (mmc_prepare_key(zkey, key, &key_len) != MMC_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ RETURN_FALSE;
+ }
+
+ mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC);
+ spprintf(&hostname, 0, "%s:%d", mmc->host, mmc->tcp.port);
+ RETURN_STRING(hostname, 0);
+}
+/* }}} */
+
+/* {{{ proto bool memcache_add_server(string host [, int port [, bool persistent [, int weight [, double 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 *mmc_object = getThis(), *failure_callback = NULL;
+ mmc_pool_t *pool;
+ mmc_t *mmc;
+
+ char *host;
+ int host_len;
+ long tcp_port = MEMCACHE_G(default_port), weight = 1, retry_interval = MMC_DEFAULT_RETRY;
+ double timeout = MMC_DEFAULT_TIMEOUT;
+ zend_bool persistent = 1, status = 1;
+
+ if (mmc_object) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbldlbz",
+ &host, &host_len, &tcp_port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lbldlbz", &mmc_object, memcache_ce,
+ &host, &host_len, &tcp_port, &persistent, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
+ return;
+ }
+ }
+
+ 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 = php_mmc_pool_addserver(mmc_object, host, host_len, tcp_port, 0, weight, persistent, timeout, retry_interval, status, &pool TSRMLS_CC);
+ if (mmc == NULL) {
+ RETURN_FALSE;
+ }
+
+ if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) {
+ php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool memcache_set_server_params( string host [, int port [, double 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 tcp_port = MEMCACHE_G(default_port), retry_interval = MMC_DEFAULT_RETRY;
+ double timeout = MMC_DEFAULT_TIMEOUT;
+ zend_bool status = 1;
+ int host_len, i;
+ char *host;
+
+ if (mmc_object) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ldlbz",
+ &host, &host_len, &tcp_port, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|ldlbz", &mmc_object, memcache_pool_ce,
+ &host, &host_len, &tcp_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]->tcp.port == tcp_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 = double_to_timeval(timeout);
+ mmc->tcp.retry_interval = retry_interval;
+
+ /* store the smallest timeout for any server */
+ if (timeval_to_double(mmc->timeout) < timeval_to_double(pool->timeout)) {
+ pool->timeout = mmc->timeout;
+ }
+
+ if (!status) {
+ mmc->tcp.status = MMC_STATUS_FAILED;
+ mmc->udp.status = MMC_STATUS_FAILED;
+ }
+ else {
+ if (mmc->tcp.status == MMC_STATUS_FAILED) {
+ mmc->tcp.status = MMC_STATUS_DISCONNECTED;
+ }
+ if (mmc->udp.status == MMC_STATUS_FAILED) {
+ mmc->udp.status = MMC_STATUS_DISCONNECTED;
+ }
+ }
+
+ if (failure_callback != NULL) {
+ if (Z_TYPE_P(failure_callback) != IS_NULL) {
+ php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
+ }
+ else {
+ php_mmc_set_failure_callback(pool, mmc_object, NULL TSRMLS_CC);
+ }
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool memcache_set_failure_callback( callback failure_callback )
+ Changes the failover callback */
+PHP_FUNCTION(memcache_set_failure_callback)
+{
+ zval *mmc_object = getThis(), *failure_callback;
+ mmc_pool_t *pool;
+
+ if (mmc_object) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",
+ &failure_callback) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz", &mmc_object, memcache_pool_ce,
+ &failure_callback) == FAILURE) {
+ return;
+ }
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ if (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;
+ }
+ }
+
+ if (Z_TYPE_P(failure_callback) != IS_NULL) {
+ php_mmc_set_failure_callback(pool, mmc_object, failure_callback TSRMLS_CC);
+ }
+ else {
+ php_mmc_set_failure_callback(pool, mmc_object, NULL TSRMLS_CC);
+ }
+
+ 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 tcp_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, &tcp_port) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_pool_ce, &host, &host_len, &tcp_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]->tcp.port == tcp_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->tcp.status > MMC_STATUS_FAILED ? 1 : 0);
+}
+/* }}} */
+
+static int mmc_version_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
+ parses the VERSION response line, param is a zval pointer to store version into {{{ */
+{
+ if (response != MMC_RESPONSE_ERROR) {
+ char *version = emalloc(message_len + 1);
+
+ if (sscanf(message, "VERSION %s", version) == 1) {
+ ZVAL_STRING((zval *)param, version, 0);
+ }
+ else {
+ efree(version);
+ ZVAL_STRINGL((zval *)param, (char *)message, message_len, 1);
+ }
+
+ return MMC_REQUEST_DONE;
+ }
+
+ return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto string memcache_get_version( object memcache )
+ Returns server's version */
+PHP_FUNCTION(memcache_get_version)
+{
+ mmc_pool_t *pool;
+ zval *mmc_object = getThis();
+ int i;
+ mmc_request_t *request;
+
+ if (mmc_object == NULL) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &mmc_object, memcache_pool_ce) == FAILURE) {
+ return;
+ }
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
+ RETURN_FALSE;
+ }
+
+ RETVAL_FALSE;
+ for (i=0; i<pool->num_servers; i++) {
+ /* run command and check for valid return value */
+ request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_version_handler, return_value, NULL, NULL TSRMLS_CC);
+ pool->protocol->version(request);
+
+ if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
+ mmc_pool_run(pool TSRMLS_CC);
+
+ if (Z_TYPE_P(return_value) == IS_STRING) {
+ break;
+ }
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto bool memcache_add(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
+ Adds new item. Item with such key should not exist. */
+PHP_FUNCTION(memcache_add)
+{
+ php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_ADD);
+}
+/* }}} */
+
+/* {{{ proto bool memcache_set(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
+ Sets the value of an item. Item may exist or not */
+PHP_FUNCTION(memcache_set)
+{
+ php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_SET);
+}
+/* }}} */
+
+/* {{{ proto bool memcache_replace(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] )
+ Replaces existing item. Returns false if item doesn't exist */
+PHP_FUNCTION(memcache_replace)
+{
+ php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_REPLACE);
+}
+/* }}} */
+
+/* {{{ proto bool memcache_cas(object memcache, mixed key [, mixed var [, int flag [, int exptime [, long cas ] ] ] ])
+ Sets the value of an item if the CAS value is the same (Compare-And-Swap) */
+PHP_FUNCTION(memcache_cas)
+{
+ php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_CAS);
+}
+/* }}} */
+
+/* {{{ proto bool memcache_prepend(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
+ Appends a value to the stored value, value must exist */
+PHP_FUNCTION(memcache_append)
+{
+ php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_APPEND);
+}
+/* }}} */
+
+/* {{{ proto bool memcache_prepend(object memcache, mixed key [, mixed var [, int flag [, int exptime ] ] ])
+ Prepends a value to the stored value, value must exist */
+PHP_FUNCTION(memcache_prepend)
+{
+ php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, MMC_OP_PREPEND);
+}
+/* }}} */
+
+int mmc_value_handler_multi(
+ const char *key, unsigned int key_len, zval *value,
+ unsigned int flags, unsigned long cas, void *param TSRMLS_DC) /*
+ receives a multiple values, param is a zval** array to store value and flags in {{{ */
+{
+ zval *arrval, **result = (zval **)param;
+ ALLOC_ZVAL(arrval);
+ *((zval *)arrval) = *value;
+
+ /* add value to result */
+ if (Z_TYPE_P(result[0]) != IS_ARRAY) {
+ array_init(result[0]);
+ }
+ add_assoc_zval_ex(result[0], (char *)key, key_len + 1, arrval);
+
+ /* add flags to result */
+ if (result[1] != NULL) {
+ if (Z_TYPE_P(result[1]) != IS_ARRAY) {
+ array_init(result[1]);
+ }
+ add_assoc_long_ex(result[1], (char *)key, key_len + 1, flags);
+ }
+
+ /* add CAS value to result */
+ if (result[2] != NULL) {
+ if (Z_TYPE_P(result[2]) != IS_ARRAY) {
+ array_init(result[2]);
+ }
+ add_assoc_long_ex(result[2], (char *)key, key_len + 1, cas);
+ }
+
+ return MMC_REQUEST_DONE;
+}
+/* }}} */
+
+int mmc_value_handler_single(
+ const char *key, unsigned int key_len, zval *value,
+ unsigned int flags, unsigned long cas, void *param TSRMLS_DC) /*
+ receives a single value, param is a zval pointer to store value to {{{ */
+{
+ zval **result = (zval **)param;
+ *(result[0]) = *value;
+
+ if (result[1] != NULL) {
+ ZVAL_LONG(result[1], flags);
+ }
+
+ if (result[2] != NULL) {
+ ZVAL_LONG(result[2], cas);
+ }
+
+ return MMC_REQUEST_DONE;
+}
+/* }}} */
+
+static int mmc_value_failover_handler(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC) /*
+ uses keys and return value to reschedule requests to other servers, param is a zval ** pointer {{{ */
+{
+ zval **key, *keys = ((zval **)param)[0], **value_handler_param = (zval **)((void **)param)[1];
+ HashPosition pos;
+
+ if (!MEMCACHE_G(allow_failover) || request->failed_servers.len >= MEMCACHE_G(max_failover_attempts)) {
+ mmc_pool_release(pool, request);
+ return MMC_REQUEST_FAILURE;
+ }
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
+
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
+ zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
+
+ /* re-schedule key if it does not exist in return value array */
+ if (Z_TYPE_P(value_handler_param[0]) != IS_ARRAY ||
+ !zend_hash_exists(Z_ARRVAL_P(value_handler_param[0]), Z_STRVAL_PP(key), Z_STRLEN_PP(key) + 1))
+ {
+ mmc_pool_schedule_get(pool, MMC_PROTO_UDP,
+ value_handler_param[2] != NULL ? MMC_OP_GETS : MMC_OP_GET, *key,
+ request->value_handler, request->value_handler_param,
+ request->failover_handler, request->failover_handler_param, request TSRMLS_CC);
+ }
+ }
+
+ mmc_pool_release(pool, request);
+ return MMC_OK;
+}
+/* }}}*/
+
+/* {{{ proto mixed memcache_get( object memcache, mixed key [, mixed &flags [, mixed &cas ] ] )
+ Returns value of existing item or false */
+PHP_FUNCTION(memcache_get)
+{
+ mmc_pool_t *pool;
+ zval *keys, *flags = NULL, *cas = NULL, *mmc_object = getThis();
+ void *value_handler_param[3], *failover_handler_param[2];
+
+ if (mmc_object == NULL) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zz", &mmc_object, memcache_pool_ce, &keys, &flags, &cas) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|zz", &keys, &flags, &cas) == FAILURE) {
+ return;
+ }
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
+ RETURN_FALSE;
+ }
+
+ value_handler_param[0] = return_value;
+ value_handler_param[1] = flags;
+ value_handler_param[2] = cas;
+
+ if (Z_TYPE_P(keys) == IS_ARRAY) {
+ zval **key;
+ HashPosition pos;
+
+ /* return empty array if no keys found */
+ array_init(return_value);
+
+ failover_handler_param[0] = keys;
+ failover_handler_param[1] = value_handler_param;
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&key, &pos) == SUCCESS) {
+ zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
+
+ /* schedule request */
+ mmc_pool_schedule_get(pool, MMC_PROTO_UDP,
+ cas != NULL ? MMC_OP_GETS : MMC_OP_GET, *key,
+ mmc_value_handler_multi, value_handler_param,
+ mmc_value_failover_handler, failover_handler_param, NULL TSRMLS_CC);
+ }
+ }
+ else {
+ mmc_request_t *request;
+
+ /* return false if key isn't found */
+ ZVAL_FALSE(return_value);
+
+ /* allocate request */
+ request = mmc_pool_request_get(
+ pool, MMC_PROTO_UDP,
+ mmc_value_handler_single, value_handler_param,
+ mmc_pool_failover_handler, NULL TSRMLS_CC);
+
+ if (mmc_prepare_key(keys, request->key, &(request->key_len)) != MMC_OK) {
+ mmc_pool_release(pool, request);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ return;
+ }
+
+ pool->protocol->get(request, cas != NULL ? MMC_OP_GETS : MMC_OP_GET, keys, request->key, request->key_len);
+
+ /* schedule request */
+ if (mmc_pool_schedule_key(pool, request->key, request->key_len, request, 1 TSRMLS_CC) != MMC_OK) {
+ return;
+ }
+ }
+
+ /* execute all requests */
+ mmc_pool_run(pool TSRMLS_CC);
+}
+/* }}} */
+
+static int mmc_stats_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
+ parses the stats response line, param is a zval pointer to store stats into {{{ */
+{
+ if (response != MMC_RESPONSE_ERROR)
+ {
+ char *line = (char *)message;
+
+ if(!message_len) {
+ return MMC_REQUEST_DONE;
+ }
+
+ if (mmc_str_left(line, "RESET", message_len, sizeof("RESET")-1)) {
+ ZVAL_TRUE((zval *)param);
+ return MMC_REQUEST_DONE;
+ }
+ else if (mmc_str_left(line, "STAT ", message_len, sizeof("STAT ")-1)) {
+ if (mmc_stats_parse_stat(line + sizeof("STAT ")-1, line + message_len - 1, (zval *)param TSRMLS_CC)) {
+ return MMC_REQUEST_AGAIN;
+ }
+ }
+ else if (mmc_str_left(line, "ITEM ", message_len, sizeof("ITEM ")-1)) {
+ if (mmc_stats_parse_item(line + sizeof("ITEM ")-1, line + message_len - 1, (zval *)param TSRMLS_CC)) {
+ return MMC_REQUEST_AGAIN;
+ }
+ }
+ else if (mmc_str_left(line, "END", message_len, sizeof("END")-1)) {
+ return MMC_REQUEST_DONE;
+ }
+ else if (mmc_stats_parse_generic(line, line + message_len, (zval *)param TSRMLS_CC)) {
+ return MMC_REQUEST_AGAIN;
+ }
+
+ zval_dtor((zval *)param);
+ ZVAL_FALSE((zval *)param);
+ return MMC_REQUEST_FAILURE;
+ }
+
+ return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
+}
+/* }}} */
+
+static int mmc_stats_checktype(const char *type) { /* {{{ */
+ return type == NULL ||
+ !strcmp(type, "reset") ||
+ !strcmp(type, "malloc") ||
+ !strcmp(type, "slabs") ||
+ !strcmp(type, "cachedump") ||
+ !strcmp(type, "items") ||
+ !strcmp(type, "sizes");
+}
+/* }}} */
+
+/* {{{ 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;
+ zval *mmc_object = getThis();
+
+ char *type = NULL;
+ int i, type_len = 0;
+ long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT;
+ mmc_request_t *request;
+
+ if (mmc_object == NULL) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_pool_ce, &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) || !pool->num_servers) {
+ RETURN_FALSE;
+ }
+
+ if (!mmc_stats_checktype(type)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stats type");
+ RETURN_FALSE;
+ }
+
+ ZVAL_FALSE(return_value);
+
+ for (i=0; i<pool->num_servers; i++) {
+ request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stats_handler, return_value, NULL, NULL TSRMLS_CC);
+ pool->protocol->stats(request, type, slabid, limit);
+
+ /* run command and check for valid return value */
+ if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
+ mmc_pool_run(pool TSRMLS_CC);
+
+ if (Z_TYPE_P(return_value) != IS_BOOL || Z_BVAL_P(return_value)) {
+ break;
+ }
+ }
+ }
+
+ /* execute all requests */
+ mmc_pool_run(pool TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ 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;
+ zval *mmc_object = getThis(), *stats;
+
+ char *host, *type = NULL;
+ int i, host_len, type_len = 0;
+ long slabid = 0, limit = MMC_DEFAULT_CACHEDUMP_LIMIT;
+ mmc_request_t *request;
+
+ if (mmc_object == NULL) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|sll", &mmc_object, memcache_pool_ce, &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) || !pool->num_servers) {
+ RETURN_FALSE;
+ }
+
+ if (!mmc_stats_checktype(type)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stats type");
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+
+ for (i=0; i<pool->num_servers; i++) {
+ MAKE_STD_ZVAL(stats);
+ ZVAL_FALSE(stats);
+
+ host_len = spprintf(&host, 0, "%s:%u", pool->servers[i]->host, pool->servers[i]->tcp.port);
+ add_assoc_zval_ex(return_value, host, host_len + 1, stats);
+ efree(host);
+
+ request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_stats_handler, stats, NULL, NULL TSRMLS_CC);
+ pool->protocol->stats(request, type, slabid, limit);
+
+ mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC);
+ }
+
+ /* execute all requests */
+ mmc_pool_run(pool TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ 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_pool_ce, &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 bool memcache_delete(object memcache, mixed key [, int exptime ])
+ Deletes existing item */
+PHP_FUNCTION(memcache_delete)
+{
+ php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto mixed memcache_increment(object memcache, mixed key [, int value [, int defval [, int exptime ] ] ])
+ Increments existing variable */
+PHP_FUNCTION(memcache_increment)
+{
+ php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
+}
+/* }}} */
+
+/* {{{ proto mixed memcache_decrement(object memcache, mixed key [, int value [, int defval [, int exptime ] ] ])
+ Decrements existing variable */
+PHP_FUNCTION(memcache_decrement)
+{
+ php_mmc_numeric(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
+}
+/* }}} */
+
+/* {{{ 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_pool_ce) == FAILURE) {
+ return;
+ }
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ mmc_pool_close(pool TSRMLS_CC);
+ RETURN_TRUE;
+}
+/* }}} */
+
+static int mmc_flush_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
+ parses the OK response line, param is an int pointer to increment on success {{{ */
+{
+ if (response == MMC_OK) {
+ (*((int *)param))++;
+ return MMC_REQUEST_DONE;
+ }
+
+ return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto bool memcache_flush( object memcache [, int delay ] )
+ Flushes cache, optionally at after the specified delay */
+PHP_FUNCTION(memcache_flush)
+{
+ mmc_pool_t *pool;
+ zval *mmc_object = getThis();
+
+ mmc_request_t *request;
+ unsigned int i, responses = 0;
+ long delay = 0;
+
+ if (mmc_object == NULL) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &mmc_object, memcache_pool_ce, &delay) == FAILURE) {
+ return;
+ }
+ }
+ else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &delay) == FAILURE) {
+ return;
+ }
+ }
+
+ if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ for (i=0; i<pool->num_servers; i++) {
+ request = mmc_pool_request(pool, MMC_PROTO_TCP, mmc_flush_handler, &responses, NULL, NULL TSRMLS_CC);
+ pool->protocol->flush(request, delay);
+
+ if (mmc_pool_schedule(pool, pool->servers[i], request TSRMLS_CC) == MMC_OK) {
+ /* begin sending requests immediatly */
+ mmc_pool_select(pool TSRMLS_CC);
+ }
+ }
+
+ /* execute all requests */
+ mmc_pool_run(pool TSRMLS_CC);
+
+ if (responses < pool->num_servers) {
+ RETURN_FALSE;
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool memcache_debug( bool onoff ) */
+PHP_FUNCTION(memcache_debug)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "memcache_debug() is deprecated, please use a debugger (like Eclipse + CDT)");
+}
+/* }}} */
+
+/*
+ * 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-3.0.5.tgz/memcache-3.0.5/memcache.dsp
^
|
(renamed from memcache-3.0.1/memcache.dsp)
|
[-]
[+]
|
Changed |
memcache-3.0.5.tgz/memcache-3.0.5/memcache.dsp
^
|
(renamed from memcache-3.0.1/memcache.dsp)
|
[-]
[+]
|
Added |
memcache-3.0.5.tgz/memcache-3.0.5/memcache.php
^
|
@@ -0,0 +1,881 @@
+<?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 303968 2010-10-03 21:38:49Z 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 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
|
[-]
[+]
|
Added |
memcache-3.0.5.tgz/memcache-3.0.5/memcache_ascii_protocol.c
^
|
@@ -0,0 +1,420 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_ascii_protocol.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "memcache_pool.h"
+#include "ext/standard/php_smart_str.h"
+
+typedef struct mmc_ascii_request {
+ mmc_request_t base; /* enable cast to mmc_request_t */
+ struct { /* stores value info while the body is being read */
+ char key[MMC_MAX_KEY_LEN + 1];
+ unsigned int flags;
+ unsigned long length;
+ unsigned long cas; /* CAS counter */
+ } value;
+} mmc_ascii_request_t;
+
+static int mmc_server_read_value(mmc_t *, mmc_request_t * TSRMLS_DC);
+
+static int mmc_stream_get_line(mmc_stream_t *io, char **line TSRMLS_DC) /*
+ attempts to read a line from server, returns the line size or 0 if no complete line was available {{{ */
+{
+ size_t returned_len = 0;
+ io->readline(io, io->input.value + io->input.idx, MMC_BUFFER_SIZE - io->input.idx, &returned_len TSRMLS_CC);
+ io->input.idx += returned_len;
+
+ if (io->input.idx && io->input.value[io->input.idx - 1] == '\n') {
+ int result = io->input.idx;
+ *line = io->input.value;
+ io->input.idx = 0;
+ return result;
+ }
+
+ return 0;
+}
+/* }}} */
+
+static int mmc_request_check_response(const char *line, int line_len) /*
+ checks for response status and error codes {{{ */
+{
+ int response;
+
+ if (mmc_str_left(line, "OK", line_len, sizeof("OK")-1) ||
+ mmc_str_left(line, "STORED", line_len, sizeof("STORED")-1) ||
+ mmc_str_left(line, "DELETED", line_len, sizeof("DELETED")-1))
+ {
+ response = MMC_OK;
+ }
+ else if (mmc_str_left(line, "NOT_FOUND", line_len, sizeof("NOT_FOUND")-1)) {
+ response = MMC_RESPONSE_NOT_FOUND;
+ }
+ else if (
+ mmc_str_left(line, "NOT_STORED", line_len, sizeof("NOT_STORED")-1) ||
+ mmc_str_left(line, "EXISTS", line_len, sizeof("EXISTS")-1))
+ {
+ response = MMC_RESPONSE_EXISTS;
+ }
+ else if (mmc_str_left(line, "SERVER_ERROR out of memory", line_len, sizeof("SERVER_ERROR out of memory")-1)) {
+ response = MMC_RESPONSE_OUT_OF_MEMORY;
+ }
+ else if (mmc_str_left(line, "SERVER_ERROR object too large", line_len, sizeof("SERVER_ERROR object too large")-1)) {
+ response = MMC_RESPONSE_TOO_LARGE;
+ }
+ else if (
+ mmc_str_left(line, "ERROR", line_len, sizeof("ERROR")-1) ||
+ mmc_str_left(line, "SERVER_ERROR", line_len, sizeof("SERVER_ERROR")-1) ||
+ mmc_str_left(line, "CLIENT_ERROR", line_len, sizeof("CLIENT_ERROR")-1))
+ {
+ response = MMC_RESPONSE_ERROR;
+ }
+ else {
+ response = MMC_RESPONSE_UNKNOWN;
+ }
+
+ return response;
+}
+
+static int mmc_request_parse_response(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ reads a generic response header and delegates it to response_handler {{{ */
+{
+ char *line;
+ int line_len = mmc_stream_get_line(request->io, &line TSRMLS_CC);
+
+ if (line_len > 0) {
+ int response = mmc_request_check_response(line, line_len);
+ return request->response_handler(mmc, request, response, line, line_len - (sizeof("\r\n")-1), request->response_handler_param TSRMLS_CC);
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static int mmc_request_parse_mutate(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ reads and parses the <long-value> response header {{{ */
+{
+ char *line;
+ int line_len;
+
+ line_len = mmc_stream_get_line(request->io, &line TSRMLS_CC);
+ if (line_len > 0) {
+ long lval;
+ zval value;
+
+ int response = mmc_request_check_response(line, line_len);
+ if (response != MMC_RESPONSE_UNKNOWN) {
+ return request->response_handler(mmc, request, response, line, line_len - (sizeof("\r\n")-1), request->response_handler_param TSRMLS_CC);
+ }
+
+ if (sscanf(line, "%lu", &lval) < 1) {
+ return mmc_server_failure(mmc, request->io, "Malformed VALUE header", 0 TSRMLS_CC);
+ }
+
+ INIT_PZVAL(&value);
+ ZVAL_LONG(&value, lval);
+ return request->value_handler(request->key, request->key_len, &value, 0, 0, request->value_handler_param TSRMLS_CC);
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static int mmc_request_parse_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ reads and parses the VALUE <key> <flags> <size> <cas> response header and then reads the value body {{{ */
+{
+ char *line;
+ int line_len;
+ mmc_ascii_request_t *req = (mmc_ascii_request_t *)request;
+
+ line_len = mmc_stream_get_line(request->io, &line TSRMLS_CC);
+ if (line_len > 0) {
+ if (mmc_str_left(line, "END", line_len, sizeof("END")-1)) {
+ return MMC_REQUEST_DONE;
+ }
+
+ if (sscanf(line, MMC_VALUE_HEADER, req->value.key, &(req->value.flags), &(req->value.length), &(req->value.cas)) < 3) {
+ return mmc_server_failure(mmc, request->io, "Malformed VALUE header", 0 TSRMLS_CC);
+ }
+
+ /* memory for data + \r\n */
+ mmc_buffer_alloc(&(request->readbuf), req->value.length + 2);
+
+ /* allow read_value handler to read the value body */
+ request->parse = mmc_server_read_value;
+
+ /* read more, php streams buffer input which must be read if available */
+ return MMC_REQUEST_AGAIN;
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static int mmc_server_read_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ read the value body into the buffer {{{ */
+{
+ mmc_ascii_request_t *req = (mmc_ascii_request_t *)request;
+ request->readbuf.idx +=
+ request->io->read(request->io, request->readbuf.value.c + request->readbuf.idx, req->value.length + 2 - request->readbuf.idx TSRMLS_CC);
+
+ /* done reading? */
+ if (request->readbuf.idx >= req->value.length + 2) {
+ /* allow parse_value to read next VALUE or END line */
+ request->parse = mmc_request_parse_value;
+ mmc_buffer_reset(&(request->readbuf));
+
+ int result = mmc_unpack_value(
+ mmc, request, &(request->readbuf), req->value.key, strlen(req->value.key),
+ req->value.flags, req->value.cas, req->value.length TSRMLS_CC);
+
+ /* request more data (END line) */
+ if (result == MMC_REQUEST_DONE) {
+ return MMC_REQUEST_AGAIN;
+ }
+
+ return result;
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static mmc_request_t *mmc_ascii_create_request() /* {{{ */
+{
+ mmc_ascii_request_t *request = emalloc(sizeof(mmc_ascii_request_t));
+ memset(request, 0, sizeof(*request));
+ return (mmc_request_t *)request;
+}
+/* }}} */
+
+static void mmc_ascii_clone_request(mmc_request_t *clone, mmc_request_t *request) /* {{{ */
+{}
+/* }}} */
+
+static void mmc_ascii_reset_request(mmc_request_t *request) /* {{{ */
+{
+ mmc_ascii_request_t *req = (mmc_ascii_request_t *)request;
+ req->value.cas = 0;
+ mmc_request_reset(request);
+}
+/* }}} */
+
+static void mmc_ascii_begin_get(mmc_request_t *request, int op) /* {{{ */
+{
+ request->parse = mmc_request_parse_value;
+
+ if (op == MMC_OP_GETS) {
+ smart_str_appendl(&(request->sendbuf.value), "gets", sizeof("gets")-1);
+ }
+ else {
+ smart_str_appendl(&(request->sendbuf.value), "get", sizeof("get")-1);
+ }
+}
+/* }}} */
+
+static void mmc_ascii_append_get(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
+{
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+}
+/* }}} */
+
+static void mmc_ascii_end_get(mmc_request_t *request) /* {{{ */
+{
+ smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
+}
+/* }}} */
+
+static void mmc_ascii_get(mmc_request_t *request, int op, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
+{
+ mmc_ascii_begin_get(request, op);
+ mmc_ascii_append_get(request, zkey, key, key_len);
+ mmc_ascii_end_get(request);
+}
+/* }}} */
+
+static int mmc_ascii_store(
+ mmc_pool_t *pool, mmc_request_t *request, int op, const char *key, unsigned int key_len,
+ unsigned int flags, unsigned int exptime, unsigned long cas, zval *value TSRMLS_DC) /* {{{ */
+{
+ int status;
+ mmc_buffer_t buffer;
+ request->parse = mmc_request_parse_response;
+
+ memset(&buffer, 0, sizeof(buffer));
+ status = mmc_pack_value(pool, &buffer, value, &flags TSRMLS_CC);
+
+ if (status != MMC_OK) {
+ return status;
+ }
+
+ switch (op) {
+ case MMC_OP_SET:
+ smart_str_appendl(&(request->sendbuf.value), "set", sizeof("set")-1);
+ break;
+ case MMC_OP_ADD:
+ smart_str_appendl(&(request->sendbuf.value), "add", sizeof("add")-1);
+ break;
+ case MMC_OP_REPLACE:
+ smart_str_appendl(&(request->sendbuf.value), "replace", sizeof("replace")-1);
+ break;
+ case MMC_OP_CAS:
+ smart_str_appendl(&(request->sendbuf.value), "cas", sizeof("cas")-1);
+ break;
+ case MMC_OP_APPEND:
+ smart_str_appendl(&(request->sendbuf.value), "append", sizeof("append")-1);
+ break;
+ case MMC_OP_PREPEND:
+ smart_str_appendl(&(request->sendbuf.value), "prepend", sizeof("prepend")-1);
+ break;
+ default:
+ return MMC_REQUEST_FAILURE;
+ }
+
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_append_unsigned(&(request->sendbuf.value), flags);
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_append_unsigned(&(request->sendbuf.value), exptime);
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_append_unsigned(&(request->sendbuf.value), buffer.value.len);
+
+ if (op == MMC_OP_CAS) {
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_append_unsigned(&(request->sendbuf.value), cas);
+ }
+
+ smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
+ smart_str_appendl(&(request->sendbuf.value), buffer.value.c, buffer.value.len);
+ smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
+
+ mmc_buffer_free(&buffer);
+ return MMC_OK;
+}
+/* }}} */
+
+static void mmc_ascii_delete(mmc_request_t *request, const char *key, unsigned int key_len, unsigned int exptime) /* {{{ */
+{
+ request->parse = mmc_request_parse_response;
+
+ smart_str_appendl(&(request->sendbuf.value), "delete", sizeof("delete")-1);
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+
+ if (exptime > 0) {
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_append_unsigned(&(request->sendbuf.value), exptime);
+ }
+
+ smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
+}
+/* }}} */
+
+static void mmc_ascii_mutate(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, int defval_used, unsigned int exptime) /* {{{ */
+{
+ request->parse = mmc_request_parse_mutate;
+
+ if (value >= 0) {
+ smart_str_appendl(&(request->sendbuf.value), "incr", sizeof("incr")-1);
+ }
+ else {
+ smart_str_appendl(&(request->sendbuf.value), "decr", sizeof("decr")-1);
+ }
+
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_append_unsigned(&(request->sendbuf.value), value >= 0 ? value : -value);
+ smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
+}
+/* }}} */
+
+static void mmc_ascii_flush(mmc_request_t *request, unsigned int exptime) /* {{{ */
+{
+ request->parse = mmc_request_parse_response;
+ smart_str_appendl(&(request->sendbuf.value), "flush_all", sizeof("flush_all")-1);
+
+ if (exptime > 0) {
+ smart_str_appendl(&(request->sendbuf.value), " ", 1);
+ smart_str_append_unsigned(&(request->sendbuf.value), exptime);
+ }
+
+ smart_str_appendl(&(request->sendbuf.value), "\r\n", sizeof("\r\n")-1);
+}
+/* }}} */
+
+static void mmc_ascii_version(mmc_request_t *request) /* {{{ */
+{
+ request->parse = mmc_request_parse_response;
+ smart_str_appendl(&(request->sendbuf.value), "version\r\n", sizeof("version\r\n")-1);
+}
+/* }}} */
+
+static void mmc_ascii_stats(mmc_request_t *request, const char *type, long slabid, long limit) /* {{{ */
+{
+ char *cmd;
+ unsigned int cmd_len;
+ request->parse = mmc_request_parse_response;
+
+ if (slabid) {
+ cmd_len = spprintf(&cmd, 0, "stats %s %ld %ld\r\n", type, slabid, limit);
+ }
+ else if (type) {
+ cmd_len = spprintf(&cmd, 0, "stats %s\r\n", type);
+ }
+ else {
+ cmd_len = spprintf(&cmd, 0, "stats\r\n");
+ }
+
+ smart_str_appendl(&(request->sendbuf.value), cmd, cmd_len);
+ efree(cmd);
+}
+/* }}} */
+
+mmc_protocol_t mmc_ascii_protocol = {
+ mmc_ascii_create_request,
+ mmc_ascii_clone_request,
+ mmc_ascii_reset_request,
+ mmc_request_free,
+ mmc_ascii_get,
+ mmc_ascii_begin_get,
+ mmc_ascii_append_get,
+ mmc_ascii_end_get,
+ mmc_ascii_store,
+ mmc_ascii_delete,
+ mmc_ascii_mutate,
+ mmc_ascii_flush,
+ mmc_ascii_version,
+ mmc_ascii_stats
+};
+
+/*
+ * 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-3.0.5.tgz/memcache-3.0.5/memcache_binary_protocol.c
^
|
@@ -0,0 +1,596 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_binary_protocol.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include "memcache_pool.h"
+#include "ext/standard/php_smart_str.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(x) (x)
+# define htonll(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# include <byteswap.h>
+# define ntohll(x) bswap_64(x)
+# define htonll(x) bswap_64(x)
+#else
+# error "Could not determine byte order: __BYTE_ORDER uncorrectly defined"
+#endif
+
+#define MMC_REQUEST_MAGIC 0x80
+#define MMC_RESPONSE_MAGIC 0x81
+
+#define MMC_OP_GET 0x00
+#define MMC_OP_SET 0x01
+#define MMC_OP_ADD 0x02
+#define MMC_OP_REPLACE 0x03
+#define MMC_OP_DELETE 0x04
+#define MMC_OP_INCR 0x05
+#define MMC_OP_DECR 0x06
+#define MMC_OP_QUIT 0x07
+#define MMC_OP_FLUSH 0x08
+#define MMC_OP_GETQ 0x09
+#define MMC_OP_NOOP 0x0a
+#define MMC_OP_VERSION 0x0b
+
+typedef struct mmc_binary_request {
+ mmc_request_t base; /* enable cast to mmc_request_t */
+ mmc_request_parser next_parse_handler; /* next payload parser state */
+ mmc_queue_t keys; /* mmc_queue_t<zval *>, reqid -> key mappings */
+ struct {
+ uint8_t opcode;
+ uint8_t error; /* error received in current request */
+ uint32_t reqid; /* current reqid being processed */
+ } command;
+ struct { /* stores value info while the body is being read */
+ unsigned int flags;
+ unsigned long length;
+ uint64_t cas; /* CAS counter */
+ } value;
+} mmc_binary_request_t;
+
+typedef struct mmc_request_header {
+ uint8_t magic;
+ uint8_t opcode;
+ uint16_t key_len;
+ uint8_t extras_len;
+ uint8_t datatype;
+ uint16_t _reserved;
+ uint32_t length; /* trailing body length (not including this header) */
+ uint32_t reqid; /* opaque request id */
+} mmc_request_header_t;
+
+typedef struct mmc_store_request_header {
+ mmc_request_header_t base;
+ uint64_t cas;
+ uint32_t flags;
+ uint32_t exptime;
+} mmc_store_request_header_t;
+
+typedef struct mmc_delete_request_header {
+ mmc_request_header_t base;
+ uint32_t exptime;
+} mmc_delete_request_header_t;
+
+typedef struct mmc_mutate_request_header {
+ mmc_request_header_t base;
+ uint64_t value;
+ uint64_t defval;
+ uint32_t exptime;
+} mmc_mutate_request_header_t;
+
+typedef struct mmc_response_header {
+ uint8_t magic;
+ uint8_t opcode;
+ uint16_t error;
+ uint8_t extras_len;
+ uint8_t datatype;
+ uint16_t _reserved;
+ uint32_t length; /* trailing body length (not including this header) */
+ uint32_t reqid; /* echo'ed from request */
+} mmc_response_header_t;
+
+typedef struct mmc_get_response_header {
+ uint64_t cas;
+ uint32_t flags;
+} mmc_get_response_header_t;
+
+typedef struct mmc_mutate_response_header {
+ uint64_t value;
+} mmc_mutate_response_header_t;
+
+static int mmc_request_read_response(mmc_t *, mmc_request_t * TSRMLS_DC);
+static int mmc_request_parse_value(mmc_t *, mmc_request_t * TSRMLS_DC);
+static int mmc_request_read_value(mmc_t *, mmc_request_t * TSRMLS_DC);
+
+static inline char *mmc_stream_get(mmc_stream_t *io, size_t bytes TSRMLS_DC) /*
+ attempts to read a number of bytes from server, returns the a pointer to the buffer on success, NULL if the complete number of bytes could not be read {{{ */
+{
+ io->input.idx += io->read(io, io->input.value + io->input.idx, bytes - io->input.idx TSRMLS_CC);
+
+ if (io->input.idx >= bytes) {
+ io->input.idx = 0;
+ return io->input.value;
+ }
+
+ return NULL;
+}
+/* }}} */
+
+static int mmc_request_parse_response(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ reads a generic response header and reads the response body {{{ */
+{
+ mmc_response_header_t *header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ header = (mmc_response_header_t *)mmc_stream_get(request->io, sizeof(*header) TSRMLS_CC);
+ if (header != NULL) {
+ if (header->magic != MMC_RESPONSE_MAGIC) {
+ return mmc_server_failure(mmc, request->io, "Malformed server response (invalid magic byte)", 0 TSRMLS_CC);
+ }
+
+ if (header->opcode == MMC_OP_NOOP) {
+ return MMC_REQUEST_DONE;
+ }
+
+ req->command.opcode = header->opcode;
+ req->command.error = ntohs(header->error);
+ req->command.reqid = ntohl(header->reqid);
+ req->value.length = ntohl(header->length);
+
+ if (req->value.length == 0) {
+ return request->response_handler(mmc, request, req->command.error, "", 0, request->response_handler_param TSRMLS_CC);
+ }
+
+ /* allow read_response handler to read the response body */
+ if (req->command.error) {
+ request->parse = mmc_request_read_response;
+ mmc_buffer_alloc(&(request->readbuf), req->value.length + 1);
+ }
+ else {
+ request->parse = req->next_parse_handler;
+
+ if (req->value.length >= header->extras_len) {
+ req->value.length -= header->extras_len;
+ }
+
+ mmc_buffer_alloc(&(request->readbuf), req->value.length + 1);
+ }
+
+ /* read more, php streams buffer input which must be read if available */
+ return MMC_REQUEST_AGAIN;
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static int mmc_request_parse_null(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ always returns MMC_REQUEST_DONE {{{ */
+{
+ return MMC_REQUEST_DONE;
+}
+
+static int mmc_request_read_response(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ read the response body into the buffer and delegates to response_handler {{{ */
+{
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+ request->readbuf.idx +=
+ request->io->read(request->io, request->readbuf.value.c + request->readbuf.idx, req->value.length - request->readbuf.idx TSRMLS_CC);
+
+ /* done reading? */
+ if (request->readbuf.idx >= req->value.length) {
+ request->readbuf.value.c[req->value.length] = '\0';
+ return request->response_handler(mmc, request, req->command.error, request->readbuf.value.c, req->value.length, request->response_handler_param TSRMLS_CC);
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static int mmc_request_read_mutate(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ reads and parses the mutate response header {{{ */
+{
+ mmc_mutate_response_header_t *header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ header = (mmc_mutate_response_header_t *)mmc_stream_get(request->io, sizeof(*header) TSRMLS_CC);
+ if (header != NULL) {
+ int result;
+ zval *key, value;
+
+ /* convert remembered key to string and unpack value */
+ key = (zval *)mmc_queue_item(&(req->keys), req->command.reqid);
+
+ INIT_PZVAL(&value);
+ ZVAL_LONG(&value, ntohll(header->value));
+
+ if (Z_TYPE_P(key) != IS_STRING) {
+ zval keytmp = *key;
+
+ zval_copy_ctor(&keytmp);
+ INIT_PZVAL(&keytmp);
+ convert_to_string(&keytmp);
+
+ result = request->value_handler(
+ Z_STRVAL(keytmp), Z_STRLEN(keytmp), &value,
+ req->value.flags, req->value.cas, request->value_handler_param TSRMLS_CC);
+
+ zval_dtor(&keytmp);
+ }
+ else {
+ result = request->value_handler(
+ Z_STRVAL_P(key), Z_STRLEN_P(key), &value,
+ req->value.flags, req->value.cas, request->value_handler_param TSRMLS_CC);
+ }
+
+ return result;
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static int mmc_request_parse_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ reads and parses the value response header and then reads the value body {{{ */
+{
+ mmc_get_response_header_t *header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ header = (mmc_get_response_header_t *)mmc_stream_get(request->io, sizeof(*header) TSRMLS_CC);
+ if (header != NULL) {
+ req->value.cas = ntohll(header->cas);
+ req->value.flags = ntohl(header->flags);
+
+ /* allow read_value handler to read the value body */
+ request->parse = mmc_request_read_value;
+
+ /* read more, php streams buffer input which must be read if available */
+ return MMC_REQUEST_AGAIN;
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static int mmc_request_read_value(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ read the value body into the buffer {{{ */
+{
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+ request->readbuf.idx +=
+ request->io->read(request->io, request->readbuf.value.c + request->readbuf.idx, req->value.length - request->readbuf.idx TSRMLS_CC);
+
+ /* done reading? */
+ if (request->readbuf.idx >= req->value.length) {
+ zval *key;
+ int result;
+
+ /* allow parse_value to read next VALUE or NOOP, done here to ensure reentrancy */
+ if (req->command.opcode == MMC_OP_GET) {
+ request->parse = mmc_request_parse_null;
+ }
+ else {
+ request->parse = mmc_request_parse_response;
+ }
+ mmc_buffer_reset(&(request->readbuf));
+
+ /* convert remembered key to string and unpack value */
+ key = (zval *)mmc_queue_item(&(req->keys), req->command.reqid);
+ if (Z_TYPE_P(key) != IS_STRING) {
+ zval keytmp = *key;
+
+ zval_copy_ctor(&keytmp);
+ INIT_PZVAL(&keytmp);
+ convert_to_string(&keytmp);
+
+ result = mmc_unpack_value(
+ mmc, request, &(request->readbuf), Z_STRVAL(keytmp), Z_STRLEN(keytmp),
+ req->value.flags, req->value.cas, req->value.length TSRMLS_CC);
+
+ zval_dtor(&keytmp);
+ }
+ else {
+ result = mmc_unpack_value(
+ mmc, request, &(request->readbuf), Z_STRVAL_P(key), Z_STRLEN_P(key),
+ req->value.flags, req->value.cas, req->value.length TSRMLS_CC);
+ }
+
+ if (result == MMC_REQUEST_DONE && (req->command.opcode == MMC_OP_GET || req->command.reqid >= req->keys.len)) {
+ return MMC_REQUEST_DONE;
+ }
+
+ return MMC_REQUEST_AGAIN;
+ }
+
+ return MMC_REQUEST_MORE;
+}
+/* }}}*/
+
+static inline void mmc_pack_header(mmc_request_header_t *header, uint8_t opcode, unsigned int reqid, unsigned int key_len, unsigned int extras_len, unsigned int length) /* {{{ */
+{
+ header->magic = MMC_REQUEST_MAGIC;
+ header->opcode = opcode;
+ header->key_len = htons(key_len);
+ header->extras_len = extras_len;
+ header->datatype = 0;
+ header->_reserved = 0;
+ header->length = htonl(key_len + extras_len + length);
+ header->reqid = htonl(reqid);
+}
+/* }}} */
+
+static mmc_request_t *mmc_binary_create_request() /* {{{ */
+{
+ mmc_binary_request_t *request = emalloc(sizeof(mmc_binary_request_t));
+ memset(request, 0, sizeof(*request));
+ return (mmc_request_t *)request;
+}
+/* }}} */
+
+static void mmc_binary_clone_request(mmc_request_t *clone, mmc_request_t *request) /* {{{ */
+{
+ mmc_binary_request_t *rcl = (mmc_binary_request_t *)clone;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ rcl->next_parse_handler = req->next_parse_handler;
+ mmc_queue_copy(&(rcl->keys), &(req->keys));
+}
+/* }}} */
+
+static void mmc_binary_reset_request(mmc_request_t *request) /* {{{ */
+{
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+ mmc_queue_reset(&(req->keys));
+ req->value.cas = 0;
+ mmc_request_reset(request);
+}
+/* }}} */
+
+static void mmc_binary_free_request(mmc_request_t *request) /* {{{ */
+{
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+ mmc_queue_free(&(req->keys));
+ mmc_request_free(request);
+}
+/* }}} */
+
+static void mmc_binary_begin_get(mmc_request_t *request, int op) /* {{{ */
+{
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_parse_value;
+}
+/* }}} */
+
+static void mmc_binary_append_get(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
+{
+ mmc_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ /* reqid/opaque is the index into the collection of key pointers */
+ mmc_pack_header(&header, MMC_OP_GETQ, req->keys.len, key_len, 0, 0);
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+
+ /* store key to be used by the response handler */
+ mmc_queue_push(&(req->keys), zkey);
+}
+/* }}} */
+
+static void mmc_binary_end_get(mmc_request_t *request) /* {{{ */
+{
+ mmc_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+ mmc_pack_header(&header, MMC_OP_NOOP, req->keys.len, 0, 0, 0);
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+}
+/* }}} */
+
+static void mmc_binary_get(mmc_request_t *request, int op, zval *zkey, const char *key, unsigned int key_len) /* {{{ */
+{
+ mmc_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_parse_value;
+
+ /* reqid/opaque is the index into the collection of key pointers */
+ mmc_pack_header(&header, MMC_OP_GET, req->keys.len, key_len, 0, 0);
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+
+ /* store key to be used by the response handler */
+ mmc_queue_push(&(req->keys), zkey);
+}
+/* }}} */
+
+static int mmc_binary_store(
+ mmc_pool_t *pool, mmc_request_t *request, int op, const char *key, unsigned int key_len,
+ unsigned int flags, unsigned int exptime, unsigned long cas, zval *value TSRMLS_DC) /* {{{ */
+{
+ int status, prevlen, valuelen;
+ mmc_store_request_header_t *header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_read_response;
+
+ prevlen = request->sendbuf.value.len;
+
+ /* allocate space for header */
+ mmc_buffer_alloc(&(request->sendbuf), sizeof(*header));
+ request->sendbuf.value.len += sizeof(*header);
+
+ /* append key and data */
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+
+ valuelen = request->sendbuf.value.len;
+ status = mmc_pack_value(pool, &(request->sendbuf), value, &flags TSRMLS_CC);
+
+ if (status != MMC_OK) {
+ return status;
+ }
+
+ /* initialize header */
+ header = (mmc_store_request_header_t *)(request->sendbuf.value.c + prevlen);
+
+ switch (op) {
+ case MMC_OP_CAS:
+ op = MMC_OP_SET;
+ break;
+
+ case MMC_OP_APPEND:
+ case MMC_OP_PREPEND:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Binary protocol doesn't support append/prepend");
+ return MMC_REQUEST_FAILURE;
+ }
+
+ mmc_pack_header(&(header->base), op, 0, key_len, sizeof(*header) - sizeof(header->base), request->sendbuf.value.len - valuelen);
+
+ header->cas = htonll(cas);
+ header->flags = htonl(flags);
+ header->exptime = htonl(exptime);
+
+ return MMC_OK;
+}
+/* }}} */
+
+static void mmc_binary_delete(mmc_request_t *request, const char *key, unsigned int key_len, unsigned int exptime) /* {{{ */
+{
+ mmc_delete_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_read_response;
+
+ mmc_pack_header(&(header.base), MMC_OP_DELETE, 0, key_len, sizeof(header) - sizeof(header.base), 0);
+ header.exptime = htonl(exptime);
+
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+}
+/* }}} */
+
+static void mmc_binary_mutate(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, int defval_used, unsigned int exptime) /* {{{ */
+{
+ mmc_mutate_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_read_mutate;
+
+ if (value >= 0) {
+ mmc_pack_header(&(header.base), MMC_OP_INCR, req->keys.len, key_len, sizeof(header) - sizeof(header.base), 0);
+ header.value = htonll(value);
+ }
+ else {
+ mmc_pack_header(&(header.base), MMC_OP_DECR, req->keys.len, key_len, sizeof(header) - sizeof(header.base), 0);
+ header.value = htonll(-value);
+ }
+
+ header.defval = htonll(defval);
+
+ if (defval_used) {
+ /* server inserts defval if key doesn't exist */
+ header.exptime = htonl(exptime);
+ }
+ else {
+ /* server replies with NOT_FOUND if exptime ~0 and key doesn't exist */
+ header.exptime = ~(uint32_t)0;
+ }
+
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+ smart_str_appendl(&(request->sendbuf.value), key, key_len);
+
+ /* store key to be used by the response handler */
+ mmc_queue_push(&(req->keys), zkey);
+}
+/* }}} */
+
+static void mmc_binary_flush(mmc_request_t *request, unsigned int exptime) /* {{{ */
+{
+ mmc_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_read_response;
+
+ mmc_pack_header(&header, MMC_OP_FLUSH, 0, 0, 0, 0);
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+}
+/* }}} */
+
+static void mmc_binary_version(mmc_request_t *request) /* {{{ */
+{
+ mmc_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_read_response;
+
+ mmc_pack_header(&header, MMC_OP_VERSION, 0, 0, 0, 0);
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+}
+/* }}} */
+
+static void mmc_binary_stats(mmc_request_t *request, const char *type, long slabid, long limit) /* {{{ */
+{
+ /* stats not supported */
+ mmc_request_header_t header;
+ mmc_binary_request_t *req = (mmc_binary_request_t *)request;
+
+ request->parse = mmc_request_parse_response;
+ req->next_parse_handler = mmc_request_read_response;
+
+ mmc_pack_header(&header, MMC_OP_NOOP, 0, 0, 0, 0);
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+}
+/* }}} */
+
+mmc_protocol_t mmc_binary_protocol = {
+ mmc_binary_create_request,
+ mmc_binary_clone_request,
+ mmc_binary_reset_request,
+ mmc_binary_free_request,
+ mmc_binary_get,
+ mmc_binary_begin_get,
+ mmc_binary_append_get,
+ mmc_binary_end_get,
+ mmc_binary_store,
+ mmc_binary_delete,
+ mmc_binary_mutate,
+ mmc_binary_flush,
+ mmc_binary_version,
+ mmc_binary_stats
+};
+
+/*
+ * 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-3.0.5.tgz/memcache-3.0.5/memcache_consistent_hash.c
^
|
@@ -0,0 +1,184 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_consistent_hash.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#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_t *hash;
+} mmc_consistent_state_t;
+
+void *mmc_consistent_create_state(mmc_hash_function_t *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;
+
+ /* 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, unsigned int key_len TSRMLS_DC) /* {{{ */
+{
+ mmc_consistent_state_t *state = s;
+
+ if (state->num_servers > 1) {
+ unsigned int hash;
+
+ if (!state->buckets_populated) {
+ mmc_consistent_populate_buckets(state);
+ }
+
+ hash = mmc_hash(state->hash, key, key_len);
+ return state->buckets[hash % MMC_CONSISTENT_BUCKETS];
+ }
+
+ return state->points[0].server;
+}
+/* }}} */
+
+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;
+ unsigned int seed = state->hash->init(), hash;
+
+ /* buffer for "host:port-i\0" */
+ char *key = emalloc(strlen(mmc->host) + MAX_LENGTH_OF_LONG * 2 + 3);
+ key_len = sprintf(key, "%s:%d-", mmc->host, mmc->tcp.port);
+ seed = state->hash->combine(seed, key, key_len);
+
+ /* add weight * MMC_CONSISTENT_POINTS number of points for this server */
+ state->points = erealloc(state->points, sizeof(*state->points) * (state->num_points + points));
+
+ for (i=0; i<points; i++) {
+ key_len = sprintf(key, "%d", i);
+ hash = state->hash->finish(state->hash->combine(seed, key, key_len));
+ state->points[state->num_points + i].server = mmc;
+ state->points[state->num_points + i].point = hash;
+ }
+
+ state->num_points += points;
+ state->num_servers++;
+ state->buckets_populated = 0;
+
+ efree(key);
+}
+/* }}} */
+
+mmc_hash_strategy_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-3.0.5.tgz/memcache-3.0.5/memcache_pool.c
^
|
@@ -0,0 +1,1720 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_pool.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <zlib.h>
+#include <arpa/inet.h>
+
+#include "php.h"
+#include "php_network.h"
+#include "ext/standard/crc32.h"
+#include "ext/standard/php_var.h"
+#include "ext/standard/php_string.h"
+#include "ext/standard/php_smart_str.h"
+#include "memcache_pool.h"
+
+ZEND_DECLARE_MODULE_GLOBALS(memcache)
+
+inline void mmc_buffer_alloc(mmc_buffer_t *buffer, unsigned int size) /*
+ ensures space for an additional size bytes {{{ */
+{
+ register size_t newlen;
+ smart_str_alloc((&(buffer->value)), size, 0);
+}
+/* }}} */
+
+inline void mmc_buffer_free(mmc_buffer_t *buffer) /* {{{ */
+{
+ if (buffer->value.c != NULL) {
+ smart_str_free(&(buffer->value));
+ }
+ memset(buffer, 0, sizeof(*buffer));
+}
+/* }}} */
+
+static unsigned int mmc_hash_crc32_init() { return ~0; }
+static unsigned int mmc_hash_crc32_finish(unsigned int seed) { return ~seed; }
+
+static unsigned int mmc_hash_crc32_combine(unsigned int seed, const void *key, unsigned int key_len) /*
+ CRC32 hash {{{ */
+{
+ const char *p = (const char *)key, *end = p + key_len;
+ while (p < end) {
+ CRC32(seed, *(p++));
+ }
+
+ return seed;
+}
+/* }}} */
+
+mmc_hash_function_t mmc_hash_crc32 = {
+ mmc_hash_crc32_init,
+ mmc_hash_crc32_combine,
+ mmc_hash_crc32_finish
+};
+
+static unsigned int mmc_hash_fnv1a_combine(unsigned int seed, const void *key, unsigned int key_len) /*
+ FNV-1a hash {{{ */
+{
+ const char *p = (const char *)key, *end = p + key_len;
+ while (p < end) {
+ seed ^= (unsigned int)*(p++);
+ seed *= FNV_32_PRIME;
+ }
+
+ return seed;
+}
+/* }}} */
+
+static unsigned int mmc_hash_fnv1a_init() { return FNV_32_INIT; }
+static unsigned int mmc_hash_fnv1a_finish(unsigned int seed) { return seed; }
+
+mmc_hash_function_t mmc_hash_fnv1a = {
+ mmc_hash_fnv1a_init,
+ mmc_hash_fnv1a_combine,
+ mmc_hash_fnv1a_finish
+};
+
+double timeval_to_double(struct timeval tv) {
+ return (double)tv.tv_sec + ((double)tv.tv_usec) / 1000000;
+}
+
+struct timeval double_to_timeval(double sec) {
+ struct timeval tv;
+ tv.tv_sec = (long)sec;
+ tv.tv_usec = (sec - tv.tv_sec) * 1000000;
+ return tv;
+}
+
+static size_t mmc_stream_read_buffered(mmc_stream_t *io, char *buf, size_t count TSRMLS_DC) /*
+ attempts to reads count bytes from the stream buffer {{{ */
+{
+ size_t toread = io->buffer.value.len - io->buffer.idx < count ? io->buffer.value.len - io->buffer.idx : count;
+ memcpy(buf, io->buffer.value.c + io->buffer.idx, toread);
+ io->buffer.idx += toread;
+ return toread;
+}
+/* }}} */
+
+static char *mmc_stream_readline_buffered(mmc_stream_t *io, char *buf, size_t maxlen, size_t *retlen TSRMLS_DC) /*
+ reads count bytes from the stream buffer, this implementation only detects \r\n (like memcached sends) {{{ */
+{
+ char *eol;
+
+ eol = memchr(io->buffer.value.c + io->buffer.idx, '\n', io->buffer.value.len - io->buffer.idx);
+ if (eol != NULL) {
+ *retlen = eol - io->buffer.value.c - io->buffer.idx + 1;
+ }
+ else {
+ *retlen = io->buffer.value.len - io->buffer.idx;
+ }
+
+ /* ensure space for data + \0 */
+ if (*retlen >= maxlen) {
+ *retlen = maxlen - 1;
+ }
+
+ memcpy(buf, io->buffer.value.c + io->buffer.idx, *retlen);
+ io->buffer.idx += *retlen;
+ buf[*retlen] = '\0';
+
+ return buf;
+}
+/* }}} */
+
+static size_t mmc_stream_read_wrapper(mmc_stream_t *io, char *buf, size_t count TSRMLS_DC) /* {{{ */
+{
+ return php_stream_read(io->stream, buf, count);
+}
+/* }}} */
+
+static char *mmc_stream_readline_wrapper(mmc_stream_t *io, char *buf, size_t maxlen, size_t *retlen TSRMLS_DC) /* {{{ */
+{
+ return php_stream_get_line(io->stream, ZSTR(buf), maxlen, retlen);
+}
+/* }}} */
+
+void mmc_request_reset(mmc_request_t *request) /* {{{ */
+{
+ request->key_len = 0;
+ mmc_buffer_reset(&(request->sendbuf));
+ mmc_queue_reset(&(request->failed_servers));
+ request->failed_index = 0;
+}
+/* }}} */
+
+void mmc_request_free(mmc_request_t *request) /* {{{ */
+{
+ mmc_buffer_free(&(request->sendbuf));
+ mmc_buffer_free(&(request->readbuf));
+ mmc_queue_free(&(request->failed_servers));
+ efree(request);
+}
+/* }}} */
+
+static inline int mmc_request_send(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /* {{{ */
+{
+ int count, bytes;
+
+ /* send next chunk of buffer */
+ count = request->sendbuf.value.len - request->sendbuf.idx;
+ if (count > request->io->stream->chunk_size) {
+ count = request->io->stream->chunk_size;
+ }
+
+ bytes = send(request->io->fd, request->sendbuf.value.c + request->sendbuf.idx, count, MSG_NOSIGNAL);
+ if (bytes >= 0) {
+ request->sendbuf.idx += bytes;
+
+ /* done sending? */
+ if (request->sendbuf.idx >= request->sendbuf.value.len) {
+ return MMC_REQUEST_DONE;
+ }
+
+ return MMC_REQUEST_MORE;
+ }
+ else {
+ char *message, buf[1024];
+ long err = php_socket_errno();
+
+ if (err == EAGAIN) {
+ return MMC_REQUEST_MORE;
+ }
+
+ message = php_socket_strerror(err, buf, 1024);
+ return mmc_server_failure(mmc, request->io, message, err TSRMLS_CC);
+ }
+}
+/* }}} */
+
+static int mmc_request_read_udp(mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ reads an entire datagram into buffer and validates the udp header {{{ */
+{
+ size_t bytes;
+ mmc_udp_header_t *header;
+
+ /* reset buffer if completely consumed */
+ if (request->io->buffer.idx >= request->io->buffer.value.len) {
+ mmc_buffer_reset(&(request->io->buffer));
+ }
+
+ /* attempt to read datagram + sentinel-byte */
+ mmc_buffer_alloc(&(request->io->buffer), MMC_MAX_UDP_LEN + 1);
+ bytes = php_stream_read(request->io->stream, request->io->buffer.value.c + request->io->buffer.value.len, MMC_MAX_UDP_LEN + 1);
+
+ if (bytes < sizeof(mmc_udp_header_t)) {
+ return mmc_server_failure(mmc, request->io, "Failed te read complete UDP header from stream", 0 TSRMLS_CC);
+ }
+ if (bytes > MMC_MAX_UDP_LEN) {
+ return mmc_server_failure(mmc, request->io, "Server sent packet larger than MMC_MAX_UDP_LEN bytes", 0 TSRMLS_CC);
+ }
+
+ header = (mmc_udp_header_t *)(request->io->buffer.value.c + request->io->buffer.value.len);
+ uint16_t reqid = ntohs(header->reqid);
+ uint16_t seqid = ntohs(header->seqid);
+
+ /* initialize udp header fields */
+ if (!request->udp.total && request->udp.reqid == reqid) {
+ request->udp.seqid = seqid;
+ request->udp.total = ntohs(header->total);
+ }
+
+ /* detect dropped packets and reschedule for tcp delivery */
+ if (request->udp.reqid != reqid || request->udp.seqid != seqid) {
+ /* ensure that no more udp requests are scheduled for a while */
+ request->io->status = MMC_STATUS_FAILED;
+ request->io->failed = (long)time(NULL);
+
+ /* discard packets for previous requests */
+ if (reqid < request->udp.reqid) {
+ return MMC_REQUEST_MORE;
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "UDP packet loss, expected reqid/seqid %d/%d got %d/%d",
+ (int)request->udp.reqid, (int)request->udp.seqid, (int)reqid, (int)seqid);
+ return MMC_REQUEST_RETRY;
+ }
+
+ request->udp.seqid++;
+
+ /* skip udp header */
+ if (request->io->buffer.idx > 0) {
+ memmove(
+ request->io->buffer.value.c + request->io->buffer.value.len,
+ request->io->buffer.value.c + request->io->buffer.value.len + sizeof(mmc_udp_header_t),
+ bytes - sizeof(mmc_udp_header_t));
+ }
+ else {
+ request->io->buffer.idx += sizeof(mmc_udp_header_t);
+ }
+
+ request->io->buffer.value.len += bytes;
+ return MMC_OK;
+}
+/* }}} */
+
+static void mmc_compress(mmc_pool_t *pool, mmc_buffer_t *buffer, const char *value, int value_len, unsigned int *flags, int copy TSRMLS_DC) /* {{{ */
+{
+ /* autocompress large values */
+ if (pool->compress_threshold && value_len >= pool->compress_threshold) {
+ *flags |= MMC_COMPRESSED;
+ }
+
+ if (*flags & MMC_COMPRESSED) {
+ int status;
+ mmc_buffer_t prev;
+ unsigned long result_len = value_len * (1 - pool->min_compress_savings);
+
+ if (copy) {
+ /* value is already in output buffer */
+ prev = *buffer;
+
+ /* allocate space for prev header + result */
+ memset(buffer, 0, sizeof(*buffer));
+ mmc_buffer_alloc(buffer, prev.value.len + result_len);
+
+ /* append prev header */
+ smart_str_appendl(&(buffer->value), prev.value.c, prev.value.len - value_len);
+ buffer->idx = prev.idx;
+ }
+ else {
+ /* allocate space directly in buffer */
+ mmc_buffer_alloc(buffer, result_len);
+ }
+
+ if (MMC_COMPRESSION_LEVEL >= 0) {
+ status = compress2((unsigned char *)buffer->value.c + buffer->value.len, &result_len, (unsigned const char *)value, value_len, MMC_COMPRESSION_LEVEL);
+ } else {
+ status = compress((unsigned char *)buffer->value.c + buffer->value.len, &result_len, (unsigned const char *)value, value_len);
+ }
+
+ if (status == Z_OK) {
+ buffer->value.len += result_len;
+ }
+ else {
+ smart_str_appendl(&(buffer->value), value, value_len);
+ *flags &= ~MMC_COMPRESSED;
+ }
+
+ if (copy) {
+ mmc_buffer_free(&prev);
+ }
+ }
+ else if (!copy) {
+ smart_str_appendl(&(buffer->value), value, value_len);
+ }
+}
+/* }}}*/
+
+static int mmc_uncompress(const char *data, unsigned long data_len, char **result, unsigned long *result_len) /* {{{ */
+{
+ int status, factor = 1;
+
+ do {
+ *result_len = data_len * (1 << factor++);
+ *result = (char *)erealloc(*result, *result_len + 1);
+ status = uncompress((unsigned char *)*result, result_len, (unsigned const char *)data, data_len);
+ } while (status == Z_BUF_ERROR && factor < 16);
+
+ if (status == Z_OK) {
+ return MMC_OK;
+ }
+
+ efree(*result);
+ return MMC_REQUEST_FAILURE;
+}
+/* }}}*/
+
+int mmc_pack_value(mmc_pool_t *pool, mmc_buffer_t *buffer, zval *value, unsigned int *flags TSRMLS_DC) /*
+ does serialization and compression to pack a zval into the buffer {{{ */
+{
+ if (*flags & 0xffff & ~MMC_COMPRESSED) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The lowest two bytes of the flags array is reserved for pecl/memcache internal use");
+ return MMC_REQUEST_FAILURE;
+ }
+
+ *flags &= ~MMC_SERIALIZED;
+ switch (Z_TYPE_P(value)) {
+ case IS_STRING:
+ *flags |= MMC_TYPE_STRING;
+ mmc_compress(pool, buffer, Z_STRVAL_P(value), Z_STRLEN_P(value), flags, 0 TSRMLS_CC);
+ break;
+
+ case IS_LONG:
+ *flags |= MMC_TYPE_LONG;
+ *flags &= ~MMC_COMPRESSED;
+ smart_str_append_long(&(buffer->value), Z_LVAL_P(value));
+ break;
+
+ case IS_DOUBLE: {
+ char buf[256];
+ int len = snprintf(buf, 256, "%.14g", Z_DVAL_P(value));
+ *flags |= MMC_TYPE_DOUBLE;
+ *flags &= ~MMC_COMPRESSED;
+ smart_str_appendl(&(buffer->value), buf, len);
+ break;
+ }
+
+ case IS_BOOL:
+ *flags |= MMC_TYPE_BOOL;
+ *flags &= ~MMC_COMPRESSED;
+ smart_str_appendc(&(buffer->value), Z_BVAL_P(value) ? '1' : '0');
+ break;
+
+ default: {
+ php_serialize_data_t value_hash;
+ zval value_copy, *value_copy_ptr;
+ size_t prev_len = buffer->value.len;
+
+ /* 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(&(buffer->value), &value_copy_ptr, &value_hash TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(value_hash);
+
+ /* trying to save null or something went really wrong */
+ if (buffer->value.c == NULL || buffer->value.len == prev_len) {
+ zval_dtor(&value_copy);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to serialize value");
+ return MMC_REQUEST_FAILURE;
+ }
+
+ *flags |= MMC_SERIALIZED;
+ zval_dtor(&value_copy);
+
+ mmc_compress(pool, buffer, buffer->value.c + prev_len, buffer->value.len - prev_len, flags, 1 TSRMLS_CC);
+ }
+ }
+
+ return MMC_OK;
+}
+/* }}} */
+
+int mmc_unpack_value(
+ mmc_t *mmc, mmc_request_t *request, mmc_buffer_t *buffer, const char *key, unsigned int key_len,
+ unsigned int flags, unsigned long cas, unsigned int bytes TSRMLS_DC) /*
+ does uncompression and unserializing to reconstruct a zval {{{ */
+{
+ char *data = NULL;
+ unsigned long data_len;
+
+ zval value;
+ INIT_ZVAL(value);
+
+ if (flags & MMC_COMPRESSED) {
+ if (mmc_uncompress(buffer->value.c, bytes, &data, &data_len) != MMC_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to uncompress data");
+ return MMC_REQUEST_DONE;
+ }
+ }
+ else {
+ data = buffer->value.c;
+ data_len = bytes;
+ }
+
+ if (flags & MMC_SERIALIZED) {
+ php_unserialize_data_t var_hash;
+ const unsigned char *p = (unsigned char *)data;
+ zval *object = &value;
+
+ char key_tmp[MMC_MAX_KEY_LEN + 1];
+ mmc_request_value_handler value_handler;
+ void *value_handler_param;
+ mmc_buffer_t buffer_tmp;
+
+ /* make copies of data to ensure re-entrancy */
+ memcpy(key_tmp, key, key_len + 1);
+ value_handler = request->value_handler;
+ value_handler_param = request->value_handler_param;
+
+ if (!(flags & MMC_COMPRESSED)) {
+ buffer_tmp = *buffer;
+ mmc_buffer_release(buffer);
+ }
+
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ if (!php_var_unserialize(&object, &p, p + data_len, &var_hash TSRMLS_CC)) {
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+
+ if (flags & MMC_COMPRESSED) {
+ efree(data);
+ }
+ else if (buffer->value.c == NULL) {
+ *buffer = buffer_tmp;
+ }
+ else {
+ mmc_buffer_free(&buffer_tmp);
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to unserialize data");
+ return MMC_REQUEST_DONE;
+ }
+
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+
+ if (flags & MMC_COMPRESSED) {
+ efree(data);
+ }
+ else if (buffer->value.c == NULL) {
+ *buffer = buffer_tmp;
+ }
+ else {
+ mmc_buffer_free(&buffer_tmp);
+ }
+
+ /* delegate to value handler */
+ return value_handler(key_tmp, key_len, object, flags, cas, value_handler_param TSRMLS_CC);
+ }
+ else {
+ switch (flags & 0x0f00) {
+ case MMC_TYPE_LONG: {
+ long val;
+ data[data_len] = '\0';
+ val = strtol(data, NULL, 10);
+ ZVAL_LONG(&value, val);
+ break;
+ }
+
+ case MMC_TYPE_DOUBLE: {
+ double val = 0;
+ data[data_len] = '\0';
+ sscanf(data, "%lg", &val);
+ ZVAL_DOUBLE(&value, val);
+ break;
+ }
+
+ case MMC_TYPE_BOOL:
+ ZVAL_BOOL(&value, data_len == 1 && data[0] == '1');
+ break;
+
+ default:
+ data[data_len] = '\0';
+ ZVAL_STRINGL(&value, data, data_len, 0);
+
+ if (!(flags & MMC_COMPRESSED)) {
+ /* release buffer because it's now owned by the zval */
+ mmc_buffer_release(buffer);
+ }
+ }
+
+ /* delegate to value handler */
+ return request->value_handler(key, key_len, &value, flags, cas, request->value_handler_param TSRMLS_CC);
+ }
+}
+/* }}}*/
+
+
+mmc_t *mmc_server_new(
+ const char *host, int host_len, unsigned short tcp_port, unsigned short udp_port,
+ int persistent, double 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->tcp.port = tcp_port;
+ mmc->tcp.status = MMC_STATUS_DISCONNECTED;
+ mmc->udp.port = udp_port;
+ mmc->udp.status = MMC_STATUS_DISCONNECTED;
+
+ mmc->persistent = persistent;
+ mmc->timeout = double_to_timeval(timeout);
+
+ mmc->tcp.retry_interval = retry_interval;
+ mmc->tcp.chunk_size = MEMCACHE_G(chunk_size);
+ mmc->udp.retry_interval = retry_interval;
+ mmc->udp.chunk_size = MEMCACHE_G(chunk_size); /* = MMC_MAX_UDP_LEN;*/
+
+ return mmc;
+}
+/* }}} */
+
+static void _mmc_server_disconnect(mmc_t *mmc, mmc_stream_t *io, int close_persistent_stream TSRMLS_DC) /* {{{ */
+{
+ mmc_buffer_free(&(io->buffer));
+
+ if (io->stream != NULL) {
+ if (mmc->persistent) {
+ if (close_persistent_stream) {
+ php_stream_pclose(io->stream);
+ }
+ }
+ else {
+ php_stream_close(io->stream);
+ }
+
+ io->stream = NULL;
+ io->fd = 0;
+ }
+
+ io->status = MMC_STATUS_DISCONNECTED;
+}
+/* }}} */
+
+void mmc_server_disconnect(mmc_t *mmc, mmc_stream_t *io TSRMLS_DC) /* {{{ */
+{
+ _mmc_server_disconnect(mmc, io, 1 TSRMLS_CC);
+}
+/* }}} */
+
+static void mmc_server_seterror(mmc_t *mmc, const char *error, int errnum) /* {{{ */
+{
+ if (error != NULL) {
+ if (mmc->error != NULL) {
+ efree(mmc->error);
+ }
+
+ mmc->error = estrdup(error);
+ mmc->errnum = errnum;
+ }
+}
+/* }}} */
+
+static void mmc_server_deactivate(mmc_pool_t *pool, mmc_t *mmc TSRMLS_DC) /*
+ disconnect and marks the server as down, failovers all queued requests {{{ */
+{
+ mmc_queue_t readqueue;
+ mmc_request_t *request;
+
+ mmc_server_disconnect(mmc, &(mmc->tcp) TSRMLS_CC);
+ mmc_server_disconnect(mmc, &(mmc->udp) TSRMLS_CC);
+
+ mmc->tcp.status = MMC_STATUS_FAILED;
+ mmc->udp.status = MMC_STATUS_FAILED;
+ mmc->tcp.failed = (long)time(NULL);
+ mmc->udp.failed = mmc->tcp.failed;
+
+ mmc_queue_remove(pool->sending, mmc);
+ mmc_queue_remove(pool->reading, mmc);
+
+ /* failover queued requests, sendque can be ignored since
+ * readque + readreq + buildreq will always contain all active requests */
+ mmc_queue_reset(&(mmc->sendqueue));
+ mmc->sendreq = NULL;
+
+ readqueue = mmc->readqueue;
+ mmc_queue_release(&(mmc->readqueue));
+
+ if (mmc->readreq != NULL) {
+ mmc_queue_push(&readqueue, mmc->readreq);
+ mmc->readreq = NULL;
+ }
+
+ if (mmc->buildreq != NULL) {
+ mmc_queue_push(&readqueue, mmc->buildreq);
+ mmc->buildreq = NULL;
+ }
+
+ /* delegate to failover handlers */
+ while ((request = mmc_queue_pop(&readqueue)) != NULL) {
+ request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
+ }
+
+ mmc_queue_free(&readqueue);
+
+ /* fire userspace failure event */
+ if (pool->failure_callback != NULL) {
+ pool->failure_callback(pool, mmc, pool->failure_callback_param TSRMLS_CC);
+ }
+}
+/* }}} */
+
+int mmc_server_failure(mmc_t *mmc, mmc_stream_t *io, const char *error, int errnum TSRMLS_DC) /*
+ determines if a request should be retried or is a hard network failure {{{ */
+{
+ switch (io->status) {
+ case MMC_STATUS_DISCONNECTED:
+ return MMC_REQUEST_RETRY;
+
+ /* attempt reconnect of sockets in unknown state */
+ case MMC_STATUS_UNKNOWN:
+ io->status = MMC_STATUS_DISCONNECTED;
+ return MMC_REQUEST_RETRY;
+ }
+
+ mmc_server_seterror(mmc, error, errnum);
+ return MMC_REQUEST_FAILURE;
+}
+/* }}} */
+
+int mmc_request_failure(mmc_t *mmc, mmc_stream_t *io, const char *message, unsigned int message_len, int errnum TSRMLS_DC) /*
+ checks for a valid server generated error message and calls mmc_server_failure() {{{ */
+{
+ if (message_len) {
+ return mmc_server_failure(mmc, io, message, errnum TSRMLS_CC);
+ }
+
+ return mmc_server_failure(mmc, io, "Malformed server response", errnum TSRMLS_CC);
+}
+/* }}} */
+
+static int mmc_server_connect(mmc_pool_t *pool, mmc_t *mmc, mmc_stream_t *io, int udp TSRMLS_DC) /*
+ connects a stream, calls mmc_server_deactivate() on failure {{{ */
+{
+ char *host, *hash_key = NULL, *errstr = NULL;
+ int host_len, errnum = 0;
+ struct timeval tv = mmc->timeout;
+
+ /* close open stream */
+ if (io->stream != NULL) {
+ mmc_server_disconnect(mmc, io TSRMLS_CC);
+ }
+
+ if (mmc->persistent) {
+ spprintf(&hash_key, 0, "memcache:stream:%s:%u:%d", mmc->host, io->port, udp);
+ }
+
+#if PHP_API_VERSION > 20020918
+
+ if (udp) {
+ host_len = spprintf(&host, 0, "udp://%s:%u", mmc->host, io->port);
+ }
+ else if (io->port) {
+ host_len = spprintf(&host, 0, "%s:%u", mmc->host, io->port);
+ }
+ else {
+ host_len = spprintf(&host, 0, "%s", mmc->host);
+ }
+
+ io->stream = php_stream_xport_create(
+ host, host_len,
+ ENFORCE_SAFE_MODE | REPORT_ERRORS | (mmc->persistent ? STREAM_OPEN_PERSISTENT : 0),
+ STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
+ hash_key, &tv, NULL, &errstr, &errnum);
+
+ efree(host);
+
+#else
+
+ if (mmc->persistent) {
+ switch (php_stream_from_persistent_id(hash_key, &(io->stream) TSRMLS_CC)) {
+ case PHP_STREAM_PERSISTENT_SUCCESS:
+ if (php_stream_eof(io->stream)) {
+ php_stream_pclose(io->stream);
+ io->stream = NULL;
+ io->fd = 0;
+ break;
+ }
+ case PHP_STREAM_PERSISTENT_FAILURE:
+ break;
+ }
+ }
+
+ if (io->stream == NULL) {
+ if (io->port) {
+ io->stream = php_stream_sock_open_host(mmc->host, io->port, udp ? SOCK_DGRAM : SOCK_STREAM, &tv, hash_key);
+ }
+ else if (strncasecmp("unix://", mmc->host, sizeof("unix://")-1) == 0 && strlen(mmc->host) > sizeof("unix://")-1) {
+ io->stream = php_stream_sock_open_unix(mmc->host + sizeof("unix://")-1, strlen(mmc->host + sizeof("unix://")-1), hash_key, &tv);
+ }
+ else {
+ io->stream = php_stream_sock_open_unix(mmc->host, strlen(mmc->host), hash_key, &tv);
+ }
+ }
+
+#endif
+
+ if (hash_key != NULL) {
+ efree(hash_key);
+ }
+
+ /* check connection and extract socket for select() purposes */
+ void *fd;
+
+ if (!io->stream || php_stream_cast(io->stream, PHP_STREAM_AS_FD_FOR_SELECT, &fd, 1) != SUCCESS) {
+ mmc_server_seterror(mmc, errstr != NULL ? errstr : "Connection failed", errnum);
+ mmc_server_deactivate(pool, mmc TSRMLS_CC);
+
+ if (errstr != NULL) {
+ efree(errstr);
+ }
+
+ return MMC_REQUEST_FAILURE;
+ }
+
+ io->fd = (long)fd;
+ io->status = MMC_STATUS_CONNECTED;
+
+ php_stream_auto_cleanup(io->stream);
+ php_stream_set_chunk_size(io->stream, io->chunk_size);
+ php_stream_set_option(io->stream, PHP_STREAM_OPTION_BLOCKING, 0, NULL);
+ php_stream_set_option(io->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &(mmc->timeout));
+
+ /* doing our own buffering increases performance */
+ php_stream_set_option(io->stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
+ php_stream_set_option(io->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
+
+ /* php_stream buffering prevent us from detecting datagram boundaries when using udp */
+ if (udp) {
+ io->read = mmc_stream_read_buffered;
+ io->readline = mmc_stream_readline_buffered;
+ }
+ else {
+ io->read = mmc_stream_read_wrapper;
+ io->readline = mmc_stream_readline_wrapper;
+ }
+
+#ifdef SO_NOSIGPIPE
+ /* Mac OS X doesn't have MSG_NOSIGNAL */
+ {
+ int optval = 1;
+ setsockopt(io->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&optval, sizeof(optval));
+ }
+#endif
+
+ if (mmc->error != NULL) {
+ efree(mmc->error);
+ mmc->error = NULL;
+ }
+
+ return MMC_OK;
+}
+/* }}} */
+
+int mmc_server_valid(mmc_t *mmc TSRMLS_DC) /*
+ checks if a server should be considered valid to serve requests {{{ */
+{
+ if (mmc != NULL) {
+ if (mmc->tcp.status >= MMC_STATUS_DISCONNECTED) {
+ return 1;
+ }
+
+ if (mmc->tcp.status == MMC_STATUS_FAILED &&
+ mmc->tcp.retry_interval >= 0 && (long)time(NULL) >= mmc->tcp.failed + mmc->tcp.retry_interval) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+/* }}} */
+
+void mmc_server_sleep(mmc_t *mmc TSRMLS_DC) /*
+ prepare server struct for persistent sleep {{{ */
+{
+ mmc_buffer_free(&(mmc->tcp.buffer));
+ mmc_buffer_free(&(mmc->udp.buffer));
+
+ mmc->sendreq = NULL;
+ mmc->readreq = NULL;
+ mmc->buildreq = NULL;
+
+ mmc_queue_free(&(mmc->sendqueue));
+ mmc_queue_free(&(mmc->readqueue));
+
+ if (mmc->error != NULL) {
+ efree(mmc->error);
+ mmc->error = NULL;
+ }
+}
+/* }}} */
+
+void mmc_server_free(mmc_t *mmc TSRMLS_DC) /* {{{ */
+{
+ mmc_server_sleep(mmc TSRMLS_CC);
+ _mmc_server_disconnect(mmc, &(mmc->tcp), 0 TSRMLS_CC);
+ _mmc_server_disconnect(mmc, &(mmc->udp), 0 TSRMLS_CC);
+
+ pefree(mmc->host, mmc->persistent);
+ pefree(mmc, mmc->persistent);
+}
+/* }}} */
+
+static void mmc_pool_init_hash(mmc_pool_t *pool TSRMLS_DC) /* {{{ */
+{
+ mmc_hash_function_t *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));
+ memset(pool, 0, sizeof(*pool));
+
+ switch (MEMCACHE_G(protocol)) {
+ case MMC_BINARY_PROTOCOL:
+ pool->protocol = &mmc_binary_protocol;
+ break;
+ default:
+ pool->protocol = &mmc_ascii_protocol;
+ }
+
+ mmc_pool_init_hash(pool TSRMLS_CC);
+ pool->compress_threshold = MEMCACHE_G(compress_threshold);
+ pool->min_compress_savings = MMC_DEFAULT_SAVINGS;
+
+ pool->sending = &(pool->_sending1);
+ pool->reading = &(pool->_reading1);
+
+ return pool;
+}
+/* }}} */
+
+void mmc_pool_free(mmc_pool_t *pool TSRMLS_DC) /* {{{ */
+{
+ int i;
+ mmc_request_t *request;
+
+ for (i=0; i<pool->num_servers; i++) {
+ if (pool->servers[i] != NULL) {
+ if (pool->servers[i]->persistent) {
+ mmc_server_sleep(pool->servers[i] TSRMLS_CC);
+ } else {
+ mmc_server_free(pool->servers[i] TSRMLS_CC);
+ }
+ pool->servers[i] = NULL;
+ }
+ }
+
+ if (pool->num_servers) {
+ efree(pool->servers);
+ }
+
+ pool->hash->free_state(pool->hash_state);
+
+ mmc_queue_free(&(pool->_sending1));
+ mmc_queue_free(&(pool->_sending2));
+ mmc_queue_free(&(pool->_reading1));
+ mmc_queue_free(&(pool->_reading2));
+ mmc_queue_free(&(pool->pending));
+
+ /* requests are owned by us so free them */
+ while ((request = mmc_queue_pop(&(pool->free_requests))) != NULL) {
+ pool->protocol->free_request(request);
+ }
+ mmc_queue_free(&(pool->free_requests));
+
+ efree(pool);
+}
+/* }}} */
+
+void mmc_pool_add(mmc_pool_t *pool, mmc_t *mmc, unsigned int weight) /*
+ adds a server to the pool and hash strategy {{{ */
+{
+ pool->hash->add_server(pool->hash_state, mmc, weight);
+ pool->servers = erealloc(pool->servers, sizeof(*pool->servers) * (pool->num_servers + 1));
+ pool->servers[pool->num_servers] = mmc;
+
+ /* store the smallest timeout for any server */
+ if (!pool->num_servers || timeval_to_double(mmc->timeout) < timeval_to_double(pool->timeout)) {
+ pool->timeout = mmc->timeout;
+ }
+
+ pool->num_servers++;
+}
+/* }}} */
+
+void 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) {
+ mmc_server_sleep(pool->servers[i] TSRMLS_CC);
+ } else {
+ mmc_server_free(pool->servers[i] TSRMLS_CC);
+ }
+ }
+
+ efree(pool->servers);
+ pool->servers = NULL;
+ pool->num_servers = 0;
+
+ /* reallocate the hash strategy state */
+ pool->hash->free_state(pool->hash_state);
+ mmc_pool_init_hash(pool TSRMLS_CC);
+ }
+}
+/* }}} */
+
+int mmc_pool_open(mmc_pool_t *pool, mmc_t *mmc, mmc_stream_t *io, int udp TSRMLS_DC) /*
+ connects if the stream is not already connected {{{ */
+{
+ switch (io->status) {
+ case MMC_STATUS_CONNECTED:
+ case MMC_STATUS_UNKNOWN:
+ return MMC_OK;
+
+ case MMC_STATUS_DISCONNECTED:
+ case MMC_STATUS_FAILED:
+ return mmc_server_connect(pool, mmc, io, udp TSRMLS_CC);
+ }
+
+ return MMC_REQUEST_FAILURE;
+}
+/* }}} */
+
+mmc_t *mmc_pool_find_next(mmc_pool_t *pool, const char *key, unsigned int key_len, mmc_queue_t *skip_servers, unsigned int *last_index TSRMLS_DC) /*
+ finds the next server in the failover sequence {{{ */
+{
+ mmc_t *mmc;
+ char keytmp[MMC_MAX_KEY_LEN + MAX_LENGTH_OF_LONG + 1];
+ unsigned int keytmp_len;
+
+ /* find the next server not present in the skip-list */
+ do {
+ keytmp_len = sprintf(keytmp, "%s-%d", key, (*last_index)++);
+ mmc = pool->hash->find_server(pool->hash_state, keytmp, keytmp_len TSRMLS_CC);
+ } while (mmc_queue_contains(skip_servers, mmc) && *last_index < MEMCACHE_G(max_failover_attempts));
+
+ return mmc;
+}
+
+mmc_t *mmc_pool_find(mmc_pool_t *pool, const char *key, unsigned int key_len TSRMLS_DC) /*
+ maps a key to a non-failed server {{{ */
+{
+ mmc_t *mmc = pool->hash->find_server(pool->hash_state, key, key_len TSRMLS_CC);
+
+ /* check validity and try to failover otherwise */
+ if (!mmc_server_valid(mmc TSRMLS_CC) && MEMCACHE_G(allow_failover)) {
+ unsigned int last_index = 0;
+
+ do {
+ mmc = mmc_pool_find_next(pool, key, key_len, NULL, &last_index TSRMLS_CC);
+ } while (!mmc_server_valid(mmc TSRMLS_CC) && last_index < MEMCACHE_G(max_failover_attempts));
+ }
+
+ return mmc;
+}
+/* }}} */
+
+int mmc_pool_failover_handler(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC) /*
+ uses request->key to reschedule request to other server {{{ */
+{
+ if (MEMCACHE_G(allow_failover) && request->failed_index < MEMCACHE_G(max_failover_attempts) && request->failed_servers.len < pool->num_servers) {
+ do {
+ mmc_queue_push(&(request->failed_servers), mmc);
+ mmc = mmc_pool_find_next(pool, request->key, request->key_len, &(request->failed_servers), &(request->failed_index) TSRMLS_CC);
+ } while (!mmc_server_valid(mmc TSRMLS_CC) && request->failed_index < MEMCACHE_G(max_failover_attempts) && request->failed_servers.len < pool->num_servers);
+
+ return mmc_pool_schedule(pool, mmc, request TSRMLS_CC);
+ }
+
+ mmc_pool_release(pool, request);
+ return MMC_REQUEST_FAILURE;
+}
+/* }}}*/
+
+int mmc_pool_failover_handler_null(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC) /*
+ always returns failure {{{ */
+{
+ mmc_pool_release(pool, request);
+ return MMC_REQUEST_FAILURE;
+}
+/* }}}*/
+
+static int mmc_pool_response_handler_null(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
+ always returns done {{{ */
+{
+ return MMC_REQUEST_DONE;
+}
+/* }}}*/
+
+static inline mmc_request_t *mmc_pool_request_alloc(mmc_pool_t *pool, int protocol,
+ mmc_request_failover_handler failover_handler, void *failover_handler_param TSRMLS_DC) /* {{{ */
+{
+ mmc_request_t *request = mmc_queue_pop(&(pool->free_requests));
+ if (request == NULL) {
+ request = pool->protocol->create_request();
+ }
+ else {
+ pool->protocol->reset_request(request);
+ }
+
+ request->protocol = protocol;
+
+ if (protocol == MMC_PROTO_UDP) {
+ mmc_udp_header_t header = {0};
+ smart_str_appendl(&(request->sendbuf.value), (const char *)&header, sizeof(header));
+ }
+
+ request->failover_handler = failover_handler != NULL ? failover_handler : mmc_pool_failover_handler_null;
+ request->failover_handler_param = failover_handler_param;
+
+ return request;
+}
+/* }}} */
+
+mmc_request_t *mmc_pool_request(mmc_pool_t *pool, int protocol,
+ mmc_request_response_handler response_handler, void *response_handler_param,
+ mmc_request_failover_handler failover_handler, void *failover_handler_param TSRMLS_DC) /*
+ allocates a request, must be added to pool using mmc_pool_schedule or released with mmc_pool_release {{{ */
+{
+ mmc_request_t *request = mmc_pool_request_alloc(pool, protocol, failover_handler, failover_handler_param TSRMLS_CC);
+ request->response_handler = response_handler;
+ request->response_handler_param = response_handler_param;
+ return request;
+}
+/* }}} */
+
+mmc_request_t *mmc_pool_request_get(mmc_pool_t *pool, int protocol,
+ mmc_request_value_handler value_handler, void *value_handler_param,
+ mmc_request_failover_handler failover_handler, void *failover_handler_param TSRMLS_DC) /*
+ allocates a request, must be added to pool using mmc_pool_schedule or released with mmc_pool_release {{{ */
+{
+ mmc_request_t *request = mmc_pool_request(
+ pool, protocol,
+ mmc_pool_response_handler_null, NULL,
+ failover_handler, failover_handler_param TSRMLS_CC);
+
+ request->value_handler = value_handler;
+ request->value_handler_param = value_handler_param;
+ return request;
+}
+/* }}} */
+
+mmc_request_t *mmc_pool_clone_request(mmc_pool_t *pool, mmc_request_t *request TSRMLS_DC) /*
+ clones a request, must be added to pool using mmc_pool_schedule or released with mmc_pool_release {{{ */
+{
+ mmc_request_t *clone = mmc_pool_request_alloc(pool, request->protocol, NULL, NULL TSRMLS_CC);
+
+ clone->response_handler = request->response_handler;
+ clone->response_handler_param = request->response_handler_param;
+ clone->value_handler = request->value_handler;
+ clone->value_handler_param = request->value_handler_param;
+
+ /* copy payload parser */
+ clone->parse = request->parse;
+
+ /* copy key */
+ memcpy(clone->key, request->key, request->key_len);
+ clone->key_len = request->key_len;
+
+ /* copy sendbuf */
+ mmc_buffer_alloc(&(clone->sendbuf), request->sendbuf.value.len);
+ memcpy(clone->sendbuf.value.c, request->sendbuf.value.c, request->sendbuf.value.len);
+ clone->sendbuf.value.len = request->sendbuf.value.len;
+
+ /* copy protocol specific values */
+ pool->protocol->clone_request(clone, request);
+
+ return clone;
+}
+/* }}} */
+
+static int mmc_pool_slot_send(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, int handle_failover TSRMLS_DC) /* {{{ */
+{
+ if (request != NULL) {
+ /* select protocol strategy and open connection */
+ if (request->protocol == MMC_PROTO_UDP && mmc->udp.port &&
+ request->sendbuf.value.len <= mmc->udp.chunk_size &&
+ mmc_pool_open(pool, mmc, &(mmc->udp), 1 TSRMLS_CC) == MMC_OK)
+ {
+ request->io = &(mmc->udp);
+ request->read = mmc_request_read_udp;
+
+ /* initialize udp header */
+ request->udp.reqid = mmc->reqid++;
+ request->udp.seqid = 0;
+ request->udp.total = 0;
+
+ ((mmc_udp_header_t *)request->sendbuf.value.c)->reqid = htons(request->udp.reqid);
+ ((mmc_udp_header_t *)request->sendbuf.value.c)->total = htons(1);
+ }
+ else if (mmc_pool_open(pool, mmc, &(mmc->tcp), 0 TSRMLS_CC) == MMC_OK) {
+ /* skip udp header */
+ if (request->protocol == MMC_PROTO_UDP) {
+ request->sendbuf.idx += sizeof(mmc_udp_header_t);
+ }
+
+ request->io = &(mmc->tcp);
+ request->read = NULL;
+ }
+ else {
+ mmc->sendreq = NULL;
+ if (handle_failover) {
+ return request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
+ }
+ return MMC_REQUEST_FAILURE;
+ }
+ }
+
+ mmc->sendreq = request;
+ return MMC_OK;
+}
+/* }}} */
+
+int mmc_pool_schedule(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ schedules a request against a server, return MMC_OK on success {{{ */
+{
+ if (!mmc_server_valid(mmc TSRMLS_CC)) {
+ /* delegate to failover handler if connect fails */
+ return request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
+ }
+
+ /* reset sendbuf to start position */
+ request->sendbuf.idx = 0;
+ /* reset readbuf entirely */
+ mmc_buffer_reset(&(request->readbuf));
+
+ /* push request into sendreq slot if available */
+ if (mmc->sendreq == NULL) {
+ if (mmc_pool_slot_send(pool, mmc, request, 0 TSRMLS_CC) != MMC_OK) {
+ return request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
+ }
+ mmc_queue_push(pool->sending, mmc);
+ }
+ else {
+ mmc_queue_push(&(mmc->sendqueue), request);
+ }
+
+ /* push request into readreq slot if available */
+ if (mmc->readreq == NULL) {
+ mmc->readreq = request;
+ mmc_queue_push(pool->reading, mmc);
+ }
+ else {
+ mmc_queue_push(&(mmc->readqueue), request);
+ }
+
+ return MMC_OK;
+}
+/* }}} */
+
+int mmc_pool_schedule_key(mmc_pool_t *pool, const char *key, unsigned int key_len, mmc_request_t *request, unsigned int redundancy TSRMLS_DC) /*
+ schedules a request against a server selected by the provided key, return MMC_OK on success {{{ */
+{
+ if (redundancy > 1) {
+ int i, result;
+ mmc_t *mmc;
+
+ unsigned int last_index = 0;
+ mmc_queue_t skip_servers = {0};
+
+ /* schedule the first request */
+ mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC);
+ result = mmc_pool_schedule(pool, mmc, request TSRMLS_CC);
+
+ /* clone and schedule redundancy-1 additional requests */
+ for (i=0; i < redundancy-1 && i < pool->num_servers-1; i++) {
+ mmc_queue_push(&skip_servers, mmc);
+ mmc = mmc_pool_find_next(pool, key, key_len, &skip_servers, &last_index TSRMLS_CC);
+
+ if (mmc_server_valid(mmc TSRMLS_CC)) {
+ mmc_pool_schedule(pool, mmc, mmc_pool_clone_request(pool, request TSRMLS_CC) TSRMLS_CC);
+ }
+ }
+
+ mmc_queue_free(&skip_servers);
+ return result;
+ }
+
+ return mmc_pool_schedule(pool, mmc_pool_find(pool, key, key_len TSRMLS_CC), request TSRMLS_CC);
+}
+/* }}} */
+
+int mmc_pool_schedule_get(
+ mmc_pool_t *pool, int protocol, int op, zval *zkey,
+ mmc_request_value_handler value_handler, void *value_handler_param,
+ mmc_request_failover_handler failover_handler, void *failover_handler_param,
+ mmc_request_t *failed_request TSRMLS_DC) /*
+ schedules a get command against a server {{{ */
+{
+ mmc_t *mmc;
+ char key[MMC_MAX_KEY_LEN + 1];
+ unsigned int key_len;
+
+ if (mmc_prepare_key(zkey, key, &key_len) != MMC_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid key");
+ return MMC_REQUEST_FAILURE;
+ }
+
+ mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC);
+ if (!mmc_server_valid(mmc TSRMLS_CC)) {
+ return MMC_REQUEST_FAILURE;
+ }
+
+ if (mmc->buildreq == NULL) {
+ mmc_queue_push(&(pool->pending), mmc);
+
+ mmc->buildreq = mmc_pool_request_get(
+ pool, protocol, value_handler, value_handler_param,
+ failover_handler, failover_handler_param TSRMLS_CC);
+
+ if (failed_request != NULL) {
+ mmc_queue_copy(&(mmc->buildreq->failed_servers), &(failed_request->failed_servers));
+ mmc->buildreq->failed_index = failed_request->failed_index;
+ }
+
+ pool->protocol->begin_get(mmc->buildreq, op);
+ }
+ else if (protocol == MMC_PROTO_UDP && mmc->buildreq->sendbuf.value.len + key_len + 3 > MMC_MAX_UDP_LEN) {
+ /* datagram if full, schedule for delivery */
+ pool->protocol->end_get(mmc->buildreq);
+ mmc_pool_schedule(pool, mmc, mmc->buildreq TSRMLS_CC);
+
+ /* begin sending requests immediatly */
+ mmc_pool_select(pool TSRMLS_CC);
+
+ mmc->buildreq = mmc_pool_request_get(
+ pool, protocol, value_handler, value_handler_param,
+ failover_handler, failover_handler_param TSRMLS_CC);
+
+ if (failed_request != NULL) {
+ mmc_queue_copy(&(mmc->buildreq->failed_servers), &(failed_request->failed_servers));
+ mmc->buildreq->failed_index = failed_request->failed_index;
+ }
+
+ pool->protocol->begin_get(mmc->buildreq, op);
+ }
+
+ pool->protocol->append_get(mmc->buildreq, zkey, key, key_len);
+ return MMC_OK;
+}
+/* }}} */
+
+static inline void mmc_pool_switch(mmc_pool_t *pool) {
+ /* switch sending and reading queues */
+ if (pool->sending == &(pool->_sending1)) {
+ pool->sending = &(pool->_sending2);
+ pool->reading = &(pool->_reading2);
+ }
+ else {
+ pool->sending = &(pool->_sending1);
+ pool->reading = &(pool->_reading1);
+ }
+
+ /* reset queues so they can be re-populated */
+ mmc_queue_reset(pool->sending);
+ mmc_queue_reset(pool->reading);
+}
+
+static int mmc_select_failure(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, int result TSRMLS_DC) /* {{{ */
+{
+ if (result == 0) {
+ /* timeout expired, non-responsive server */
+ if (mmc_server_failure(mmc, request->io, "Network timeout", 0 TSRMLS_CC) == MMC_REQUEST_RETRY) {
+ return MMC_REQUEST_RETRY;
+ }
+ }
+ else {
+ char buf[1024];
+ const char *message;
+ long err = php_socket_errno();
+
+ if (err) {
+ message = php_socket_strerror(err, buf, 1024);
+ }
+ else {
+ message = "Unknown select() error";
+ }
+
+ mmc_server_seterror(mmc, message, errno);
+ }
+
+ /* hard failure, deactivate connection */
+ mmc_server_deactivate(pool, mmc TSRMLS_CC);
+ return MMC_REQUEST_FAILURE;
+}
+/* }}} */
+
+static void mmc_select_retry(mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request TSRMLS_DC) /*
+ removes request from send/read queues and calls failover {{{ */
+{
+ /* clear out failed request from queues */
+ mmc_queue_remove(&(mmc->sendqueue), request);
+ mmc_queue_remove(&(mmc->readqueue), request);
+
+ /* shift next request into send slot */
+ if (mmc->sendreq == request) {
+ mmc_pool_slot_send(pool, mmc, mmc_queue_pop(&(mmc->sendqueue)), 1 TSRMLS_CC);
+
+ /* clear out connection from send queue if no new request was slotted */
+ if (!mmc->sendreq) {
+ mmc_queue_remove(pool->sending, mmc);
+ }
+ }
+
+ /* shift next request into read slot */
+ if (mmc->readreq == request) {
+ mmc->readreq = mmc_queue_pop(&(mmc->readqueue));
+
+ /* clear out connection from read queue if no new request was slotted */
+ if (!mmc->readreq) {
+ mmc_queue_remove(pool->reading, mmc);
+ }
+ }
+
+ request->failover_handler(pool, mmc, request, request->failover_handler_param TSRMLS_CC);
+}
+/* }}} */
+
+void mmc_pool_select(mmc_pool_t *pool TSRMLS_DC) /*
+ runs one select() round on all scheduled requests {{{ */
+{
+ int i, fd, result;
+ mmc_t *mmc;
+ mmc_queue_t *sending, *reading;
+
+ /* help complete previous run */
+ if (pool->in_select) {
+ if (pool->sending == &(pool->_sending1)) {
+ sending = &(pool->_sending2);
+ reading = &(pool->_reading2);
+ }
+ else {
+ sending = &(pool->_sending1);
+ reading = &(pool->_reading1);
+ }
+ }
+ else {
+ int nfds = 0;
+ struct timeval tv = pool->timeout;
+
+ sending = pool->sending;
+ reading = pool->reading;
+ mmc_pool_switch(pool);
+
+ FD_ZERO(&(pool->wfds));
+ FD_ZERO(&(pool->rfds));
+
+ for (i=0; i < sending->len; i++) {
+ mmc = mmc_queue_item(sending, i);
+ if (mmc->sendreq->io->fd > nfds) {
+ nfds = mmc->sendreq->io->fd;
+ }
+ FD_SET(mmc->sendreq->io->fd, &(pool->wfds));
+ }
+
+ for (i=0; i < reading->len; i++) {
+ mmc = mmc_queue_item(reading, i);
+ if (mmc->readreq->io->fd > nfds) {
+ nfds = mmc->readreq->io->fd;
+ }
+ FD_SET(mmc->readreq->io->fd, &(pool->rfds));
+ }
+
+ result = select(nfds + 1, &(pool->rfds), &(pool->wfds), NULL, &tv);
+
+ /* if select timed out */
+ if (result <= 0) {
+ for (i=0; i < sending->len; i++) {
+ mmc = (mmc_t *)mmc_queue_item(sending, i);
+
+ /* remove sending request */
+ if (!FD_ISSET(mmc->sendreq->io->fd, &(pool->wfds))) {
+ mmc_queue_remove(sending, mmc);
+ mmc_queue_remove(reading, mmc);
+ i--;
+
+ if (mmc_select_failure(pool, mmc, mmc->sendreq, result TSRMLS_CC) == MMC_REQUEST_RETRY) {
+ /* allow request to try and send again */
+ mmc_select_retry(pool, mmc, mmc->sendreq TSRMLS_CC);
+ }
+ }
+ }
+
+ for (i=0; i < reading->len; i++) {
+ mmc = (mmc_t *)mmc_queue_item(reading, i);
+
+ /* remove reading request */
+ if (!FD_ISSET(mmc->readreq->io->fd, &(pool->rfds))) {
+ mmc_queue_remove(sending, mmc);
+ mmc_queue_remove(reading, mmc);
+ i--;
+
+ if (mmc_select_failure(pool, mmc, mmc->readreq, result TSRMLS_CC) == MMC_REQUEST_RETRY) {
+ /* allow request to try and read again */
+ mmc_select_retry(pool, mmc, mmc->readreq TSRMLS_CC);
+ }
+ }
+ }
+ }
+
+ pool->in_select = 1;
+ }
+
+ for (i=0; i < sending->len; i++) {
+ mmc = mmc_queue_item(sending, i);
+
+ /* skip servers which have failed */
+ if (!mmc->sendreq) {
+ continue;
+ }
+
+ if (FD_ISSET(mmc->sendreq->io->fd, &(pool->wfds))) {
+ fd = mmc->sendreq->io->fd;
+
+ /* clear bit for reentrancy reasons */
+ FD_CLR(fd, &(pool->wfds));
+
+ /* until stream buffer is empty */
+ do {
+ /* delegate to request send handler */
+ result = mmc_request_send(mmc, mmc->sendreq TSRMLS_CC);
+
+ /* check if someone has helped complete our run */
+ if (!pool->in_select) {
+ return;
+ }
+
+ switch (result) {
+ case MMC_REQUEST_FAILURE:
+ /* take server offline and failover requests */
+ mmc_server_deactivate(pool, mmc TSRMLS_CC);
+
+ /* server is failed, remove from read queue */
+ mmc_queue_remove(reading, mmc);
+ break;
+
+ case MMC_REQUEST_RETRY:
+ /* allow request to reschedule itself */
+ mmc_select_retry(pool, mmc, mmc->sendreq TSRMLS_CC);
+ break;
+
+ case MMC_REQUEST_DONE:
+ /* shift next request into send slot */
+ mmc_pool_slot_send(pool, mmc, mmc_queue_pop(&(mmc->sendqueue)), 1 TSRMLS_CC);
+ break;
+
+ case MMC_REQUEST_MORE:
+ /* send more data to socket */
+ break;
+
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid return value, bailing out");
+ }
+ } while (mmc->sendreq != NULL && (result == MMC_REQUEST_DONE || result == MMC_REQUEST_AGAIN));
+
+ if (result == MMC_REQUEST_MORE) {
+ /* add server to read queue once more */
+ mmc_queue_push(pool->sending, mmc);
+ }
+ }
+ else {
+ /* add server to send queue once more */
+ mmc_queue_push(pool->sending, mmc);
+ }
+ }
+
+ for (i=0; i < reading->len; i++) {
+ mmc = mmc_queue_item(reading, i);
+
+ /* skip servers which have failed */
+ if (!mmc->readreq) {
+ continue;
+ }
+
+ if (FD_ISSET(mmc->readreq->io->fd, &(pool->rfds))) {
+ fd = mmc->readreq->io->fd;
+
+ /* clear bit for reentrancy reasons */
+ FD_CLR(fd, &(pool->rfds));
+
+ /* fill read buffer if needed */
+ if (mmc->readreq->read != NULL) {
+ result = mmc->readreq->read(mmc, mmc->readreq TSRMLS_CC);
+
+ if (result != MMC_OK) {
+ switch (result) {
+ case MMC_REQUEST_FAILURE:
+ /* take server offline and failover requests */
+ mmc_server_deactivate(pool, mmc TSRMLS_CC);
+ break;
+
+ case MMC_REQUEST_RETRY:
+ /* allow request to reschedule itself */
+ mmc_select_retry(pool, mmc, mmc->readreq TSRMLS_CC);
+ break;
+
+ case MMC_REQUEST_MORE:
+ /* add server to read queue once more */
+ mmc_queue_push(pool->reading, mmc);
+ break;
+
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid return value, bailing out");
+ }
+
+ /* skip to next request */
+ continue;
+ }
+ }
+
+ /* until stream buffer is empty */
+ do {
+ /* delegate to request response handler */
+ result = mmc->readreq->parse(mmc, mmc->readreq TSRMLS_CC);
+
+ /* check if someone has helped complete our run */
+ if (!pool->in_select) {
+ return;
+ }
+
+ switch (result) {
+ case MMC_REQUEST_FAILURE:
+ /* take server offline and failover requests */
+ mmc_server_deactivate(pool, mmc TSRMLS_CC);
+ break;
+
+ case MMC_REQUEST_RETRY:
+ /* allow request to reschedule itself */
+ mmc_select_retry(pool, mmc, mmc->readreq TSRMLS_CC);
+ break;
+
+ case MMC_REQUEST_DONE:
+ /* might have completed without having sent all data (e.g. object too large errors) */
+ if (mmc->sendreq == mmc->readreq) {
+ /* disconnect stream since data may have been sent before we received the SERVER_ERROR */
+ mmc_server_disconnect(mmc, mmc->readreq->io TSRMLS_CC);
+
+ /* shift next request into send slot */
+ mmc_pool_slot_send(pool, mmc, mmc_queue_pop(&(mmc->sendqueue)), 1 TSRMLS_CC);
+
+ /* clear out connection from send queue if no new request was slotted */
+ if (!mmc->sendreq) {
+ mmc_queue_remove(pool->sending, mmc);
+ }
+ }
+
+ /* release completed request */
+ mmc_pool_release(pool, mmc->readreq);
+
+ /* shift next request into read slot */
+ mmc->readreq = mmc_queue_pop(&(mmc->readqueue));
+ break;
+
+ case MMC_REQUEST_MORE:
+ /* read more data from socket */
+ if (php_stream_eof(mmc->readreq->io->stream)) {
+ result = mmc_server_failure(mmc, mmc->readreq->io, "Read failed (socket was unexpectedly closed)", 0 TSRMLS_CC);
+ if (result == MMC_REQUEST_FAILURE) {
+ /* take server offline and failover requests */
+ mmc_server_deactivate(pool, mmc TSRMLS_CC);
+ }
+ }
+ break;
+
+ case MMC_REQUEST_AGAIN:
+ /* request wants another loop */
+ break;
+
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid return value, bailing out");
+ }
+ } while (mmc->readreq != NULL && (result == MMC_REQUEST_DONE || result == MMC_REQUEST_AGAIN));
+
+ if (result == MMC_REQUEST_MORE) {
+ /* add server to read queue once more */
+ mmc_queue_push(pool->reading, mmc);
+ }
+ }
+ else {
+ /* add server to read queue once more */
+ mmc_queue_push(pool->reading, mmc);
+ }
+ }
+
+ pool->in_select = 0;
+}
+/* }}} */
+
+void mmc_pool_run(mmc_pool_t *pool TSRMLS_DC) /*
+ runs all scheduled requests to completion {{{ */
+{
+ mmc_t *mmc;
+ while ((mmc = mmc_queue_pop(&(pool->pending))) != NULL) {
+ pool->protocol->end_get(mmc->buildreq);
+ mmc_pool_schedule(pool, mmc, mmc->buildreq TSRMLS_CC);
+ mmc->buildreq = NULL;
+ }
+
+ while (pool->reading->len || pool->sending->len) {
+ mmc_pool_select(pool TSRMLS_CC);
+ }
+}
+/* }}} */
+
+inline int mmc_prepare_key_ex(const char *key, unsigned int key_len, char *result, unsigned int *result_len) /* {{{ */
+{
+ unsigned int i;
+ if (key_len == 0) {
+ return MMC_REQUEST_FAILURE;
+ }
+
+ *result_len = key_len < MMC_MAX_KEY_LEN ? key_len : MMC_MAX_KEY_LEN;
+ result[*result_len] = '\0';
+
+ for (i=0; i<*result_len; i++) {
+ result[i] = ((unsigned char)key[i]) > ' ' ? key[i] : '_';
+ }
+
+ return MMC_OK;
+}
+/* }}} */
+
+inline int mmc_prepare_key(zval *key, char *result, unsigned int *result_len) /* {{{ */
+{
+ if (Z_TYPE_P(key) == IS_STRING) {
+ return mmc_prepare_key_ex(Z_STRVAL_P(key), Z_STRLEN_P(key), result, result_len);
+ } else {
+ int res;
+ zval keytmp = *key;
+
+ zval_copy_ctor(&keytmp);
+ convert_to_string(&keytmp);
+
+ res = mmc_prepare_key_ex(Z_STRVAL(keytmp), Z_STRLEN(keytmp), result, result_len);
+
+ zval_dtor(&keytmp);
+ return res;
+ }
+}
+/* }}} */
+
+
+/*
+ * 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-3.0.5.tgz/memcache-3.0.5/memcache_pool.h
^
|
@@ -0,0 +1,418 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_pool.h 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#ifndef MEMCACHE_POOL_H
+#define MEMCACHE_POOL_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include <stdint.h>
+#include <string.h>
+
+#include "php.h"
+#include "ext/standard/php_smart_str_public.h"
+#include "memcache_queue.h"
+
+#ifndef ZSTR
+#define ZSTR
+#define ZSTR_VAL(v) v
+#define zstr char *
+#else
+#define ZSTR_VAL(v) (v).s
+#endif
+
+/*
+ * Mac OS X has no MSG_NOSIGNAL but >= 10.2 comes with SO_NOSIGPIPE which is a setsockopt() option
+ * and not a send() parameter as MSG_NOSIGNAL. OpenBSD has none of the options so we need to ignore
+ * SIGPIPE events
+ */
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif /*MSG_NOSIGNAL*/
+
+/* use lowest byte for flags */
+#define MMC_SERIALIZED 0x0001
+#define MMC_COMPRESSED 0x0002
+
+/* use second lowest byte to indicate data type */
+#define MMC_TYPE_STRING 0x0000
+#define MMC_TYPE_BOOL 0x0100
+/*#define MMC_TYPE_INT 0x0200*/
+#define MMC_TYPE_LONG 0x0300
+/*#define MMC_TYPE_DATE 0x0400*/
+/*#define MMC_TYPE_BYTE 0x0500*/
+/*#define MMC_TYPE_FLOAT 0x0600*/
+#define MMC_TYPE_DOUBLE 0x0700
+/*#define MMC_TYPE_BLOB 0x0800*/
+
+#define MMC_BUFFER_SIZE 4096
+#define MMC_MAX_UDP_LEN 1400
+#define MMC_MAX_KEY_LEN 250
+#define MMC_VALUE_HEADER "VALUE %250s %u %lu %lu" /* keep in sync with MMC_MAX_KEY_LEN */
+
+#define MMC_COMPRESSION_LEVEL Z_DEFAULT_COMPRESSION
+#define MMC_DEFAULT_COMPRESS 20000 /* minimum 20k byte values for auto compression to be used */
+#define MMC_DEFAULT_SAVINGS 0.2 /* minimum 20% savings for compression to be used */
+
+#define MMC_PROTO_TCP 0
+#define MMC_PROTO_UDP 1
+
+#define MMC_STATUS_FAILED -1 /* server/stream is down */
+#define MMC_STATUS_DISCONNECTED 0 /* stream is disconnected, ie. new connection */
+#define MMC_STATUS_UNKNOWN 1 /* stream is in unknown state, ie. non-validated persistent connection */
+#define MMC_STATUS_CONNECTED 2 /* stream is connected */
+
+#define MMC_OK 0
+
+#define MMC_REQUEST_FAILURE -1 /* operation failed, failover to other server */
+#define MMC_REQUEST_DONE 0 /* ok result, or reading/writing is done */
+#define MMC_REQUEST_MORE 1 /* more data follows in another packet, try select() again */
+#define MMC_REQUEST_AGAIN 2 /* more data follows in this packet, try read/write again */
+#define MMC_REQUEST_RETRY 3 /* retry/reschedule request */
+
+#define MMC_RESPONSE_UNKNOWN -2
+#define MMC_RESPONSE_ERROR -1
+#define MMC_RESPONSE_NOT_FOUND 0x01 /* same as binary protocol */
+#define MMC_RESPONSE_EXISTS 0x02 /* same as binary protocol */
+#define MMC_RESPONSE_TOO_LARGE 0x03 /* same as binary protocol */
+#define MMC_RESPONSE_NOT_STORED 0x05 /* same as binary protocol */
+#define MMC_RESPONSE_UNKNOWN_CMD 0x81 /* same as binary protocol */
+#define MMC_RESPONSE_OUT_OF_MEMORY 0x82 /* same as binary protocol */
+
+#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 */
+
+/* io buffer */
+typedef struct mmc_buffer {
+ smart_str value;
+ unsigned int idx; /* current index */
+} mmc_buffer_t;
+
+#define mmc_buffer_release(b) memset((b), 0, sizeof(*(b)))
+#define mmc_buffer_reset(b) (b)->value.len = (b)->idx = 0
+
+inline void mmc_buffer_alloc(mmc_buffer_t *, unsigned int);
+inline void mmc_buffer_free(mmc_buffer_t *);
+
+/* stream handlers */
+typedef struct mmc_stream mmc_stream_t;
+
+typedef size_t (*mmc_stream_read)(mmc_stream_t *stream, char *buf, size_t count TSRMLS_DC);
+typedef char *(*mmc_stream_readline)(mmc_stream_t *stream, char *buf, size_t maxlen, size_t *retlen TSRMLS_DC);
+
+/* stream container */
+struct mmc_stream {
+ php_stream *stream;
+ int fd; /* file descriptor for select() */
+ unsigned short port; /* tcp/udp port stream is connected to */
+ int chunk_size; /* stream chunk size */
+ int status; /* stream status in MMC_STATUS_* status codes */
+ long failed; /* the timestamp the stream was marked as failed */
+ long retry_interval; /* seconds to wait before automatic reconnect */
+ mmc_buffer_t buffer; /* read buffer (when using udp) */
+ mmc_stream_read read; /* handles reading from stream */
+ mmc_stream_readline readline; /* handles reading lines from stream */
+ struct { /* temporary input buffer, see mmc_server_readline() */
+ char value[MMC_BUFFER_SIZE];
+ int idx;
+ } input;
+};
+
+/* request handlers */
+typedef struct mmc mmc_t;
+typedef struct mmc_pool mmc_pool_t;
+typedef struct mmc_request mmc_request_t;
+
+typedef int (*mmc_request_reader)(mmc_t *mmc, mmc_request_t *request TSRMLS_DC);
+typedef int (*mmc_request_parser)(mmc_t *mmc, mmc_request_t *request TSRMLS_DC);
+typedef int (*mmc_request_value_handler)(
+ const char *key, unsigned int key_len, zval *value,
+ unsigned int flags, unsigned long cas, void *param TSRMLS_DC);
+typedef int (*mmc_request_response_handler)(
+ mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC);
+typedef int (*mmc_request_failover_handler)(
+ mmc_pool_t *pool, mmc_t *mmc, mmc_request_t *request, void *param TSRMLS_DC);
+
+void mmc_request_reset(mmc_request_t *);
+void mmc_request_free(mmc_request_t *);
+
+/* server request */
+struct mmc_request {
+ mmc_stream_t *io; /* stream this request is sending on */
+ mmc_buffer_t sendbuf; /* request buffer */
+ mmc_buffer_t readbuf; /* response buffer */
+ char key[MMC_MAX_KEY_LEN + 1]; /* key buffer to use on failover of single-key requests */
+ unsigned int key_len;
+ unsigned int protocol; /* protocol encoding of request {tcp, udp} */
+ mmc_queue_t failed_servers; /* mmc_queue_t<mmc_t *>, servers this request has failed at */
+ unsigned int failed_index; /* last index probed on failure */
+ mmc_request_reader read; /* handles reading (and validating datagrams) */
+ mmc_request_parser parse; /* called to parse response payload */
+ mmc_request_value_handler value_handler; /* called when result value have been parsed */
+ void *value_handler_param;
+ mmc_request_response_handler response_handler; /* called when a non-value response has been received */
+ void *response_handler_param;
+ mmc_request_failover_handler failover_handler; /* called to perform failover of failed request */
+ void *failover_handler_param;
+ struct {
+ uint16_t reqid; /* id of the request, increasing value set by client */
+ uint16_t seqid; /* next expected seqid */
+ uint16_t total; /* number of datagrams in response */
+ } udp;
+};
+
+/* udp protocol header */
+typedef struct mmc_udp_header {
+ uint16_t reqid; /* id of the request, increasing value set by client */
+ uint16_t seqid; /* index of this datagram in response */
+ uint16_t total; /* number of datagrams in response */
+ uint16_t _reserved;
+} mmc_udp_header_t;
+
+/* server */
+struct mmc {
+ mmc_stream_t tcp; /* main stream, might be tcp or unix socket */
+ mmc_stream_t udp; /* auxiliary udp connection */
+ mmc_request_t *sendreq; /* currently sending request, NULL if none */
+ mmc_request_t *readreq; /* currently reading request, NULL if none */
+ mmc_request_t *buildreq; /* request currently being built, NULL if none */
+ mmc_queue_t sendqueue; /* mmc_queue_t<mmc_request_t *>, requests waiting to be sent */
+ mmc_queue_t readqueue; /* mmc_queue_t<mmc_request_t *>, requests waiting to be read */
+ char *host;
+ struct timeval timeout; /* network timeout for this server */
+ int persistent;
+ uint16_t reqid; /* next sequential request id */
+ char *error; /* last error message */
+ int errnum; /* last error code */
+};
+
+/* wire protocol */
+#define MMC_ASCII_PROTOCOL 1
+#define MMC_BINARY_PROTOCOL 2
+
+/* same as in binary protocol */
+#define MMC_OP_GET 0x00
+#define MMC_OP_SET 0x01
+#define MMC_OP_ADD 0x02
+#define MMC_OP_REPLACE 0x03
+#define MMC_OP_GETS 0x32
+#define MMC_OP_CAS 0x33
+#define MMC_OP_APPEND 0x34 /* not supported by binary protocol */
+#define MMC_OP_PREPEND 0x35 /* not supported by binary protocol */
+
+typedef mmc_request_t * (*mmc_protocol_create_request)();
+typedef void (*mmc_protocol_clone_request)(mmc_request_t *clone, mmc_request_t *request);
+typedef void (*mmc_protocol_reset_request)(mmc_request_t *request);
+typedef void (*mmc_protocol_free_request)(mmc_request_t *request);
+
+typedef void (*mmc_protocol_get)(mmc_request_t *request, int op, zval *zkey, const char *key, unsigned int key_len);
+typedef void (*mmc_protocol_begin_get)(mmc_request_t *request, int op);
+typedef void (*mmc_protocol_append_get)(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len);
+typedef void (*mmc_protocol_end_get)(mmc_request_t *request);
+
+typedef int (*mmc_protocol_store)(
+ mmc_pool_t *pool, mmc_request_t *request, int op, const char *key, unsigned int key_len,
+ unsigned int flags, unsigned int exptime, unsigned long cas, zval *value TSRMLS_DC);
+typedef void (*mmc_protocol_delete)(mmc_request_t *request, const char *key, unsigned int key_len, unsigned int exptime);
+typedef void (*mmc_protocol_mutate)(mmc_request_t *request, zval *zkey, const char *key, unsigned int key_len, long value, long defval, int defval_used, unsigned int exptime);
+
+typedef void (*mmc_protocol_flush)(mmc_request_t *request, unsigned int exptime);
+typedef void (*mmc_protocol_stats)(mmc_request_t *request, const char *type, long slabid, long limit);
+typedef void (*mmc_protocol_version)(mmc_request_t *request);
+
+typedef struct mmc_protocol {
+ mmc_protocol_create_request create_request;
+ mmc_protocol_clone_request clone_request;
+ mmc_protocol_reset_request reset_request;
+ mmc_protocol_free_request free_request;
+
+ mmc_protocol_get get;
+ mmc_protocol_begin_get begin_get;
+ mmc_protocol_append_get append_get;
+ mmc_protocol_end_get end_get;
+
+ mmc_protocol_store store;
+ mmc_protocol_delete delete;
+ mmc_protocol_mutate mutate;
+
+ mmc_protocol_flush flush;
+ mmc_protocol_version version;
+ mmc_protocol_stats stats;
+} mmc_protocol_t;
+
+extern mmc_protocol_t mmc_ascii_protocol;
+extern mmc_protocol_t mmc_binary_protocol;
+
+/* hashing strategy */
+typedef unsigned int (*mmc_hash_function_init)();
+typedef unsigned int (*mmc_hash_function_combine)(unsigned int seed, const void *key, unsigned int key_len);
+typedef unsigned int (*mmc_hash_function_finish)(unsigned int seed);
+
+typedef struct mmc_hash_function {
+ mmc_hash_function_init init;
+ mmc_hash_function_combine combine;
+ mmc_hash_function_finish finish;
+} mmc_hash_function_t;
+
+extern mmc_hash_function_t mmc_hash_crc32;
+extern mmc_hash_function_t mmc_hash_fnv1a;
+
+#define mmc_hash(hash, key, key_len) ((hash)->finish((hash)->combine((hash)->init(), (key), (key_len))))
+
+typedef void * (*mmc_hash_create_state)(mmc_hash_function_t *);
+typedef void (*mmc_hash_free_state)(void *state);
+typedef mmc_t * (*mmc_hash_find_server)(void *state, const char *key, unsigned int key_len TSRMLS_DC);
+typedef void (*mmc_hash_add_server)(void *state, mmc_t *mmc, unsigned int weight);
+
+typedef struct mmc_hash_strategy {
+ 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_strategy_t;
+
+extern mmc_hash_strategy_t mmc_standard_hash;
+extern mmc_hash_strategy_t mmc_consistent_hash;
+
+/* 32 bit magic FNV-1a prime and init */
+#define FNV_32_PRIME 0x01000193
+#define FNV_32_INIT 0x811c9dc5
+
+/* failure callback prototype */
+typedef void (*mmc_failure_callback)(mmc_pool_t *pool, mmc_t *mmc, void *param TSRMLS_DC);
+
+/* server pool */
+struct mmc_pool {
+ mmc_t **servers;
+ int num_servers;
+ mmc_protocol_t *protocol; /* wire protocol */
+ mmc_hash_strategy_t *hash; /* hash strategy */
+ void *hash_state; /* strategy specific state */
+ fd_set wfds;
+ fd_set rfds;
+ struct timeval timeout; /* smallest timeout for any of the servers */
+ int in_select;
+ mmc_queue_t *sending; /* mmc_queue_t<mmc_t *>, connections that want to send */
+ mmc_queue_t *reading; /* mmc_queue_t<mmc_t *>, connections that want to read */
+ mmc_queue_t _sending1, _sending2;
+ mmc_queue_t _reading1, _reading2;
+ mmc_queue_t pending; /* mmc_queue_t<mmc_t *>, connections that have non-finalized requests */
+ mmc_queue_t free_requests; /* mmc_queue_t<mmc_request_t *>, request free-list */
+ double min_compress_savings;
+ unsigned int compress_threshold;
+ mmc_failure_callback failure_callback; /* receives notification when a server fails */
+ void *failure_callback_param;
+};
+
+/* server functions */
+mmc_t *mmc_server_new(const char *, int, unsigned short, unsigned short, int, double, int TSRMLS_DC);
+void mmc_server_free(mmc_t * TSRMLS_DC);
+void mmc_server_disconnect(mmc_t *mmc, mmc_stream_t *io TSRMLS_DC);
+int mmc_server_valid(mmc_t * TSRMLS_DC);
+int mmc_server_failure(mmc_t *, mmc_stream_t *, const char *, int TSRMLS_DC);
+int mmc_request_failure(mmc_t *, mmc_stream_t *, const char *, unsigned int, int TSRMLS_DC);
+
+/* pool functions */
+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);
+void mmc_pool_close(mmc_pool_t * TSRMLS_DC);
+int mmc_pool_open(mmc_pool_t *, mmc_t *, mmc_stream_t *, int TSRMLS_DC);
+void mmc_pool_select(mmc_pool_t * TSRMLS_DC);
+void mmc_pool_run(mmc_pool_t * TSRMLS_DC);
+mmc_t *mmc_pool_find_next(mmc_pool_t *, const char *, unsigned int, mmc_queue_t *, unsigned int * TSRMLS_DC);
+mmc_t *mmc_pool_find(mmc_pool_t *, const char *, unsigned int TSRMLS_DC);
+int mmc_pool_schedule(mmc_pool_t *, mmc_t *, mmc_request_t * TSRMLS_DC);
+int mmc_pool_failover_handler(mmc_pool_t *, mmc_t *, mmc_request_t *, void * TSRMLS_DC);
+int mmc_pool_failover_handler_null(mmc_pool_t *, mmc_t *, mmc_request_t *, void * TSRMLS_DC);
+
+mmc_request_t *mmc_pool_request(mmc_pool_t *, int,
+ mmc_request_response_handler, void *, mmc_request_failover_handler, void * TSRMLS_DC);
+mmc_request_t *mmc_pool_request_get(mmc_pool_t *, int,
+ mmc_request_value_handler, void *, mmc_request_failover_handler, void * TSRMLS_DC);
+
+#define mmc_pool_release(p, r) mmc_queue_push(&((p)->free_requests), (r))
+
+int mmc_prepare_store(
+ mmc_pool_t *, mmc_request_t *, const char *, unsigned int,
+ const char *, unsigned int, unsigned int, unsigned int, zval * TSRMLS_DC);
+
+int mmc_pool_schedule_key(mmc_pool_t *, const char *, unsigned int, mmc_request_t *, unsigned int TSRMLS_DC);
+int mmc_pool_schedule_get(mmc_pool_t *, int, int, zval *,
+ mmc_request_value_handler, void *, mmc_request_failover_handler, void *, mmc_request_t * TSRMLS_DC);
+
+/* utility functions */
+int mmc_pack_value(mmc_pool_t *, mmc_buffer_t *, zval *, unsigned int * TSRMLS_DC);
+int mmc_unpack_value(mmc_t *, mmc_request_t *, mmc_buffer_t *, const char *, unsigned int, unsigned int, unsigned long, unsigned int TSRMLS_DC);
+double timeval_to_double(struct timeval tv);
+struct timeval double_to_timeval(double sec);
+
+inline int mmc_prepare_key_ex(const char *, unsigned int, char *, unsigned int *);
+inline int mmc_prepare_key(zval *, char *, unsigned int *);
+
+#define mmc_str_left(h, n, hlen, nlen) ((hlen) >= (nlen) ? memcmp((h), (n), (nlen)) == 0 : 0)
+
+/* globals */
+ZEND_BEGIN_MODULE_GLOBALS(memcache)
+ long default_port;
+ long chunk_size;
+ long protocol;
+ long hash_strategy;
+ long hash_function;
+ long allow_failover;
+ long max_failover_attempts;
+ long redundancy;
+ long session_redundancy;
+ long compress_threshold;
+ long lock_timeout;
+ZEND_END_MODULE_GLOBALS(memcache)
+
+#ifdef ZTS
+#define MEMCACHE_G(v) TSRMG(memcache_globals_id, zend_memcache_globals *, v)
+#else
+#define MEMCACHE_G(v) (memcache_globals.v)
+#endif
+
+#endif /* MEMCACHE_POOL_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-3.0.5.tgz/memcache-3.0.5/memcache_queue.c
^
|
@@ -0,0 +1,128 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_queue.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "memcache_queue.h"
+
+inline 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++;
+}
+
+inline 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;
+}
+
+inline 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;
+}
+
+inline void mmc_queue_free(mmc_queue_t *queue) {
+ if (queue->items != NULL) {
+ efree(queue->items);
+ }
+ memset(queue, 0, sizeof(*queue));
+}
+
+inline void mmc_queue_copy(mmc_queue_t *target, mmc_queue_t *source) {
+ if (target->alloc != source->alloc) {
+ target->alloc = source->alloc;
+ target->items = 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;
+}
+
+inline 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-3.0.5.tgz/memcache-3.0.5/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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_queue.h 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#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)])
+
+inline void mmc_queue_push(mmc_queue_t *, void *);
+inline void *mmc_queue_pop(mmc_queue_t *);
+inline int mmc_queue_contains(mmc_queue_t *, void *);
+inline void mmc_queue_free(mmc_queue_t *);
+inline void mmc_queue_copy(mmc_queue_t *, mmc_queue_t *);
+inline 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-3.0.5.tgz/memcache-3.0.5/memcache_session.c
^
|
@@ -0,0 +1,516 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_session.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#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/php_smart_str.h"
+#include "ext/standard/url.h"
+#include "php_memcache.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(memcache)
+
+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, udp_port = 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), "udp_port", sizeof("udp_port"), (void **) ¶m) != FAILURE) {
+ convert_to_long_ex(param);
+ udp_port = Z_LVAL_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, 0, timeout, retry_interval TSRMLS_CC);
+ }
+ else {
+ mmc = mmc_server_new(host, host_len, 0, 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, udp_port, timeout, retry_interval TSRMLS_CC);
+ }
+ else {
+ mmc = mmc_server_new(url->host, strlen(url->host), url->port, udp_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;
+}
+/* }}} */
+
+static int php_mmc_session_read_request(
+ mmc_pool_t *pool, zval *zkey, zval **lockparam, zval *addparam, zval **dataparam,
+ mmc_request_t **lockreq, mmc_request_t **addreq, mmc_request_t **datareq TSRMLS_DC) /* {{{ */
+{
+ mmc_request_t *lreq, *areq, *dreq;
+
+ /* increment request which stores the response int using value_handler_single */
+ lreq = mmc_pool_request(
+ pool, MMC_PROTO_TCP, mmc_numeric_response_handler, lockparam[0],
+ mmc_pool_failover_handler_null, NULL TSRMLS_CC);
+ lreq->value_handler = mmc_value_handler_single;
+ lreq->value_handler_param = lockparam;
+
+ /* add request which should fail if lock has been incremented */
+ areq = mmc_pool_request(
+ pool, MMC_PROTO_TCP, mmc_stored_handler, addparam,
+ mmc_pool_failover_handler_null, NULL TSRMLS_CC);
+
+ /* request to fetch the session data */
+ dreq = mmc_pool_request_get(
+ pool, MMC_PROTO_TCP, mmc_value_handler_single, dataparam,
+ mmc_pool_failover_handler_null, NULL TSRMLS_CC);
+
+ /* prepare key */
+ if (mmc_prepare_key_ex(Z_STRVAL_P(zkey), Z_STRLEN_P(zkey), dreq->key, &(dreq->key_len)) != MMC_OK) {
+ mmc_pool_release(pool, lreq);
+ mmc_pool_release(pool, areq);
+ mmc_pool_release(pool, dreq);
+ return MMC_REQUEST_FAILURE;
+ }
+
+ /* append .lock to key */
+ memcpy(lreq->key, dreq->key, dreq->key_len);
+ strcpy(lreq->key + dreq->key_len, ".lock");
+
+ memcpy(areq->key, dreq->key, dreq->key_len);
+ strcpy(areq->key + dreq->key_len, ".lock");
+
+ lreq->key_len = areq->key_len = dreq->key_len + sizeof(".lock")-1;
+
+ /* value for add request */
+ zval lockvalue;
+ ZVAL_LONG(&lockvalue, 1);
+
+ /* build requests */
+ pool->protocol->mutate(lreq, zkey, lreq->key, lreq->key_len, 1, 1, 1, MEMCACHE_G(lock_timeout));
+ pool->protocol->store(pool, areq, MMC_OP_ADD, areq->key, areq->key_len, 0, MEMCACHE_G(lock_timeout), 0, &lockvalue TSRMLS_CC);
+ pool->protocol->get(dreq, MMC_OP_GET, zkey, dreq->key, dreq->key_len);
+
+ *lockreq = lreq;
+ *addreq = areq;
+ *datareq = dreq;
+ return MMC_OK;
+}
+/* }}} */
+
+/* {{{ PS_READ_FUNC
+ */
+PS_READ_FUNC(memcache)
+{
+ mmc_pool_t *pool = PS_GET_MOD_DATA();
+
+ if (pool != NULL) {
+ zval lockresult, addresult, dataresult, zkey;
+ zval *lockparam[3];
+ zval *dataparam[3];
+
+ mmc_t *mmc;
+ mmc_request_t *lockrequest, *addrequest, *datarequest;
+ mmc_queue_t skip_servers = {0};
+ unsigned int last_index = 0, prev_index = 0, timeout = 5000;
+ long remainingtime = MEMCACHE_G(lock_timeout) * 1000000 * 2;
+
+ lockparam[0] = &lockresult;
+ lockparam[1] = NULL;
+ lockparam[2] = NULL;
+
+ dataparam[0] = &dataresult;
+ dataparam[1] = NULL;
+ dataparam[2] = NULL;
+
+ ZVAL_STRING(&zkey, (char *)key, 0);
+
+ do {
+ /* first request tries to increment lock */
+ ZVAL_NULL(&lockresult);
+
+ /* second request tries to add lock, succeeds if lock doesn't exist (not relevant for binary
+ * protocol where increment takes a default value */
+ ZVAL_NULL(&addresult);
+
+ /* third request fetches the data, data is only valid if either of the lock requests succeeded */
+ ZVAL_NULL(&dataresult);
+
+ /* create requests */
+ if (php_mmc_session_read_request(pool, &zkey, lockparam, &addresult, dataparam, &lockrequest, &addrequest, &datarequest TSRMLS_CC) != MMC_OK) {
+ break;
+ }
+
+ /* find next server in line */
+ prev_index = last_index;
+ mmc = mmc_pool_find_next(pool, datarequest->key, datarequest->key_len, &skip_servers, &last_index TSRMLS_CC);
+
+ /* schedule the requests */
+ if (!mmc_server_valid(mmc TSRMLS_CC) ||
+ mmc_pool_schedule(pool, mmc, lockrequest TSRMLS_CC) != MMC_OK ||
+ /*pool->protocol != &mmc_binary_protocol && */mmc_pool_schedule(pool, mmc, addrequest TSRMLS_CC) != MMC_OK ||
+ mmc_pool_schedule(pool, mmc, datarequest TSRMLS_CC) != MMC_OK) {
+ mmc_pool_release(pool, lockrequest);
+ mmc_pool_release(pool, addrequest);
+ mmc_pool_release(pool, datarequest);
+ mmc_queue_push(&skip_servers, mmc);
+ continue;
+ }
+
+ /* execute requests */
+ mmc_pool_run(pool TSRMLS_CC);
+
+ if ((Z_TYPE(lockresult) == IS_LONG && Z_LVAL(lockresult) == 1) || (Z_TYPE(addresult) == IS_BOOL && Z_BVAL(addresult))) {
+ if (Z_TYPE(dataresult) == IS_STRING) {
+ /* break if successfully locked with existing value */
+ mmc_queue_free(&skip_servers);
+ *val = Z_STRVAL(dataresult);
+ *vallen = Z_STRLEN(dataresult);
+ return SUCCESS;
+ }
+
+ /* if missing value, skip this server and try next */
+ zval_dtor(&dataresult);
+ mmc_queue_push(&skip_servers, mmc);
+ }
+ else {
+ /* if missing lock, back off and retry same server */
+ last_index = prev_index;
+ usleep(timeout);
+ remainingtime -= timeout;
+ timeout *= 2;
+
+ /* max value to usleep() is 1 second */
+ if (timeout > 1000000) {
+ timeout = 1000000;
+ }
+ }
+ } while (skip_servers.len < MEMCACHE_G(session_redundancy)-1 && skip_servers.len < pool->num_servers && remainingtime > 0);
+
+ mmc_queue_free(&skip_servers);
+ zval_dtor(&dataresult);
+ }
+
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ PS_WRITE_FUNC
+ */
+PS_WRITE_FUNC(memcache)
+{
+ mmc_pool_t *pool = PS_GET_MOD_DATA();
+
+ if (pool != NULL) {
+ zval lockresult, dataresult, lockvalue, value;
+
+ mmc_t *mmc;
+ mmc_request_t *lockrequest, *datarequest;
+ mmc_queue_t skip_servers = {0};
+ unsigned int last_index = 0;
+
+ ZVAL_NULL(&lockresult);
+ ZVAL_NULL(&dataresult);
+
+ do {
+ /* allocate requests */
+ datarequest = mmc_pool_request(
+ pool, MMC_PROTO_TCP, mmc_stored_handler, &dataresult,
+ mmc_pool_failover_handler_null, NULL TSRMLS_CC);
+
+ if (mmc_prepare_key_ex(key, strlen(key), datarequest->key, &(datarequest->key_len)) != MMC_OK) {
+ mmc_pool_release(pool, datarequest);
+ break;
+ }
+
+ /* append .lock to key */
+ lockrequest = mmc_pool_request(
+ pool, MMC_PROTO_TCP, mmc_stored_handler, &lockresult,
+ mmc_pool_failover_handler_null, NULL TSRMLS_CC);
+
+ memcpy(lockrequest->key, datarequest->key, datarequest->key_len);
+ strcpy(lockrequest->key + datarequest->key_len, ".lock");
+ lockrequest->key_len = datarequest->key_len + sizeof(".lock")-1;
+
+ ZVAL_LONG(&lockvalue, 0);
+ ZVAL_STRINGL(&value, (char *)val, vallen, 0);
+
+ /* assemble commands to store data and reset lock */
+ if (pool->protocol->store(pool, datarequest, MMC_OP_SET, datarequest->key, datarequest->key_len, 0, INI_INT("session.gc_maxlifetime"), 0, &value TSRMLS_CC) != MMC_OK ||
+ pool->protocol->store(pool, lockrequest, MMC_OP_SET, lockrequest->key, lockrequest->key_len, 0, MEMCACHE_G(lock_timeout), 0, &lockvalue TSRMLS_CC) != MMC_OK) {
+ mmc_pool_release(pool, datarequest);
+ mmc_pool_release(pool, lockrequest);
+ break;
+ }
+
+ /* find next server in line */
+ mmc = mmc_pool_find_next(pool, datarequest->key, datarequest->key_len, &skip_servers, &last_index TSRMLS_CC);
+ mmc_queue_push(&skip_servers, mmc);
+
+ if (!mmc_server_valid(mmc TSRMLS_CC) ||
+ mmc_pool_schedule(pool, mmc, datarequest TSRMLS_CC) != MMC_OK ||
+ mmc_pool_schedule(pool, mmc, lockrequest TSRMLS_CC) != MMC_OK) {
+ mmc_pool_release(pool, datarequest);
+ mmc_pool_release(pool, lockrequest);
+ continue;
+ }
+ } while (skip_servers.len < MEMCACHE_G(session_redundancy)-1 && skip_servers.len < pool->num_servers);
+
+ mmc_queue_free(&skip_servers);
+
+ /* execute requests */
+ mmc_pool_run(pool TSRMLS_CC);
+
+ if (Z_BVAL(lockresult) && Z_BVAL(dataresult)) {
+ return SUCCESS;
+ }
+ }
+
+ return FAILURE;
+}
+/* }}} */
+
+static int mmc_deleted_handler(mmc_t *mmc, mmc_request_t *request, int response, const char *message, unsigned int message_len, void *param TSRMLS_DC) /*
+ parses a DELETED response line, param is a zval pointer to store result into {{{ */
+{
+ if (response == MMC_OK || response == MMC_RESPONSE_NOT_FOUND) {
+ ZVAL_TRUE((zval *)param);
+ return MMC_REQUEST_DONE;
+ }
+
+ return mmc_request_failure(mmc, request->io, message, message_len, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ PS_DESTROY_FUNC
+ */
+PS_DESTROY_FUNC(memcache)
+{
+ mmc_pool_t *pool = PS_GET_MOD_DATA();
+
+ if (pool != NULL) {
+ zval lockresult, dataresult;
+
+ mmc_t *mmc;
+ mmc_request_t *lockrequest, *datarequest;
+ mmc_queue_t skip_servers = {0};
+ unsigned int last_index = 0;
+
+ ZVAL_NULL(&lockresult);
+ ZVAL_NULL(&dataresult);
+
+ do {
+ /* allocate requests */
+ datarequest = mmc_pool_request(
+ pool, MMC_PROTO_TCP, mmc_deleted_handler, &dataresult,
+ mmc_pool_failover_handler_null, NULL TSRMLS_CC);
+
+ if (mmc_prepare_key_ex(key, strlen(key), datarequest->key, &(datarequest->key_len)) != MMC_OK) {
+ mmc_pool_release(pool, datarequest);
+ break;
+ }
+
+ /* append .lock to key */
+ lockrequest = mmc_pool_request(
+ pool, MMC_PROTO_TCP, mmc_deleted_handler, &lockresult,
+ mmc_pool_failover_handler_null, NULL TSRMLS_CC);
+
+ memcpy(lockrequest->key, datarequest->key, datarequest->key_len);
+ strcpy(lockrequest->key + datarequest->key_len, ".lock");
+ lockrequest->key_len = datarequest->key_len + sizeof(".lock")-1;
+
+ /* assemble commands to store data and reset lock */
+ pool->protocol->delete(datarequest, datarequest->key, datarequest->key_len, 0);
+ pool->protocol->delete(lockrequest, lockrequest->key, lockrequest->key_len, 0);
+
+ /* find next server in line */
+ mmc = mmc_pool_find_next(pool, datarequest->key, datarequest->key_len, &skip_servers, &last_index TSRMLS_CC);
+ mmc_queue_push(&skip_servers, mmc);
+
+ if (!mmc_server_valid(mmc TSRMLS_CC) ||
+ mmc_pool_schedule(pool, mmc, datarequest TSRMLS_CC) != MMC_OK ||
+ mmc_pool_schedule(pool, mmc, lockrequest TSRMLS_CC) != MMC_OK) {
+ mmc_pool_release(pool, datarequest);
+ mmc_pool_release(pool, lockrequest);
+ continue;
+ }
+ } while (skip_servers.len < MEMCACHE_G(session_redundancy)-1 && skip_servers.len < pool->num_servers);
+
+ mmc_queue_free(&skip_servers);
+
+ /* execute requests */
+ mmc_pool_run(pool TSRMLS_CC);
+
+ if (Z_BVAL(lockresult) && Z_BVAL(dataresult)) {
+ 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-3.0.5.tgz/memcache-3.0.5/memcache_standard_hash.c
^
|
@@ -0,0 +1,104 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: memcache_standard_hash.c 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#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_t *hash;
+} mmc_standard_state_t;
+
+void *mmc_standard_create_state(mmc_hash_function_t *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);
+ }
+}
+/* }}} */
+
+mmc_t *mmc_standard_find_server(void *s, const char *key, unsigned int key_len TSRMLS_DC) /* {{{ */
+{
+ mmc_standard_state_t *state = s;
+
+ if (state->num_servers > 1) {
+ /* "new-style" hash */
+ unsigned int hash = (mmc_hash(state->hash, key, key_len) >> 16) & 0x7fff;
+ return state->buckets[(hash ? hash : 1) % state->num_buckets];
+ }
+
+ return state->buckets[0];
+}
+/* }}} */
+
+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 */
+ state->buckets = erealloc(state->buckets, sizeof(*state->buckets) * (state->num_buckets + weight));
+
+ for (i=0; i<weight; i++) {
+ state->buckets[state->num_buckets + i] = mmc;
+ }
+
+ state->num_buckets += weight;
+ state->num_servers++;
+}
+/* }}} */
+
+mmc_hash_strategy_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-3.0.5.tgz/memcache-3.0.5/php_memcache.h
^
|
@@ -0,0 +1,106 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 <tony2001@phpclub.net> |
+ | Mikael Johansson <mikael AT synd DOT info> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id: php_memcache.h 303968 2010-10-03 21:38:49Z hradtke $ */
+
+#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
+
+#include "memcache_pool.h"
+
+PHP_MINIT_FUNCTION(memcache);
+PHP_MSHUTDOWN_FUNCTION(memcache);
+PHP_MINFO_FUNCTION(memcache);
+
+PHP_NAMED_FUNCTION(zif_memcache_pool_connect);
+PHP_NAMED_FUNCTION(zif_memcache_pool_addserver);
+PHP_NAMED_FUNCTION(zif_memcache_pool_findserver);
+
+PHP_FUNCTION(memcache_connect);
+PHP_FUNCTION(memcache_pconnect);
+PHP_FUNCTION(memcache_add_server);
+PHP_FUNCTION(memcache_set_server_params);
+PHP_FUNCTION(memcache_set_failure_callback);
+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_cas);
+PHP_FUNCTION(memcache_append);
+PHP_FUNCTION(memcache_prepend);
+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);
+
+#define PHP_MEMCACHE_VERSION "3.0.5"
+
+#define MMC_DEFAULT_TIMEOUT 1 /* seconds */
+#define MMC_DEFAULT_RETRY 15 /* retry failed server after x seconds */
+#define MMC_DEFAULT_CACHEDUMP_LIMIT 100 /* number of entries */
+
+#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_find_persistent(const char *, int, unsigned short, unsigned short, double, int TSRMLS_DC);
+int mmc_value_handler_single(const char *, unsigned int, zval *, unsigned int, unsigned long, void * TSRMLS_DC);
+int mmc_value_handler_multi(const char *, unsigned int, zval *, unsigned int, unsigned long, void * TSRMLS_DC);
+int mmc_stored_handler(mmc_t *, mmc_request_t *, int, const char *, unsigned int, void * TSRMLS_DC);
+int mmc_numeric_response_handler(mmc_t *, mmc_request_t *, int, const char *, unsigned int, void * 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
+
+#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-3.0.5.tgz/package.xml
^
|
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.6.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.1" 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>
@@ -11,8 +11,8 @@
<lead>
<name>Antony Dovgal</name>
<user>tony2001</user>
- <email>tony2001@phpclub.net</email>
- <active>yes</active>
+ <email>tony@daylessday.org</email>
+ <active>no</active>
</lead>
<lead>
<name>Mikael Johansson</name>
@@ -20,45 +20,58 @@
<email>mikael@synd.info</email>
<active>yes</active>
</lead>
- <date>2008-02-05</date>
- <time>21:00:12</time>
+ <lead>
+ <name>Pierre-Alain Joye</name>
+ <user>pajoye</user>
+ <email>pierre.php@gmail.com</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Herman Radtke</name>
+ <user>hradtke</user>
+ <email>hradtke@php.net</email>
+ <active>yes</active>
+ </lead>
+ <date>2010-10-03</date>
+ <time>14:41:21</time>
<version>
- <release>3.0.1</release>
- <api>3.0.1</api>
+ <release>3.0.5</release>
+ <api>3.0.5</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://www.php.net/license">PHP License</license>
- <notes>- Fixed PECL bug #12866 (Ignore memcache.default_port in memcache_connect)
-- Fixed PECL bug #12883 (Breaks UTF-8 in keys)
-- Fixed PECL bug #13060 (make problems, due to role="doc" instead of role="src")
-- 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
-- Added package version to phpinfo()</notes>
+ <notes>
+- Fixed PECL bug #16059 (Build error: 'MSG_NOSIGNAL' undeclared)
+- Added method MemcachePool::findServer(key) which returns the server a key hashes to
+- Changed MemcachePool::findServer() to return only "hostname:port" since tcp port is significant
+- Fixed PECL bug #16536 (Weight of 0 causes SegFault on memcache_add_server)
+- Fixed PECL bug #17566 (3.0.4 cache delete bug)
+- Fixed PECL Bug #16442 (memcache_set fail with integer value)
+ </notes>
<contents>
<dir name="/">
- <file md5sum="a35c3d4407a9f946e6ea8f26e75ef72b" name="config.m4" role="src" />
- <file md5sum="62e65f09c4d1ee3d38a2e170ef17e042" name="config9.m4" role="src" />
- <file md5sum="2a642f5397d67994a6c9a6862fd7bd23" name="config.w32" role="src" />
+ <file md5sum="2de287e7774dad44aaa11a7da26e38d0" name="config.m4" role="src" />
+ <file md5sum="5bf1bf855ca8efdb17352736da7e5c17" name="config9.m4" role="src" />
+ <file md5sum="01b1231fa34c0bd88605ebcaa1654d68" name="config.w32" role="src" />
<file md5sum="f818c8af5b84d8c936eca307b63aafec" name="CREDITS" role="doc" />
<file md5sum="5b6b03aebb60f141416489a527b2c9be" name="example.php" role="doc" />
- <file md5sum="dc435e28946f2dc7330042301d401919" name="memcache.c" role="src" />
- <file md5sum="0808afc4b4615b0b0770fee908eb0597" name="memcache_pool.c" role="src" />
- <file md5sum="8a0e0a15854f2b2af3e29401622f448b" name="memcache_queue.c" role="src" />
- <file md5sum="aa718bf4c86febe06f6ebfbbca882336" name="memcache_session.c" role="src" />
- <file md5sum="ceb73d8c2fb7f06d9ca1527c7b1fa0d4" name="memcache_ascii_protocol.c" role="src" />
- <file md5sum="15b23090f62fab91271dca5c08cb010f" name="memcache_binary_protocol.c" role="src" />
- <file md5sum="828a7d59e28e9926c0eb865cb1d252e8" name="memcache_standard_hash.c" role="src" />
- <file md5sum="59280415fd3b8024ab4118a1db1acdc4" name="memcache_consistent_hash.c" role="src" />
+ <file md5sum="b064ff2dc6df9ee8eeb75a2fb5676622" name="memcache.c" role="src" />
+ <file md5sum="c2f4abe0b3d85dbefeb9384ca2f6b010" name="memcache_pool.c" role="src" />
+ <file md5sum="843f0c3791344a6d0afc546c926a2fcf" name="memcache_queue.c" role="src" />
+ <file md5sum="b11e41a96ce2e25c4bb56444476c117e" name="memcache_session.c" role="src" />
+ <file md5sum="2b1a5e228ace204fa9e4cb707a075705" name="memcache_ascii_protocol.c" role="src" />
+ <file md5sum="86ee1ca48017b57b803b3e5e44567987" name="memcache_binary_protocol.c" role="src" />
+ <file md5sum="cb6d2a37b6f4818e7b5fd8814e72415d" name="memcache_standard_hash.c" role="src" />
+ <file md5sum="755184d99ff95ab0d79dc3ef48ccdd86" name="memcache_consistent_hash.c" role="src" />
<file md5sum="a0904f003d7ae14ff22c15fd0c417ceb" name="memcache.dsp" role="src" />
- <file md5sum="be74ef03252c5c09f2fe3bb321886199" name="php_memcache.h" role="src">
- <tasks:replace from="@PACKAGE-VERSION@" to="version" type="package-info" />
- </file>
- <file md5sum="a1001b0fcfe7c7b838c1ab5525628842" name="memcache_pool.h" role="src" />
- <file md5sum="c8a146e0c8e014ec12a3e39c767466ab" name="memcache_queue.h" role="src" />
- <file md5sum="3f098d47c7382ce599eab268cb074d86" name="README" role="doc" />
+ <file md5sum="a6d2231072225be47c47a7fe4cb53387" name="php_memcache.h" role="src" />
+ <file md5sum="f9a3aca8f95d64da5034ac85dabc7366" name="memcache_pool.h" role="src" />
+ <file md5sum="311d824a78554154157f647a87a708b2" name="memcache_queue.h" role="src" />
+ <file md5sum="7900b5759a4d1a89ae40753b0a7bc065" name="README" role="doc" />
+ <file md5sum="f35ec9b92f71391e6b26d0fc5f02aead" name="memcache.php" role="doc" />
</dir>
</contents>
<dependencies>
@@ -77,6 +90,103 @@
</extsrcrelease>
<changelog>
<release>
+ <date>2009-02-22</date>
+ <version>
+ <release>3.0.4</release>
+ <api>3.0.4</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+- Improved performance of consistent hash strategy
+- Accept timeout parameter as float to enable microsecond timeouts, param is still
+ given in seconds but with a microsecond fraction.
+- Added session locking to avoid concurrency problems with AJAX apps
+- Fixed PECL bug #14642 (3.0.x breaks BC with 2.2.x)
+- Fixed PECL request #13758 (Failed to extract 'connection' variable from object)
+- Fixed PECL request #14658 (Allow connection timeouts in ms, not seconds)
+- New INI directive
+ memcache.lock_timeout = 15
+ </notes>
+ </release>
+ <release>
+ <date>2009-01-13</date>
+ <version>
+ <release>3.0.3</release>
+ <api>3.0.3</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+- Enabled compression by default for values larger than 20kb
+- Scalar data types (int, bool, double) are preserved by get/set
+- Reserved the lowest 2 bytes of the flags for internal use
+- Fixed PECL bug #14157 (Segmentation fault with errorcallback handler)
+- Fixed PECL bug #15342 (memcache keys whitespaces replace issue)
+- Fixed PECL bug #15447 (Persistent Connections Cause Segfaults if One Server Drops)
+- Fixed PECL bug #15529 (memcache object loses port information)
+- Fixed PECL bug #14730 (Types lost during get/set)
+- Fixed PECL request #14801 (Session handler and large sessions)
+- Added REPORT_ERRORS to php stream open
+- New INI directive
+ memcache.compress_threshold = 20000
+ </notes>
+ </release>
+ <release>
+ <date>2008-09-11</date>
+ <version>
+ <release>3.0.2</release>
+ <api>3.0.2</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+- Updated binary protocol to be compatible with memcached 1.3.0
+- 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 #13592 (error in opcode)
+- Fixed PECL req #13588 (minor inefficiency in binary protocol implementation)
+- Fixed PECL bug #14044 (send of 32768 bytes failed with errno=11 Resource temporarily unavailable)
+- Fixed PECL bug #14239 (Memcache::set() modifies value parameter)
+- Fixed PECL bug #14156 (No check for parameter count in php_mmc_store)
+- Fixed PECL bug #14458 (off-by-one causes corrupted arrays in 3.0.x)
+- Fixed PECL bug #14104 (Malformed VALUE header (0))
+- 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>
+ </release>
+ <release>
+ <date>2008-02-05</date>
+ <version>
+ <release>3.0.1</release>
+ <api>3.0.1</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+- Fixed PECL bug #12866 (Ignore memcache.default_port in memcache_connect)
+- Fixed PECL bug #12883 (Breaks UTF-8 in keys)
+- Fixed PECL bug #13060 (make problems, due to role="doc" instead of role="src")
+- 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
+- Added package version to phpinfo()
+ </notes>
+ </release>
+ <release>
<date>2007-11-26</date>
<version>
<release>3.0.0</release>
@@ -87,7 +197,8 @@
<api>alpha</api>
</stability>
<license uri="http://www.php.net/license">PHP License</license>
- <notes>See README for details on new API and INI directives.
+ <notes>
+See README for details on new API and INI directives.
- UDP support
- Binary protocol support
@@ -104,7 +215,8 @@
memcache.session_redundancy = 2
- Changed INI defaults
memcache.hash_strategy = consistent
- memcache.chunk_size = 32768</notes>
+ memcache.chunk_size = 32768
+ </notes>
</release>
<release>
<date>2008-02-05</date>
@@ -117,9 +229,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>
@@ -132,10 +246,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>
@@ -148,10 +264,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>
@@ -164,7 +282,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}
@@ -172,7 +291,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>
@@ -185,7 +305,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>
@@ -198,9 +320,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>
@@ -213,13 +337,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>
@@ -232,8 +358,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>
@@ -246,8 +374,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>
@@ -260,11 +390,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>
@@ -277,11 +409,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>
@@ -294,9 +428,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>
@@ -309,8 +445,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>
@@ -323,8 +461,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>
@@ -337,8 +477,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>
@@ -351,8 +493,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>
@@ -365,10 +509,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>
@@ -381,8 +527,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>
@@ -395,9 +543,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>
@@ -410,9 +560,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>
@@ -425,8 +577,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>
@@ -439,7 +593,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>
|