@@ -19,7 +19,6 @@
/* TODO
* - set LIBKETAMA_COMPATIBLE as the default?
* - fix unserialize(serialize($memc))
- * - ability to set binary protocol for sessions
*/
#include "php_memcached.h"
@@ -27,6 +26,9 @@
#include "php_memcached_server.h"
#include "g_fmt.h"
+#include <ctype.h>
+#include <limits.h>
+
#ifdef HAVE_MEMCACHED_SESSION
# include "php_memcached_session.h"
#endif
@@ -49,14 +51,18 @@
# include "ext/msgpack/php_msgpack.h"
#endif
-/*
- * This is needed because PHP 5.3.[01] does not install JSON_parser.h by default. This
- * constant will move into php_json.h in the future anyway.
- */
-#ifndef JSON_PARSER_DEFAULT_DEPTH
-#define JSON_PARSER_DEFAULT_DEPTH 512
+#ifdef ZTS
+#define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, memc.v)
+#else
+#define MEMC_G(v) (php_memcached_globals.memc.v)
#endif
+static int le_memc;
+
+static int php_memc_list_entry(void) {
+ return le_memc;
+}
+
/****************************************
Protocol parameters
****************************************/
@@ -70,6 +76,7 @@
#define MEMC_OPT_SERIALIZER -1003
#define MEMC_OPT_COMPRESSION_TYPE -1004
#define MEMC_OPT_STORE_RETRY_COUNT -1005
+#define MEMC_OPT_USER_FLAGS -1006
/****************************************
Custom result codes
@@ -116,96 +123,114 @@
/****************************************
"get" operation flags
****************************************/
-#define MEMC_GET_PRESERVE_ORDER (1<<0)
-
+#define MEMC_GET_PRESERVE_ORDER 1
+#define MEMC_GET_EXTENDED 2
/****************************************
Helper macros
****************************************/
-#define MEMC_METHOD_INIT_VARS \
- zval* object = getThis(); \
- php_memc_t* i_obj = NULL; \
- struct memc_obj* m_obj = NULL;
-
-#define MEMC_METHOD_FETCH_OBJECT \
- i_obj = (php_memc_t *) zend_object_store_get_object( object TSRMLS_CC ); \
- m_obj = i_obj->obj; \
- if (!m_obj) { \
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memcached constructor was not called"); \
- return; \
- }
-
-#ifndef DVAL_TO_LVAL
-#ifdef _WIN64
-# define DVAL_TO_LVAL(d, l) \
- if ((d) > LONG_MAX) { \
- (l) = (long)(unsigned long)(__int64) (d); \
- } else { \
- (l) = (long) (d); \
- }
-#else
-# define DVAL_TO_LVAL(d, l) \
- if ((d) > LONG_MAX) { \
- (l) = (unsigned long) (d); \
- } else { \
- (l) = (long) (d); \
- }
-#endif
-#endif
-
#define RETURN_FROM_GET RETURN_FALSE
-#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 3)
-#define zend_parse_parameters_none() \
- zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
-#endif
-
-
/****************************************
Structures and definitions
****************************************/
-enum memcached_compression_type {
- COMPRESSION_TYPE_ZLIB = 1,
- COMPRESSION_TYPE_FASTLZ = 2,
-};
+
+typedef enum {
+ MEMC_OP_SET,
+ MEMC_OP_TOUCH,
+ MEMC_OP_ADD,
+ MEMC_OP_REPLACE,
+ MEMC_OP_APPEND,
+ MEMC_OP_PREPEND
+} php_memc_write_op;
typedef struct {
- zend_object zo;
- struct memc_obj {
- memcached_st *memc;
- zend_bool compression;
- enum memcached_serializer serializer;
- enum memcached_compression_type compression_type;
-#if HAVE_MEMCACHED_SASL
- zend_bool has_sasl_data;
+ zend_bool is_persistent;
+ zend_bool compression_enabled;
+
+ zend_long serializer;
+ zend_long compression_type;
+
+ zend_long store_retry_count;
+ zend_long set_udf_flags;
+
+#ifdef HAVE_MEMCACHED_SASL
+ zend_bool has_sasl_data;
#endif
- long store_retry_count;
- } *obj;
+} php_memc_user_data_t;
- zend_bool is_persistent;
+typedef struct {
+ memcached_st *memc;
zend_bool is_pristine;
int rescode;
int memc_errno;
-} php_memc_t;
+ zend_object zo;
+} php_memc_object_t;
+
+typedef struct {
+ size_t num_valid_keys;
+
+ const char **mkeys;
+ size_t *mkeys_len;
+
+ zend_string **strings;
+
+} php_memc_keys_t;
+
+typedef struct {
+ zval *object;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+} php_memc_result_callback_ctx_t;
+
+static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) {
+ return (php_memc_object_t *)((char *)obj - XtOffsetOf(php_memc_object_t, zo));
+}
+#define Z_MEMC_OBJ_P(zv) php_memc_fetch_object(Z_OBJ_P(zv));
+
+#define MEMC_METHOD_INIT_VARS \
+ zval* object = getThis(); \
+ php_memc_object_t* intern = NULL; \
+ php_memc_user_data_t* memc_user_data = NULL;
+
+#define MEMC_METHOD_FETCH_OBJECT \
+ intern = Z_MEMC_OBJ_P(object); \
+ if (!intern->memc) { \
+ php_error_docref(NULL, E_WARNING, "Memcached constructor was not called"); \
+ return; \
+ } \
+ memc_user_data = (php_memc_user_data_t *) memcached_get_user_data(intern->memc);
+
+#define MEMC_CHECK_KEY(intern, key) \
+ if (UNEXPECTED(ZSTR_LEN(key) == 0 || \
+ ZSTR_LEN(key) > MEMC_OBJECT_KEY_MAX_LENGTH || \
+ (memcached_behavior_get(intern->memc, \
+ MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) ? \
+ strchr(ZSTR_VAL(key), '\n') : \
+ strchr(ZSTR_VAL(key), ' ')))) { \
+ intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; \
+ RETURN_FALSE; \
+ }
#ifdef HAVE_MEMCACHED_PROTOCOL
typedef struct {
- zend_object zo;
php_memc_proto_handler_t *handler;
+ zend_object zo;
} php_memc_server_t;
-#endif
+static inline php_memc_server_t *php_memc_server_fetch_object(zend_object *obj) {
+ return (php_memc_server_t *)((char *)obj - XtOffsetOf(php_memc_server_t, zo));
+}
+#define Z_MEMC_SERVER_P(zv) php_memc_server_fetch_object(Z_OBJ_P(zv))
-enum {
- MEMC_OP_SET,
- MEMC_OP_TOUCH,
- MEMC_OP_ADD,
- MEMC_OP_REPLACE,
- MEMC_OP_APPEND,
- MEMC_OP_PREPEND
-};
+#ifdef ZTS
+#define MEMC_SERVER_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, server.v)
+#else
+#define MEMC_SERVER_G(v) (php_memcached_globals.server.v)
+#endif
+#endif
static zend_class_entry *memcached_ce = NULL;
@@ -218,27 +243,10 @@
static zend_class_entry *memcached_server_ce = NULL;
#endif
-struct callbackContext
-{
- zval *array;
- zval *entry;
- memcached_stat_st *stats; /* for use with functions that need stats */
- void *return_value;
- unsigned int i; /* for use with structures mapped against servers */
-};
-
-#if HAVE_SPL
+#ifdef HAVE_SPL
static zend_class_entry *spl_ce_RuntimeException = NULL;
#endif
-#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3)
-const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0 };
-#undef ZEND_BEGIN_ARG_INFO_EX
-#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
- static zend_arg_info name[] = { \
- { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
-#endif
-
ZEND_DECLARE_MODULE_GLOBALS(php_memcached)
#ifdef COMPILE_DL_MEMCACHED
@@ -248,82 +256,126 @@
static PHP_INI_MH(OnUpdateCompressionType)
{
if (!new_value) {
- MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ;
- } else if (!strcmp(new_value, "fastlz")) {
- MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ;
- } else if (!strcmp(new_value, "zlib")) {
- MEMC_G(compression_type_real) = COMPRESSION_TYPE_ZLIB;
+ MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ;
+ } else if (!strcmp(ZSTR_VAL(new_value), "fastlz")) {
+ MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ;
+ } else if (!strcmp(ZSTR_VAL(new_value), "zlib")) {
+ MEMC_G(compression_type) = COMPRESSION_TYPE_ZLIB;
} else {
return FAILURE;
}
- return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+ return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
}
static PHP_INI_MH(OnUpdateSerializer)
{
if (!new_value) {
- MEMC_G(serializer) = SERIALIZER_DEFAULT;
- } else if (!strcmp(new_value, "php")) {
- MEMC_G(serializer) = SERIALIZER_PHP;
+ MEMC_G(serializer_type) = SERIALIZER_DEFAULT;
+ } else if (!strcmp(ZSTR_VAL(new_value), "php")) {
+ MEMC_G(serializer_type) = SERIALIZER_PHP;
#ifdef HAVE_MEMCACHED_IGBINARY
- } else if (!strcmp(new_value, "igbinary")) {
- MEMC_G(serializer) = SERIALIZER_IGBINARY;
+ } else if (!strcmp(ZSTR_VAL(new_value), "igbinary")) {
+ MEMC_G(serializer_type) = SERIALIZER_IGBINARY;
#endif // IGBINARY
#ifdef HAVE_JSON_API
- } else if (!strcmp(new_value, "json")) {
- MEMC_G(serializer) = SERIALIZER_JSON;
- } else if (!strcmp(new_value, "json_array")) {
- MEMC_G(serializer) = SERIALIZER_JSON_ARRAY;
+ } else if (!strcmp(ZSTR_VAL(new_value), "json")) {
+ MEMC_G(serializer_type) = SERIALIZER_JSON;
+ } else if (!strcmp(ZSTR_VAL(new_value), "json_array")) {
+ MEMC_G(serializer_type) = SERIALIZER_JSON_ARRAY;
#endif // JSON
#ifdef HAVE_MEMCACHED_MSGPACK
- } else if (!strcmp(new_value, "msgpack")) {
- MEMC_G(serializer) = SERIALIZER_MSGPACK;
+ } else if (!strcmp(ZSTR_VAL(new_value), "msgpack")) {
+ MEMC_G(serializer_type) = SERIALIZER_MSGPACK;
#endif // msgpack
} else {
return FAILURE;
}
- return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+ return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
+}
+
+static
+PHP_INI_MH(OnUpdateDeprecatedLockValue)
+{
+ if (ZSTR_LEN(new_value) > 0 && strcmp(ZSTR_VAL(new_value), "not set")) {
+ php_error_docref(NULL, E_DEPRECATED, "memcached.sess_lock_wait and memcached.sess_lock_max_wait are deprecated. Please update your configuration to use memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries");
+ }
+ return FAILURE;
+}
+
+static
+PHP_INI_MH(OnUpdateSessionPrefixString)
+{
+ if (new_value && ZSTR_LEN(new_value) > 0) {
+ char *ptr = ZSTR_VAL(new_value);
+
+ while (*ptr != '\0') {
+ if (isspace (*ptr++)) {
+ php_error_docref(NULL, E_WARNING, "memcached.sess_prefix cannot contain whitespace characters");
+ return FAILURE;
+ }
+ }
+ if (ZSTR_LEN(new_value) > MEMCACHED_MAX_KEY) {
+ php_error_docref(NULL, E_WARNING, "memcached.sess_prefix too long (max: %d)", MEMCACHED_MAX_KEY - 1);
+ return FAILURE;
+ }
+ }
+ return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
}
+#define MEMC_INI_ENTRY(key, default_value, update_fn, gkey) \
+ STD_PHP_INI_ENTRY("memcached."key, default_value, PHP_INI_ALL, update_fn, memc.gkey, zend_php_memcached_globals, php_memcached_globals)
+
+#define MEMC_SESSION_INI_ENTRY(key, default_value, update_fn, gkey) \
+ STD_PHP_INI_ENTRY("memcached.sess_"key, default_value, PHP_INI_ALL, update_fn, session.gkey, zend_php_memcached_globals, php_memcached_globals)
+
+
/* {{{ INI entries */
PHP_INI_BEGIN()
+
#ifdef HAVE_MEMCACHED_SESSION
- STD_PHP_INI_ENTRY("memcached.sess_locking", "1", PHP_INI_ALL, OnUpdateBool, sess_locking_enabled, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_consistent_hash", "0", PHP_INI_ALL, OnUpdateBool, sess_consistent_hash_enabled, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_binary", "0", PHP_INI_ALL, OnUpdateBool, sess_binary_enabled, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_lock_wait", "150000", PHP_INI_ALL, OnUpdateLongGEZero,sess_lock_wait, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_lock_max_wait", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_lock_max_wait, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_lock_expire", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_lock_expire, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_prefix", "memc.sess.key.", PHP_INI_ALL, OnUpdateString, sess_prefix, zend_php_memcached_globals, php_memcached_globals)
-
- STD_PHP_INI_ENTRY("memcached.sess_number_of_replicas", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_number_of_replicas, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_randomize_replica_read", "0", PHP_INI_ALL, OnUpdateBool, sess_randomize_replica_read, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_remove_failed", "0", PHP_INI_ALL, OnUpdateBool, sess_remove_failed_enabled, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_connect_timeout", "1000", PHP_INI_ALL, OnUpdateLong, sess_connect_timeout, zend_php_memcached_globals, php_memcached_globals)
-#if HAVE_MEMCACHED_SASL
- STD_PHP_INI_ENTRY("memcached.sess_sasl_username", "", PHP_INI_ALL, OnUpdateString, sess_sasl_username, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.sess_sasl_password", "", PHP_INI_ALL, OnUpdateString, sess_sasl_password, zend_php_memcached_globals, php_memcached_globals)
-#endif
-#endif
- STD_PHP_INI_ENTRY("memcached.compression_type", "fastlz", PHP_INI_ALL, OnUpdateCompressionType, compression_type, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.compression_factor", "1.3", PHP_INI_ALL, OnUpdateReal, compression_factor, zend_php_memcached_globals, php_memcached_globals)
- STD_PHP_INI_ENTRY("memcached.compression_threshold", "2000", PHP_INI_ALL, OnUpdateLong, compression_threshold, zend_php_memcached_globals, php_memcached_globals)
-
- STD_PHP_INI_ENTRY("memcached.serializer", SERIALIZER_DEFAULT_NAME, PHP_INI_ALL, OnUpdateSerializer, serializer_name, zend_php_memcached_globals, php_memcached_globals)
-#if HAVE_MEMCACHED_SASL
- STD_PHP_INI_ENTRY("memcached.use_sasl", "0", PHP_INI_SYSTEM, OnUpdateBool, use_sasl, zend_php_memcached_globals, php_memcached_globals)
-#endif
- STD_PHP_INI_ENTRY("memcached.store_retry_count", "2", PHP_INI_ALL, OnUpdateLong, store_retry_count, zend_php_memcached_globals, php_memcached_globals)
+ MEMC_SESSION_INI_ENTRY("locking", "1", OnUpdateBool, lock_enabled)
+ MEMC_SESSION_INI_ENTRY("lock_wait_min", "1000", OnUpdateLongGEZero, lock_wait_min)
+ MEMC_SESSION_INI_ENTRY("lock_wait_max", "2000", OnUpdateLongGEZero, lock_wait_max)
+ MEMC_SESSION_INI_ENTRY("lock_retries", "5", OnUpdateLong, lock_retries)
+ MEMC_SESSION_INI_ENTRY("lock_expire", "0", OnUpdateLongGEZero, lock_expiration)
+ MEMC_SESSION_INI_ENTRY("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled)
+ MEMC_SESSION_INI_ENTRY("consistent_hash", "1", OnUpdateBool, consistent_hash_enabled)
+ MEMC_SESSION_INI_ENTRY("number_of_replicas", "0", OnUpdateLongGEZero, number_of_replicas)
+ MEMC_SESSION_INI_ENTRY("randomize_replica_read", "0", OnUpdateLongGEZero, randomize_replica_read_enabled)
+ MEMC_SESSION_INI_ENTRY("remove_failed_servers", "0", OnUpdateBool, remove_failed_servers_enabled)
+ MEMC_SESSION_INI_ENTRY("server_failure_limit", "0", OnUpdateLongGEZero, server_failure_limit)
+ MEMC_SESSION_INI_ENTRY("connect_timeout", "0", OnUpdateLongGEZero, connect_timeout)
+ MEMC_SESSION_INI_ENTRY("sasl_username", "", OnUpdateString, sasl_username)
+ MEMC_SESSION_INI_ENTRY("sasl_password", "", OnUpdateString, sasl_password)
+ MEMC_SESSION_INI_ENTRY("prefix", "memc.sess.", OnUpdateSessionPrefixString, prefix)
+ MEMC_SESSION_INI_ENTRY("persistent", "0", OnUpdateBool, persistent_enabled)
+
+ /* Deprecated */
+ STD_PHP_INI_ENTRY("memcached.sess_lock_wait", "not set", PHP_INI_ALL, OnUpdateDeprecatedLockValue, no_effect, zend_php_memcached_globals, php_memcached_globals)
+ STD_PHP_INI_ENTRY("memcached.sess_lock_max_wait", "not set", PHP_INI_ALL, OnUpdateDeprecatedLockValue, no_effect, zend_php_memcached_globals, php_memcached_globals)
+
+#endif
+
+ MEMC_INI_ENTRY("compression_type", "fastlz", OnUpdateCompressionType, compression_name)
+ MEMC_INI_ENTRY("compression_factor", "1.3", OnUpdateReal, compression_factor)
+ MEMC_INI_ENTRY("compression_threshold", "2000", OnUpdateLong, compression_threshold)
+ MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name)
+ MEMC_INI_ENTRY("store_retry_count", "2", OnUpdateLong, store_retry_count)
+
+ MEMC_INI_ENTRY("default_consistent_hash", "0", OnUpdateBool, default_behavior.consistent_hash_enabled)
+ MEMC_INI_ENTRY("default_binary_protocol", "0", OnUpdateBool, default_behavior.binary_protocol_enabled)
+ MEMC_INI_ENTRY("default_connect_timeout", "0", OnUpdateLongGEZero, default_behavior.connect_timeout)
+
PHP_INI_END()
/* }}} */
+#undef MEMC_INI_ENTRY
+#undef MEMC_SESSION_INI_ENTRY
+
/****************************************
Forward declarations
****************************************/
-static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status TSRMLS_DC);
-static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type TSRMLS_DC);
-static int php_memc_zval_from_payload(zval *value, const char *payload, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC);
static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key);
@@ -331,563 +383,1180 @@
static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
-static memcached_return php_memc_do_cache_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char *key, size_t key_len, zval *value TSRMLS_DC);
-static int php_memc_do_result_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result TSRMLS_DC);
-static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
-static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
-static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
-static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS_DC);
+
+/* Invoke PHP functions */
+static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_bool with_cas, zend_string *key, zval *value);
+
+/* Iterate result sets */
+typedef zend_bool (*php_memc_result_apply_fn)(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *context);
+
+static
+memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, zend_bool fetch_delay, void *context);
+
+static
+zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key,
+ php_memc_keys_t *keys, php_memc_result_apply_fn result_apply_fn,
+ zend_bool with_cas, void *context);
+
+
+/* Callback functions for different server list iterations */
+static
+ memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
+
+static
+ memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
+
+static
+ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, zend_string *server_key, zend_string *key, zval *value, time_t expiration);
+
+static
+ void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data);
+
+static
+ zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *result, zval *return_value);
+
+static
+ zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t *flags);
+
+static
+ void s_hash_to_keys(php_memc_keys_t *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value);
+
+static
+ void s_clear_keys(php_memc_keys_t *keys);
+
/****************************************
- Method implementations
+ Exported helper functions
****************************************/
+zend_bool php_memc_init_sasl_if_needed()
+{
+#ifdef HAVE_MEMCACHED_SASL
+ if (MEMC_G(sasl_initialised)) {
+ return 1;
+ }
+ if (sasl_client_init(NULL) != SASL_OK) {
+ php_error_docref(NULL, E_ERROR, "Failed to initialize SASL library");
+ return 0;
+ }
+ return 1;
+#else
+ php_error_docref(NULL, E_ERROR, "Memcached not built with sasl support");
+ return 0;
+#endif
+}
-char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC)
+char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
{
char *buffer = NULL;
- if (fci->object_ptr) {
- spprintf (&buffer, 0, "%s::%s", Z_OBJCE_P (fci->object_ptr)->name, fci_cache->function_handler->common.function_name);
+ if (fci->object) {
+ spprintf (&buffer, 0, "%s::%s", ZSTR_VAL(fci->object->ce->name), fci_cache->function_handler->common.function_name);
} else {
- if (Z_TYPE_P (fci->function_name) == IS_OBJECT) {
- spprintf (&buffer, 0, "%s", Z_OBJCE_P (fci->function_name)->name);
+ if (Z_TYPE (fci->function_name) == IS_OBJECT) {
+ spprintf (&buffer, 0, "%s", ZSTR_VAL(Z_OBJCE(fci->function_name)->name));
}
else {
- spprintf (&buffer, 0, "%s", Z_STRVAL_P (fci->function_name));
+ spprintf (&buffer, 0, "%s", Z_STRVAL(fci->function_name));
}
}
return buffer;
}
-static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, char *persistent_id, int persistent_id_len TSRMLS_DC)
-{
- zend_bool retval = 1;
- zval pid_z;
- zval *retval_ptr, *pid_z_ptr = &pid_z;
- zval **params[2];
- INIT_ZVAL(pid_z);
- if (persistent_id) {
- ZVAL_STRINGL(pid_z_ptr, persistent_id, persistent_id_len, 1);
- }
+/****************************************
+ Handling error codes
+****************************************/
+
+static
+zend_bool s_memcached_return_is_error(memcached_return status, zend_bool strict)
+{
+ zend_bool result = 0;
- /* Call the cb */
- params[0] = &object;
- params[1] = &pid_z_ptr;
+ switch (status) {
+ case MEMCACHED_SUCCESS:
+ case MEMCACHED_STORED:
+ case MEMCACHED_DELETED:
+ case MEMCACHED_STAT:
+ case MEMCACHED_END:
+ case MEMCACHED_BUFFERED:
+ result = 0;
+ break;
- fci->params = params;
- fci->param_count = 2;
- fci->retval_ptr_ptr = &retval_ptr;
- fci->no_separation = 1;
+ case MEMCACHED_SOME_ERRORS:
+ result = strict;
+ break;
- if (zend_call_function(fci, fci_cache TSRMLS_CC) == FAILURE) {
- char *buf = php_memc_printable_func (fci, fci_cache TSRMLS_CC);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to invoke 'on_new' callback %s()", buf);
- efree (buf);
- retval = 0;
+ default:
+ result = 1;
+ break;
}
- zval_dtor(pid_z_ptr);
+ return result;
+}
+
+static
+int s_memc_status_handle_result_code(php_memc_object_t *intern, memcached_return status)
+{
+ intern->rescode = status;
+ intern->memc_errno = 0;
- if (retval_ptr) {
- zval_ptr_dtor(&retval_ptr);
+ if (s_memcached_return_is_error(status, 1)) {
+ intern->memc_errno = memcached_last_error_errno(intern->memc);
+ return FAILURE;
}
- return retval;
+ return SUCCESS;
}
-static int le_memc, le_memc_sess;
-
-static int php_memc_list_entry(void)
+static
+void s_memc_set_status(php_memc_object_t *intern, memcached_return status, int memc_errno)
{
- return le_memc;
+ intern->rescode = status;
+ intern->memc_errno = memc_errno;
}
-/* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]]))
- Creates a Memcached object, optionally using persistent memcache connection */
-static PHP_METHOD(Memcached, __construct)
+static
+zend_bool s_memc_status_has_error(php_memc_object_t *intern)
{
- zval *object = getThis();
- php_memc_t *i_obj;
- struct memc_obj *m_obj = NULL;
- char *persistent_id = NULL, *conn_str = NULL;
- int persistent_id_len, conn_str_len;
- zend_bool is_persistent = 0;
+ return s_memcached_return_is_error(intern->rescode, 1);
+}
- char *plist_key = NULL;
- int plist_key_len = 0;
+static
+zend_bool s_memc_status_has_result_code(php_memc_object_t *intern, memcached_return status)
+{
+ return intern->rescode == status;
+}
- zend_fcall_info fci = {0};
- zend_fcall_info_cache fci_cache;
+/****************************************
+ Marshall cas tokens
+****************************************/
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!f!s", &persistent_id, &persistent_id_len, &fci, &fci_cache, &conn_str, &conn_str_len) == FAILURE) {
- ZVAL_NULL(object);
- return;
+static
+void s_uint64_to_zval (zval *target, uint64_t value)
+{
+ if (value >= ((uint64_t) LONG_MAX)) {
+ zend_string *buffer;
+#ifdef PRIu64
+ buffer = strpprintf (0, "%" PRIu64, value);
+#else
+ /* Best effort */
+ buffer = strpprintf (0, "%llu", value);
+#endif
+ ZVAL_STR(target, buffer);
}
+ else {
+ ZVAL_LONG (target, (zend_long) value);
+ }
+}
- i_obj = (php_memc_t *) zend_object_store_get_object(object TSRMLS_CC);
- i_obj->is_pristine = 0;
+static
+uint64_t s_zval_to_uint64 (zval *cas)
+{
+ switch (Z_TYPE_P (cas)) {
+ case IS_LONG:
+ return (uint64_t) zval_get_long (cas);
+ break;
- if (persistent_id && *persistent_id) {
- zend_rsrc_list_entry *le = NULL;
+ case IS_DOUBLE:
+ if (Z_DVAL_P (cas) < 0.0)
+ return 0;
- is_persistent = 1;
- plist_key_len = spprintf(&plist_key, 0, "memcached:id=%s", persistent_id);
- plist_key_len += 1;
+ return (uint64_t) zval_get_double (cas);
+ break;
- if (zend_hash_find(&EG(persistent_list), plist_key, plist_key_len, (void *)&le) == SUCCESS) {
- if (le->type == php_memc_list_entry()) {
- m_obj = (struct memc_obj *) le->ptr;
- }
- }
- i_obj->obj = m_obj;
- }
+ case IS_STRING:
+ {
+ uint64_t val;
+ char *end;
- i_obj->is_persistent = is_persistent;
+ errno = 0;
+ val = (uint64_t) strtoull (Z_STRVAL_P (cas), &end, 0);
- if (!m_obj) {
- m_obj = pecalloc(1, sizeof(*m_obj), is_persistent);
- if (m_obj == NULL) {
- if (plist_key) {
- efree(plist_key);
+ if (*end || (errno == ERANGE && val == UINT64_MAX) || (errno != 0 && val == 0)) {
+ php_error_docref(NULL, E_ERROR, "Failed to unmarshall cas token");
+ return 0;
}
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory: cannot allocate handle");
- /* not reached */
+ return val;
}
+ break;
+ }
+ return 0;
+}
- if (conn_str) {
- m_obj->memc = php_memc_create_str(conn_str, conn_str_len);
- if (!m_obj->memc) {
- char error_buffer[1024];
- if (plist_key) {
- efree(plist_key);
- }
-#ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION
- if (libmemcached_check_configuration(conn_str, conn_str_len, error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "configuration error %s", error_buffer);
- } else {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure");
- }
-#else
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure");
-#endif
- /* not reached */
- }
- } else {
- m_obj->memc = memcached_create(NULL);
- if (m_obj->memc == NULL) {
- if (plist_key) {
- efree(plist_key);
- }
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure");
- /* not reached */
- }
- }
- m_obj->serializer = MEMC_G(serializer);
- m_obj->compression_type = MEMC_G(compression_type_real);
- m_obj->compression = 1;
- m_obj->store_retry_count = MEMC_G(store_retry_count);
+/****************************************
+ Iterate over memcached results and mget
+****************************************/
- i_obj->obj = m_obj;
- i_obj->is_pristine = 1;
+static
+memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, zend_bool fetch_delay, void *context)
+{
+ memcached_result_st result, *result_ptr;
+ memcached_return rc, status = MEMCACHED_SUCCESS;
- if (fci.size) { /* will be 0 when not available */
- if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id, persistent_id_len TSRMLS_CC) || EG(exception)) {
- /* error calling or exception thrown from callback */
- if (plist_key) {
- efree(plist_key);
- }
+ memcached_result_create(intern->memc, &result);
- i_obj->obj = NULL;
- if (is_persistent) {
- php_memc_destroy(m_obj, is_persistent TSRMLS_CC);
- }
+ do {
+ result_ptr = memcached_fetch_result(intern->memc, &result, &rc);
- return;
- }
+ if (s_memcached_return_is_error(rc, 0)) {
+ status = rc;
}
- if (is_persistent) {
- zend_rsrc_list_entry le;
+ /* nothing returned */
+ if (!result_ptr) {
+ break;
+ }
+ else {
+ zend_string *key;
+ zval val, zcas;
+ zend_bool retval;
+
+ uint64_t cas;
+ uint32_t flags;
+
+ const char *res_key;
+ size_t res_key_len;
+
+ if (!s_memcached_result_to_zval(intern->memc, &result, &val)) {
+ if (EG(exception)) {
+ status = MEMC_RES_PAYLOAD_FAILURE;
+ memcached_quit(intern->memc);
+ break;
+ }
+ status = MEMCACHED_SOME_ERRORS;
+ continue;
+ }
- le.type = php_memc_list_entry();
- le.ptr = m_obj;
- if (zend_hash_update(&EG(persistent_list), (char *)plist_key,
- plist_key_len, (void *)&le, sizeof(le), NULL) == FAILURE) {
- if (plist_key) {
- efree(plist_key);
+ res_key = memcached_result_key_value(&result);
+ res_key_len = memcached_result_key_length(&result);
+ cas = memcached_result_cas(&result);
+ flags = memcached_result_flags(&result);
+
+ s_uint64_to_zval(&zcas, cas);
+
+ key = zend_string_init (res_key, res_key_len, 0);
+ retval = result_apply_fn(intern, key, &val, &zcas, flags, context);
+
+ zend_string_release(key);
+ zval_ptr_dtor(&val);
+ zval_ptr_dtor(&zcas);
+
+ /* Stop iterating on false */
+ if (!retval) {
+ if (!fetch_delay) {
+ /* Make sure we clear our results */
+ while (memcached_fetch_result(intern->memc, &result, &rc)) {}
}
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not register persistent entry");
- /* not reached */
+ break;
}
}
- }
+ } while (result_ptr != NULL);
- if (plist_key) {
- efree(plist_key);
- }
+ memcached_result_free(&result);
+ return status;
}
-/* }}} */
-/* {{{ Memcached::get(string key [, mixed callback [, double &cas_token [, int &udf_flags ] ] ])
- Returns a value for the given key or false */
-PHP_METHOD(Memcached, get)
+static
+zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key, php_memc_keys_t *keys,
+ php_memc_result_apply_fn result_apply_fn, zend_bool with_cas, void *context)
{
- php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
-}
-/* }}} */
+ memcached_return status;
+ int mget_status;
+ uint64_t orig_cas_flag = 0;
-/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, double &cas_token [, int &udf_flags ] ] ])
- Returns a value for key from the server identified by the server key or false */
-PHP_METHOD(Memcached, getByKey)
-{
- php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
-}
-/* }}} */
+ // Reset status code
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
-/* {{{ -- php_memc_get_impl */
-static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
-{
- char *key = NULL;
- int key_len = 0;
- char *server_key = NULL;
- int server_key_len = 0;
- const char *payload = NULL;
- size_t payload_len = 0;
- uint32_t flags = 0;
- uint64_t cas = 0;
- const char* keys[1] = { NULL };
- size_t key_lens[1] = { 0 };
- zval *cas_token = NULL;
- zval *udf_flags = NULL;
- zend_fcall_info fci = empty_fcall_info;
- zend_fcall_info_cache fcc = empty_fcall_info_cache;
- memcached_result_st result;
- memcached_return status = MEMCACHED_SUCCESS;
- MEMC_METHOD_INIT_VARS;
+ if (!keys->num_valid_keys) {
+ intern->rescode = MEMCACHED_BAD_KEY_PROVIDED;
+ return 0;
+ }
- if (by_key) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|f!zz", &server_key,
- &server_key_len, &key, &key_len, &fci, &fcc, &cas_token, &udf_flags) == FAILURE) {
- return;
+ if (with_cas) {
+ orig_cas_flag = memcached_behavior_get (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS);
+
+ if (!orig_cas_flag) {
+ memcached_behavior_set (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
}
+ }
+
+ if (server_key) {
+ status = memcached_mget_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), keys->mkeys, keys->mkeys_len, keys->num_valid_keys);
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f!zz", &key, &key_len,
- &fci, &fcc, &cas_token, &udf_flags) == FAILURE) {
- return;
- }
+ status = memcached_mget(intern->memc, keys->mkeys, keys->mkeys_len, keys->num_valid_keys);
}
- MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ /* Need to handle result code before restoring cas flags, would mess up errno */
+ mget_status = s_memc_status_handle_result_code(intern, status);
+
+ if (with_cas && !orig_cas_flag) {
+ memcached_behavior_set (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
+ }
- if (key_len == 0 || key_len > MEMC_OBJECT_KEY_MAX_LENGTH || strchr(key, ' ') || strchr(key, '\n')) {
- i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
- RETURN_FROM_GET;
+ /* Return on failure codes */
+ if (mget_status == FAILURE) {
+ return 0;
}
- keys[0] = key;
- key_lens[0] = key_len;
+ if (!result_apply_fn) {
+ /* no callback, for example getDelayed */
+ return 1;
+ }
- uint64_t orig_cas_flag;
- orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS);
+ status = php_memc_result_apply(intern, result_apply_fn, 0, context);
- /*
- * Enable CAS support, but only if it is currently disabled.
- */
- if (cas_token && PZVAL_IS_REF(cas_token) && orig_cas_flag == 0) {
- memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/****************************************
+ Invoke callbacks
+****************************************/
+
+static
+zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id)
+{
+ zend_bool ret = 1;
+ zval retval;
+ zval params[2];
+
+ ZVAL_COPY(¶ms[0], object);
+ if (persistent_id) {
+ ZVAL_STR(¶ms[1], zend_string_copy(persistent_id));
+ } else {
+ ZVAL_NULL(¶ms[1]);
}
- status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, keys, key_lens, 1);
+ fci->retval = &retval;
+ fci->params = params;
+ fci->param_count = 2;
- if (cas_token && PZVAL_IS_REF(cas_token) && orig_cas_flag == 0) {
- memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
+ if (zend_call_function(fci, fci_cache) == FAILURE) {
+ char *buf = php_memc_printable_func (fci, fci_cache);
+ php_error_docref(NULL, E_WARNING, "Failed to invoke 'on_new' callback %s()", buf);
+ efree (buf);
+ ret = 0;
}
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- RETURN_FROM_GET;
+ zval_ptr_dtor(¶ms[0]);
+ zval_ptr_dtor(¶ms[1]);
+ zval_ptr_dtor(&retval);
+
+ return ret;
+}
+
+static
+zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_bool with_cas, zend_string *key, zval *value)
+{
+ zend_bool status = 0;
+ zval params[4];
+ zval retval;
+ php_memc_object_t *intern = Z_MEMC_OBJ_P(zobject);
+
+ /* Prepare params */
+ ZVAL_COPY(¶ms[0], zobject);
+ ZVAL_STR_COPY(¶ms[1], key); /* key */
+ ZVAL_NEW_REF(¶ms[2], value); /* value */
+
+ if (with_cas) {
+ fci->param_count = 3;
+ } else {
+ ZVAL_NEW_EMPTY_REF(¶ms[3]); /* expiration */
+ ZVAL_NULL(Z_REFVAL(params[3]));
+ fci->param_count = 4;
+ }
+
+ fci->retval = &retval;
+ fci->params = params;
+
+ if (zend_call_function(fci, fcc) == SUCCESS) {
+ if (zend_is_true(&retval)) {
+ time_t expiration;
+ zval *val = Z_REFVAL(params[2]);
+
+ if (with_cas) {
+ if (Z_TYPE_P(val) == IS_ARRAY) {
+ zval *rv = zend_hash_str_find(Z_ARRVAL_P(val), "value", sizeof("value") - 1);
+ if (rv) {
+ zval *cas = zend_hash_str_find(Z_ARRVAL_P(val), "cas", sizeof("cas") -1);
+ expiration = cas? Z_LVAL_P(cas) : 0;
+ status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, rv, expiration);
+ }
+ /* memleak? zval_ptr_dtor(value); */
+ ZVAL_COPY(value, val);
+ }
+ } else {
+ expiration = zval_get_long(Z_REFVAL(params[3]));
+ status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, val, expiration);
+ /* memleak? zval_ptr_dtor(value); */
+ ZVAL_COPY(value, val);
+ }
+ }
+ }
+ else {
+ s_memc_set_status(intern, MEMCACHED_NOTFOUND, 0);
+ }
+
+ zval_ptr_dtor(¶ms[0]);
+ zval_ptr_dtor(¶ms[1]);
+ zval_ptr_dtor(¶ms[2]);
+ if (!with_cas) {
+ zval_ptr_dtor(¶ms[3]);
+ }
+ zval_ptr_dtor(&retval);
+
+ return status;
+}
+
+/****************************************
+ Wrapper for setting from zval
+****************************************/
+
+static
+zend_bool s_compress_value (php_memc_compression_type compression_type, zend_string **payload_in, uint32_t *flags)
+{
+ /* status */
+ zend_bool compress_status = 0;
+ zend_string *payload = *payload_in;
+
+ /* Additional 5% for the data */
+ size_t buffer_size = (size_t) (((double) ZSTR_LEN(payload) * 1.05) + 1.0);
+ char *buffer = emalloc(buffer_size);
+
+ /* Store compressed size here */
+ size_t compressed_size = 0;
+ uint32_t original_size = ZSTR_LEN(payload);
+
+ switch (compression_type) {
+
+ case COMPRESSION_TYPE_FASTLZ:
+ {
+ compressed_size = fastlz_compress(ZSTR_VAL(payload), ZSTR_LEN(payload), buffer);
+
+ if (compressed_size > 0) {
+ compress_status = 1;
+ MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_FASTLZ);
+ }
+ }
+ break;
+
+ case COMPRESSION_TYPE_ZLIB:
+ {
+ compressed_size = buffer_size;
+ int status = compress((Bytef *) buffer, &compressed_size, (Bytef *) ZSTR_VAL(payload), ZSTR_LEN(payload));
+
+ if (status == Z_OK) {
+ compress_status = 1;
+ MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_ZLIB);
+ }
+ }
+ break;
+
+ default:
+ compress_status = 0;
+ break;
+ }
+
+ if (!compress_status) {
+ php_error_docref(NULL, E_WARNING, "could not compress value");
+ efree (buffer);
+ return 0;
}
- status = MEMCACHED_SUCCESS;
- memcached_result_create(m_obj->memc, &result);
+ /* This means the value was too small to be compressed, still a success */
+ if (compressed_size > (ZSTR_LEN(payload) * MEMC_G(compression_factor))) {
+ efree (buffer);
+ return 1;
+ }
+
+ MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSED);
+
+ payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0);
+
+ /* Copy the uin32_t at the beginning */
+ memcpy(ZSTR_VAL(payload), &original_size, sizeof(uint32_t));
+ memcpy(ZSTR_VAL(payload) + sizeof (uint32_t), buffer, compressed_size);
+ efree(buffer);
+
+ zend_string_forget_hash_val(payload);
+ *payload_in = payload;
+ return 1;
+}
- if (memcached_fetch_result(m_obj->memc, &result, &status) == NULL) {
- /* This is for historical reasons */
- if (status == MEMCACHED_END)
- status = MEMCACHED_NOTFOUND;
+static
+zend_bool s_serialize_value (php_memc_serializer_type serializer, zval *value, smart_str *buf, uint32_t *flags)
+{
+ switch (serializer) {
/*
- * If the result wasn't found, and we have the read-through callback, invoke
- * it to get the value. The CAS token will be 0, because we cannot generate it
- * ourselves.
- */
- if (cas_token) {
- ZVAL_DOUBLE(cas_token, 0.0);
+ Igbinary serialization
+ */
+#ifdef HAVE_MEMCACHED_IGBINARY
+ case SERIALIZER_IGBINARY:
+ {
+ uint8_t *buffer;
+ size_t buffer_len;
+
+ if (igbinary_serialize(&buffer, &buffer_len, value) != 0) {
+ php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary");
+ return 0;
+ }
+ smart_str_appendl (buf, buffer, buffer_len);
+ efree(buffer);
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY);
}
+ break;
+#endif
- if (status == MEMCACHED_NOTFOUND && fci.size != 0) {
- status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, key_len, return_value TSRMLS_CC);
+ /*
+ JSON serialization
+ */
+#ifdef HAVE_JSON_API
+ case SERIALIZER_JSON:
+ case SERIALIZER_JSON_ARRAY:
+ {
+ php_json_encode(buf, value, 0);
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON);
}
+ break;
+#endif
+
+ /*
+ msgpack serialization
+ */
+#ifdef HAVE_MEMCACHED_MSGPACK
+ case SERIALIZER_MSGPACK:
+ php_msgpack_serialize(buf, value);
+ if (!buf->s) {
+ php_error_docref(NULL, E_WARNING, "could not serialize value with msgpack");
+ return 0;
+ }
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_MSGPACK);
+ break;
+#endif
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- memcached_result_free(&result);
- RETURN_FROM_GET;
+ /*
+ PHP serialization
+ */
+ default:
+ {
+ php_serialize_data_t var_hash;
+ PHP_VAR_SERIALIZE_INIT(var_hash);
+ php_var_serialize(buf, value, &var_hash);
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+
+ if (!buf->s) {
+ php_error_docref(NULL, E_WARNING, "could not serialize value");
+ return 0;
+ }
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED);
}
+ break;
+ }
- /* if we have a callback, all processing is done */
- if (fci.size != 0) {
- memcached_result_free(&result);
- return;
+ /* Check for exceptions caused by serializers */
+ if (EG(exception) && buf->s->len) {
+ return 0;
+ }
+ return 1;
+}
+
+static
+zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t *flags)
+{
+ zend_string *payload;
+ php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc);
+ zend_bool should_compress = memc_user_data->compression_enabled;
+
+ switch (Z_TYPE_P(value)) {
+
+ case IS_STRING:
+ payload = zval_get_string(value);
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING);
+ break;
+
+ case IS_LONG:
+ {
+ smart_str buffer = {0};
+ smart_str_append_long (&buffer, Z_LVAL_P(value));
+ smart_str_0(&buffer);
+ payload = buffer.s;
+
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG);
+ should_compress = 0;
+ }
+ break;
+
+ case IS_DOUBLE:
+ {
+ char buffer[40];
+ php_memcached_g_fmt(buffer, Z_DVAL_P(value));
+ payload = zend_string_init (buffer, strlen (buffer), 0);
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE);
+ should_compress = 0;
}
+ break;
+
+ case IS_TRUE:
+ payload = zend_string_init ("1", 1, 0);
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL);
+ should_compress = 0;
+ break;
+
+ case IS_FALSE:
+ payload = zend_string_alloc (0, 0);
+ MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL);
+ should_compress = 0;
+ break;
+
+ default:
+ {
+ smart_str buffer = {0};
+
+ if (!s_serialize_value (memc_user_data->serializer, value, &buffer, flags)) {
+ smart_str_free(&buffer);
+ return NULL;
+ }
+ payload = buffer.s;
+ }
+ break;
}
+ zend_string_forget_hash_val(payload);
- /* Fetch all remaining results */
- memcached_result_st dummy_result;
- memcached_return dummy_status = MEMCACHED_SUCCESS;
- memcached_result_create(m_obj->memc, &dummy_result);
- while (memcached_fetch_result(m_obj->memc, &dummy_result, &dummy_status) != NULL) {}
- memcached_result_free(&dummy_result);
-
- payload = memcached_result_value(&result);
- payload_len = memcached_result_length(&result);
- flags = memcached_result_flags(&result);
- if (cas_token) {
- cas = memcached_result_cas(&result);
- }
-
- if (php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
- memcached_result_free(&result);
- i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
- RETURN_FROM_GET;
+ /* turn off compression for values below the threshold */
+ if (ZSTR_LEN(payload) == 0 || ZSTR_LEN(payload) < MEMC_G(compression_threshold)) {
+ should_compress = 0;
}
- if (cas_token) {
- zval_dtor(cas_token);
- ZVAL_DOUBLE(cas_token, (double)cas);
+ /* If we have compression flag, compress the value */
+ if (should_compress) {
+ /* status */
+ if (!s_compress_value (memc_user_data->compression_type, &payload, flags)) {
+ zend_string_release(payload);
+ return NULL;
+ }
}
- if (udf_flags) {
- zval_dtor(udf_flags);
- ZVAL_LONG(udf_flags, MEMC_VAL_GET_USER_FLAGS(flags));
+ if (memc_user_data->set_udf_flags >= 0) {
+ MEMC_VAL_SET_USER_FLAGS(*flags, ((uint32_t) memc_user_data->set_udf_flags));
}
- memcached_result_free(&result);
+ return payload;
}
-/* }}} */
-/* {{{ Memcached::getMulti(array keys [, array &cas_tokens [, array &udf_flags ] ])
- Returns values for the given keys or false */
-PHP_METHOD(Memcached, getMulti)
+static
+zend_bool s_should_retry_write (php_memc_object_t *intern, memcached_return status)
{
- php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+ if (memcached_server_count (intern->memc) == 0) {
+ return 0;
+ }
+
+ return s_memcached_return_is_error (status, 1);
}
-/* }}} */
-/* {{{ Memcached::getMultiByKey(string server_key, array keys [, array &cas_tokens [, array &udf_flags ] ])
- Returns values for the given keys from the server identified by the server key or false */
-PHP_METHOD(Memcached, getMultiByKey)
+static
+zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, zend_string *server_key, zend_string *key, zval *value, time_t expiration)
{
- php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+ uint32_t flags = 0;
+ zend_string *payload = NULL;
+ memcached_return status;
+ php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc);
+ zend_long retries = memc_user_data->store_retry_count;
+
+ if (value) {
+ payload = s_zval_to_payload(intern, value, &flags);
+
+ if (!payload) {
+ s_memc_set_status(intern, MEMC_RES_PAYLOAD_FAILURE, 0);
+ return 0;
+ }
+ }
+
+#define memc_write_using_fn(fn_name) payload ? fn_name(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags) : MEMC_RES_PAYLOAD_FAILURE;
+#define memc_write_using_fn_by_key(fn_name) payload ? fn_name(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags) : MEMC_RES_PAYLOAD_FAILURE;
+
+ if (server_key) {
+ switch (op) {
+ case MEMC_OP_SET:
+ status = memc_write_using_fn_by_key(memcached_set_by_key);
+ break;
+
+ case MEMC_OP_TOUCH:
+ status = memcached_touch_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), expiration);
+ break;
+
+ case MEMC_OP_ADD:
+ status = memc_write_using_fn_by_key(memcached_add_by_key);
+ break;
+
+ case MEMC_OP_REPLACE:
+ status = memc_write_using_fn_by_key(memcached_replace_by_key);
+ break;
+
+ case MEMC_OP_APPEND:
+ status = memc_write_using_fn_by_key(memcached_append_by_key);
+ break;
+
+ case MEMC_OP_PREPEND:
+ status = memc_write_using_fn_by_key(memcached_prepend_by_key);
+ break;
+ }
+
+ if (status == MEMCACHED_END) {
+ status = MEMCACHED_SUCCESS;
+ }
+ }
+ else {
+retry:
+ switch (op) {
+ case MEMC_OP_SET:
+ status = memc_write_using_fn(memcached_set);
+ break;
+
+ case MEMC_OP_TOUCH:
+ status = memcached_touch(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration);
+ break;
+
+ case MEMC_OP_ADD:
+ status = memc_write_using_fn(memcached_add);
+ break;
+
+ case MEMC_OP_REPLACE:
+ status = memc_write_using_fn(memcached_replace);
+ break;
+
+ case MEMC_OP_APPEND:
+ status = memc_write_using_fn(memcached_append);
+ break;
+
+ case MEMC_OP_PREPEND:
+ status = memc_write_using_fn(memcached_prepend);
+ break;
+ }
+ if (status == MEMCACHED_END) {
+ status = MEMCACHED_SUCCESS;
+ }
+ }
+
+ if (s_should_retry_write (intern, status) && retries-- > 0) {
+ goto retry;
+ }
+
+#undef memc_write_using_fn
+#undef memc_write_using_fn_by_key
+
+ if (payload) {
+ zend_string_release(payload);
+ }
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
+ return 0;
+ }
+ return 1;
+}
+
+
+/****************************************
+ Methods
+****************************************/
+
+
+/* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]]))
+ Creates a Memcached object, optionally using persistent memcache connection */
+static PHP_METHOD(Memcached, __construct)
+{
+ php_memc_object_t *intern;
+ php_memc_user_data_t *memc_user_data;
+
+ zend_string *persistent_id = NULL;
+ zend_string *conn_str = NULL;
+ zend_string *plist_key = NULL;
+ zend_fcall_info fci = {0};
+ zend_fcall_info_cache fci_cache;
+
+ zend_bool is_persistent = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) {
+ return;
+ }
+
+ intern = Z_MEMC_OBJ_P(getThis());
+ intern->is_pristine = 1;
+
+ if (persistent_id && persistent_id->len) {
+ zend_resource *le;
+
+ plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0);
+ snprintf(ZSTR_VAL(plist_key), plist_key->len + 1, "memcached:id=%s", ZSTR_VAL(persistent_id));
+
+ if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) {
+ if (le->type == php_memc_list_entry()) {
+ intern->memc = le->ptr;
+ intern->is_pristine = 0;
+ zend_string_release (plist_key);
+ return;
+ }
+ }
+ is_persistent = 1;
+ }
+
+ if (conn_str && conn_str->len > 0) {
+ intern->memc = memcached (ZSTR_VAL(conn_str), ZSTR_LEN(conn_str));
+ }
+ else {
+ intern->memc = memcached (NULL, 0);
+ }
+
+ if (!intern->memc) {
+ php_error_docref(NULL, E_ERROR, "Failed to allocate memory for memcached structure");
+ /* never reached */
+ }
+
+ memc_user_data = pecalloc (1, sizeof(*memc_user_data), is_persistent);
+ memc_user_data->serializer = MEMC_G(serializer_type);
+ memc_user_data->compression_type = MEMC_G(compression_type);
+ memc_user_data->compression_enabled = 1;
+ memc_user_data->store_retry_count = MEMC_G(store_retry_count);
+ memc_user_data->set_udf_flags = -1;
+ memc_user_data->is_persistent = is_persistent;
+
+ memcached_set_user_data(intern->memc, memc_user_data);
+
+ /* Set default behaviors */
+ {
+#ifdef mikko_0
+ fprintf (stderr, "consistent_hash_enabled=%d binary_protocol_enabled=%d connect_timeout=%ld\n",
+ MEMC_G(default_behavior.consistent_hash_enabled), MEMC_G(default_behavior.binary_protocol_enabled), MEMC_G(default_behavior.connect_timeout));
+#endif
+
+ memcached_return rc;
+
+ if (MEMC_G(default_behavior.consistent_hash_enabled)) {
+
+ rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, MEMCACHED_DISTRIBUTION_CONSISTENT);
+ if (rc != MEMCACHED_SUCCESS) {
+ php_error_docref(NULL, E_WARNING, "Failed to turn on consistent hash: %s", memcached_strerror(intern->memc, rc));
+ }
+ }
+
+ if (MEMC_G(default_behavior.binary_protocol_enabled)) {
+ rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
+ if (rc != MEMCACHED_SUCCESS) {
+ php_error_docref(NULL, E_WARNING, "Failed to turn on binary protocol: %s", memcached_strerror(intern->memc, rc));
+ }
+ }
+
+ if (MEMC_G(default_behavior.connect_timeout)) {
+ rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, MEMC_G(default_behavior.connect_timeout));
+ if (rc != MEMCACHED_SUCCESS) {
+ php_error_docref(NULL, E_WARNING, "Failed to set connect timeout: %s", memcached_strerror(intern->memc, rc));
+ }
+ }
+ }
+
+ if (fci.size) {
+ if (!s_invoke_new_instance_cb(getThis(), &fci, &fci_cache, persistent_id) || EG(exception)) {
+ /* error calling or exception thrown from callback */
+ if (plist_key) {
+ zend_string_release(plist_key);
+ }
+ /*
+ Setting intern->memc null prevents object destruction from freeing the memcached_st
+ We free it manually here because it might be persistent and has not been
+ registered to persistent_list yet
+ */
+ php_memc_destroy(intern->memc, memc_user_data);
+ intern->memc = NULL;
+ return;
+ }
+ }
+
+ if (plist_key) {
+ zend_resource le;
+
+ le.type = php_memc_list_entry();
+ le.ptr = intern->memc;
+
+ GC_REFCOUNT(&le) = 1;
+
+ /* plist_key is not a persistent allocated key, thus we use str_update here */
+ if (zend_hash_str_update_mem(&EG(persistent_list), ZSTR_VAL(plist_key), ZSTR_LEN(plist_key), &le, sizeof(le)) == NULL) {
+ zend_string_release(plist_key);
+ php_error_docref(NULL, E_ERROR, "could not register persistent entry");
+ /* not reached */
+ }
+ zend_string_release(plist_key);
+ }
}
/* }}} */
-/* {{{ -- php_memc_getMulti_impl */
-static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
+
+
+static
+void s_hash_to_keys(php_memc_keys_t *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value)
{
- zval *keys = NULL;
- char *server_key = NULL;
- int server_key_len = 0;
- size_t num_keys = 0;
- zval **entry = NULL;
- const char *payload = NULL;
- size_t payload_len = 0;
- const char **mkeys = NULL;
- size_t *mkeys_len = NULL;
- const char *tmp_key = NULL;
- size_t res_key_len = 0;
- uint32_t flags;
- uint64_t cas = 0;
- zval *cas_tokens = NULL;
- zval *udf_flags = NULL;
- uint64_t orig_cas_flag = 0;
- zval *value;
- long get_flags = 0;
- int i = 0;
- zend_bool preserve_order;
- memcached_result_st result;
+ size_t idx = 0, alloc_count;
+ zval *zv;
+
+ keys_out->num_valid_keys = 0;
+
+ alloc_count = zend_hash_num_elements(hash_in);
+ if (!alloc_count) {
+ return;
+ }
+ keys_out->mkeys = ecalloc (alloc_count, sizeof (char *));
+ keys_out->mkeys_len = ecalloc (alloc_count, sizeof (size_t));
+ keys_out->strings = ecalloc (alloc_count, sizeof (zend_string *));
+
+ ZEND_HASH_FOREACH_VAL(hash_in, zv) {
+ zend_string *key = zval_get_string(zv);
+
+ if (preserve_order && return_value) {
+ add_assoc_null_ex(return_value, ZSTR_VAL(key), ZSTR_LEN(key));
+ }
+
+ if (ZSTR_LEN(key) > 0 && ZSTR_LEN(key) < MEMCACHED_MAX_KEY) {
+ keys_out->mkeys[idx] = ZSTR_VAL(key);
+ keys_out->mkeys_len[idx] = ZSTR_LEN(key);
+
+ keys_out->strings[idx] = key;
+ idx++;
+ }
+ else {
+ zend_string_release (key);
+ }
+
+ } ZEND_HASH_FOREACH_END();
+
+ if (!idx) {
+ efree (keys_out->mkeys);
+ efree (keys_out->mkeys_len);
+ efree (keys_out->strings);
+ }
+ keys_out->num_valid_keys = idx;
+}
+
+static
+void s_key_to_keys(php_memc_keys_t *keys_out, zend_string *key)
+{
+ zval zv_keys;
+
+ array_init(&zv_keys);
+ add_next_index_str(&zv_keys, zend_string_copy(key));
+
+ s_hash_to_keys(keys_out, Z_ARRVAL(zv_keys), 0, NULL);
+ zval_ptr_dtor(&zv_keys);
+}
+
+static
+void s_clear_keys(php_memc_keys_t *keys)
+{
+ size_t i;
+
+ if (!keys->num_valid_keys) {
+ return;
+ }
+
+ for (i = 0; i < keys->num_valid_keys; i++) {
+ zend_string_release (keys->strings[i]);
+ }
+ efree(keys->strings);
+ efree(keys->mkeys);
+ efree(keys->mkeys_len);
+}
+
+typedef struct {
+ zend_bool extended;
+ zval *return_value;
+} php_memc_get_ctx_t;
+
+static
+zend_bool s_get_apply_fn(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context)
+{
+ php_memc_get_ctx_t *context = (php_memc_get_ctx_t *) in_context;
+
+ if (context->extended) {
+ Z_TRY_ADDREF_P(value);
+ Z_TRY_ADDREF_P(cas);
+
+ array_init (context->return_value);
+ add_assoc_zval (context->return_value, "value", value);
+ add_assoc_zval (context->return_value, "cas", cas);
+ add_assoc_long (context->return_value, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags));
+ }
+ else {
+ ZVAL_COPY(context->return_value, value);
+ }
+ return 0; /* Stop after one */
+}
+
+static
+void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
+{
+ php_memc_get_ctx_t context = {};
+ php_memc_keys_t keys = {0};
+ zend_long get_flags = 0;
+ zend_string *key;
+ zend_string *server_key = NULL;
+ zend_bool mget_status;
memcached_return status = MEMCACHED_SUCCESS;
+ zend_fcall_info fci = empty_fcall_info;
+ zend_fcall_info_cache fcc = empty_fcall_info_cache;
MEMC_METHOD_INIT_VARS;
if (by_key) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|zlz", &server_key,
- &server_key_len, &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!l", &server_key, &key, &fci, &fcc, &get_flags) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|zlz", &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!l", &key, &fci, &fcc, &get_flags) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
+ MEMC_CHECK_KEY(intern, key);
- preserve_order = (get_flags & MEMC_GET_PRESERVE_ORDER);
- num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys));
- mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0);
- mkeys_len = safe_emalloc(num_keys, sizeof(*mkeys_len), 0);
- array_init(return_value);
+ context.extended = (get_flags & MEMC_GET_EXTENDED);
- /*
- * Create the array of keys for libmemcached. If none of the keys were valid
- * (strings), set bad key result code and return.
- */
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(keys));
- zend_hash_get_current_data(Z_ARRVAL_P(keys), (void**)&entry) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(keys))) {
+ context.return_value = return_value;
- if (Z_TYPE_PP(entry) != IS_STRING) {
- convert_to_string_ex(entry);
- }
+ s_key_to_keys(&keys, key);
+ mget_status = php_memc_mget_apply(intern, server_key, &keys, s_get_apply_fn, context.extended, &context);
+ s_clear_keys(&keys);
- if (Z_TYPE_PP(entry) == IS_STRING && Z_STRLEN_PP(entry) > 0) {
- mkeys[i] = Z_STRVAL_PP(entry);
- mkeys_len[i] = Z_STRLEN_PP(entry);
+ if (!mget_status) {
+ if (s_memc_status_has_result_code(intern, MEMCACHED_NOTFOUND) && fci.size > 0) {
+ status = s_invoke_cache_callback(object, &fci, &fcc, context.extended, key, return_value);
- if (preserve_order) {
- add_assoc_null_ex(return_value, mkeys[i], mkeys_len[i] + 1);
+ if (!status) {
+ zval_ptr_dtor(return_value);
+ RETURN_FROM_GET;
}
- i++;
}
}
- if (i == 0) {
- i_obj->rescode = MEMCACHED_NOTFOUND;
- efree(mkeys);
- efree(mkeys_len);
- return;
+ if (s_memc_status_has_error(intern)) {
+ zval_ptr_dtor(return_value);
+ RETURN_FROM_GET;
}
+}
- /*
- * Enable CAS support, but only if it is currently disabled.
- */
- if (cas_tokens && PZVAL_IS_REF(cas_tokens)) {
- orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS);
- if (orig_cas_flag == 0) {
- memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
- }
- }
+/* {{{ Memcached::get(string key [, mixed callback [, int get_flags = 0])
+ Returns a value for the given key or false */
+PHP_METHOD(Memcached, get)
+{
+ php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+/* }}} */
- status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, mkeys, mkeys_len, i);
- /* Handle error, but ignore, there might still be some result */
- php_memc_handle_error(i_obj, status TSRMLS_CC);
+/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, int get_flags = 0])
+ Returns a value for key from the server identified by the server key or false */
+PHP_METHOD(Memcached, getByKey)
+{
+ php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+}
+/* }}} */
- /*
- * Restore the CAS support flag, but only if we had to turn it on.
- */
- if (cas_tokens && PZVAL_IS_REF(cas_tokens) && orig_cas_flag == 0) {
- memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
+static
+zend_bool s_get_multi_apply_fn(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context)
+{
+ php_memc_get_ctx_t *context = (php_memc_get_ctx_t *) in_context;
+
+ Z_TRY_ADDREF_P(value);
+
+ if (context->extended) {
+ zval node;
+
+ Z_TRY_ADDREF_P(cas);
+
+ array_init(&node);
+ add_assoc_zval(&node, "value", value);
+ add_assoc_zval(&node, "cas", cas);
+ add_assoc_long(&node, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags));
+
+ zend_symtable_update(Z_ARRVAL_P(context->return_value), key, &node);
}
+ else {
+ zend_symtable_update(Z_ARRVAL_P(context->return_value), key, value);
+ }
+ return 1;
+}
+
+/* {{{ -- php_memc_getMulti_impl */
+static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
+{
+ php_memc_get_ctx_t context;
+ php_memc_keys_t keys_out;
- efree(mkeys);
- efree(mkeys_len);
+ zval *keys = NULL;
+ zend_string *server_key = NULL;
+ zend_long flags = 0;
+ MEMC_METHOD_INIT_VARS;
+ zend_bool retval, preserve_order;
- /*
- * Iterate through the result set and create the result array. The CAS tokens are
- * returned as doubles, because we cannot store potential 64-bit values in longs.
- */
- if (cas_tokens) {
- if (PZVAL_IS_REF(cas_tokens)) {
- /* cas_tokens was passed by reference, we'll create an array for it. */
- zval_dtor(cas_tokens);
- array_init(cas_tokens);
- } else {
- /* Not passed by reference, we allow this (eg.: if you specify null
- to not enable cas but you want to use the udf_flags parameter).
- We destruct it and set it to null for the peace of mind. */
- zval_dtor(cas_tokens);
- cas_tokens = NULL;
+ if (by_key) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|l", &server_key,
+ &keys, &flags) == FAILURE) {
+ return;
+ }
+ } else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &keys, &flags) == FAILURE) {
+ return;
}
}
- /*
- * Iterate through the result set and create the result array. The flags are
- * returned as longs.
- */
- if (udf_flags) {
- zval_dtor(udf_flags);
- array_init(udf_flags);
- }
-
- memcached_result_create(m_obj->memc, &result);
- while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) {
- char res_key [MEMCACHED_MAX_KEY];
-
- if (status != MEMCACHED_SUCCESS) {
- status = MEMCACHED_SOME_ERRORS;
- php_memc_handle_error(i_obj, status TSRMLS_CC);
- continue;
- }
+ MEMC_METHOD_FETCH_OBJECT;
- payload = memcached_result_value(&result);
- payload_len = memcached_result_length(&result);
- flags = memcached_result_flags(&result);
- tmp_key = memcached_result_key_value(&result);
- res_key_len = memcached_result_key_length(&result);
+ array_init(return_value);
+ if (zend_hash_num_elements(Z_ARRVAL_P(keys)) == 0) {
+ /* BC compatible */
+ s_memc_set_status(intern, MEMCACHED_NOTFOUND, 0);
+ return;
+ }
- /*
- * This may be a bug in libmemcached, the key is not null terminated
- * whe using the binary protocol.
- */
- memcpy (res_key, tmp_key, res_key_len >= MEMCACHED_MAX_KEY ? MEMCACHED_MAX_KEY - 1 : res_key_len);
- res_key [res_key_len] = '\0';
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
- ALLOC_INIT_ZVAL(value);
+ preserve_order = (flags & MEMC_GET_PRESERVE_ORDER);
+ s_hash_to_keys(&keys_out, Z_ARRVAL_P(keys), preserve_order, return_value);
- if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
- zval_ptr_dtor(&value);
- if (EG(exception)) {
- status = MEMC_RES_PAYLOAD_FAILURE;
- php_memc_handle_error(i_obj, status TSRMLS_CC);
- memcached_quit(m_obj->memc);
+ context.extended = (flags & MEMC_GET_EXTENDED);
+ context.return_value = return_value;
- break;
- }
- status = MEMCACHED_SOME_ERRORS;
- i_obj->rescode = MEMCACHED_SOME_ERRORS;
+ retval = php_memc_mget_apply(intern, server_key, &keys_out, s_get_multi_apply_fn, context.extended, &context);
- continue;
- }
+ s_clear_keys(&keys_out);
- add_assoc_zval_ex(return_value, res_key, res_key_len+1, value);
- if (cas_tokens) {
- cas = memcached_result_cas(&result);
- add_assoc_double_ex(cas_tokens, res_key, res_key_len+1, (double)cas);
- }
- if (udf_flags) {
- add_assoc_long_ex(udf_flags, res_key, res_key_len+1, MEMC_VAL_GET_USER_FLAGS(flags));
- }
+ if (!retval && (s_memc_status_has_result_code(intern, MEMCACHED_NOTFOUND) || s_memc_status_has_result_code(intern, MEMCACHED_SOME_ERRORS))) {
+ return;
}
- memcached_result_free(&result);
-
- if (EG(exception)) {
- /* XXX: cas_tokens should only be set on success, currently we're destructive */
- if (cas_tokens) {
- zval_dtor(cas_tokens);
- ZVAL_NULL(cas_tokens);
- }
- if (udf_flags) {
- zval_dtor(udf_flags);
- ZVAL_NULL(udf_flags);
- }
+ if (!retval || EG(exception)) {
zval_dtor(return_value);
- RETURN_FALSE;
+ RETURN_FROM_GET;
}
}
/* }}} */
+/* {{{ Memcached::getMulti(array keys[, long flags = 0 ])
+ Returns values for the given keys or false */
+PHP_METHOD(Memcached, getMulti)
+{
+ php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+/* }}} */
+
+/* {{{ Memcached::getMultiByKey(string server_key, array keys[, long flags = 0 ])
+ Returns values for the given keys from the server identified by the server key or false */
+PHP_METHOD(Memcached, getMultiByKey)
+{
+ php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+}
+/* }}} */
+
/* {{{ Memcached::getDelayed(array keys [, bool with_cas [, mixed callback ] ])
Sends a request for the given keys and returns immediately */
PHP_METHOD(Memcached, getDelayed)
@@ -904,140 +1573,113 @@
}
/* }}} */
+
+static
+void s_create_result_array(zend_string *key, zval *value, zval *cas, uint32_t flags, zval *return_value)
+{
+ Z_TRY_ADDREF_P(value);
+ Z_TRY_ADDREF_P(cas);
+
+ add_assoc_str_ex(return_value, ZEND_STRL("key"), zend_string_copy(key));
+ add_assoc_zval_ex(return_value, ZEND_STRL("value"), value);
+
+ if (Z_LVAL_P(cas)) {
+ /* BC compatible */
+ add_assoc_zval_ex(return_value, ZEND_STRL("cas"), cas);
+ add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags));
+ }
+}
+
+static
+zend_bool s_result_callback_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context)
+{
+ zend_bool status = 1;
+ zval params[2];
+ zval retval;
+ php_memc_result_callback_ctx_t *context = (php_memc_result_callback_ctx_t *) in_context;
+
+ ZVAL_COPY(¶ms[0], context->object);
+ array_init(¶ms[1]);
+
+ s_create_result_array(key, value, cas, flags, ¶ms[1]);
+
+ context->fci.retval = &retval;
+ context->fci.params = params;
+ context->fci.param_count = 2;
+
+ if (zend_call_function(&context->fci, &context->fcc) == FAILURE) {
+ php_error_docref(NULL, E_WARNING, "could not invoke result callback");
+ status = 0;
+ }
+
+ zval_ptr_dtor(&retval);
+
+ zval_ptr_dtor(¶ms[0]);
+ zval_ptr_dtor(¶ms[1]);
+
+ return status;
+}
+
/* {{{ -- php_memc_getDelayed_impl */
static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
+ php_memc_keys_t keys_out = {0};
+
zval *keys = NULL;
- char *server_key = NULL;
- int server_key_len = 0;
+ zend_string *server_key = NULL;
zend_bool with_cas = 0;
- size_t num_keys = 0;
- zval **entry = NULL;
- const char **mkeys = NULL;
- size_t *mkeys_len = NULL;
- uint64_t orig_cas_flag = 0;
+
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
- int i = 0;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
+
if (by_key) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|bf!", &server_key,
- &server_key_len, &keys, &with_cas, &fci, &fcc) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|bf!", &server_key,
+ &keys, &with_cas, &fci, &fcc) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|bf!", &keys, &with_cas,
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|bf!", &keys, &with_cas,
&fci, &fcc) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
-
- /*
- * Create the array of keys for libmemcached. If none of the keys were valid
- * (strings), set bad key result code and return.
- */
- num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys));
- mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0);
- mkeys_len = safe_emalloc(num_keys, sizeof(*mkeys_len), 0);
-
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(keys));
- zend_hash_get_current_data(Z_ARRVAL_P(keys), (void**)&entry) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(keys))) {
-
- if (Z_TYPE_PP(entry) != IS_STRING) {
- convert_to_string_ex(entry);
- }
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
- if (Z_TYPE_PP(entry) == IS_STRING && Z_STRLEN_PP(entry) > 0) {
- mkeys[i] = Z_STRVAL_PP(entry);
- mkeys_len[i] = Z_STRLEN_PP(entry);
- i++;
- }
- }
-
- if (i == 0) {
- i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
- efree(mkeys);
- efree(mkeys_len);
- zval_dtor(return_value);
- RETURN_FALSE;
- }
-
- /*
- * Enable CAS support, but only if it is currently disabled.
- */
- if (with_cas) {
- orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS);
- if (orig_cas_flag == 0) {
- memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
- }
- }
-
- /*
- * Issue the request, but collect results only if the result callback is provided.
- */
- status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, mkeys, mkeys_len, i);
+ s_hash_to_keys(&keys_out, Z_ARRVAL_P(keys), 0, NULL);
- /*
- * Restore the CAS support flag, but only if we had to turn it on.
- */
- if (with_cas && orig_cas_flag == 0) {
- memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
+ if (fci.size > 0) {
+ php_memc_result_callback_ctx_t context = {
+ getThis(), fci, fcc
+ };
+ status = php_memc_mget_apply(intern, server_key, &keys_out, &s_result_callback_apply, with_cas, (void *) &context);
}
-
- efree(mkeys);
- efree(mkeys_len);
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- zval_dtor(return_value);
- RETURN_FALSE;
+ else {
+ status = php_memc_mget_apply(intern, server_key, &keys_out, NULL, with_cas, NULL);
}
- if (fci.size != 0) {
- /*
- * We have a result callback. Iterate through the result set and invoke the
- * callback for each one.
- */
- memcached_result_st result;
-
- memcached_result_create(m_obj->memc, &result);
- while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) {
- if (php_memc_do_result_callback(getThis(), &fci, &fcc, &result TSRMLS_CC) < 0) {
- status = MEMCACHED_FAILURE;
- break;
- }
- }
- memcached_result_free(&result);
+ s_clear_keys(&keys_out);
+ RETURN_BOOL(status);
+}
+/* }}} */
- /* we successfully retrieved all rows */
- if (status == MEMCACHED_END) {
- status = MEMCACHED_SUCCESS;
- }
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- RETURN_FALSE;
- }
- }
+static
+zend_bool s_fetch_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context)
+{
+ zval *return_value = (zval *) in_context;
+ s_create_result_array(key, value, cas, flags, return_value);
- RETURN_TRUE;
+ return 0; // stop iterating after one
}
-/* }}} */
/* {{{ Memcached::fetch()
Returns the next result from a previous delayed request */
PHP_METHOD(Memcached, fetch)
{
- const char *res_key = NULL;
- size_t res_key_len = 0;
- const char *payload = NULL;
- size_t payload_len = 0;
- zval *value;
- uint32_t flags = 0;
- uint64_t cas = 0;
- memcached_result_st result;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
@@ -1046,58 +1688,35 @@
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
- memcached_result_create(m_obj->memc, &result);
- if ((memcached_fetch_result(m_obj->memc, &result, &status)) == NULL) {
- php_memc_handle_error(i_obj, status TSRMLS_CC);
- memcached_result_free(&result);
- RETURN_FALSE;
- }
+ array_init(return_value);
+ status = php_memc_result_apply(intern, s_fetch_apply, 1, return_value);
- payload = memcached_result_value(&result);
- payload_len = memcached_result_length(&result);
- flags = memcached_result_flags(&result);
- res_key = memcached_result_key_value(&result);
- res_key_len = memcached_result_key_length(&result);
- cas = memcached_result_cas(&result);
-
- ALLOC_INIT_ZVAL(value);
-
- if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
- memcached_result_free(&result);
- zval_ptr_dtor(&value);
- i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
- RETURN_FALSE;
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
+ zval_ptr_dtor(return_value);
+ RETURN_FROM_GET;
}
+}
+/* }}} */
- array_init(return_value);
- add_assoc_stringl_ex(return_value, ZEND_STRS("key"), res_key, res_key_len, 1);
- add_assoc_zval_ex(return_value, ZEND_STRS("value"), value);
- if (cas != 0) {
- /* XXX: also check against ULLONG_MAX or memc_behavior */
- add_assoc_double_ex(return_value, ZEND_STRS("cas"), (double)cas);
- }
- if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) {
- add_assoc_long_ex(return_value, ZEND_STRS("flags"), MEMC_VAL_GET_USER_FLAGS(flags));
- }
+static
+zend_bool s_fetch_all_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context)
+{
+ zval zv;
+ zval *return_value = (zval *) in_context;
- memcached_result_free(&result);
+ array_init (&zv);
+ s_create_result_array(key, value, cas, flags, &zv);
+
+ add_next_index_zval(return_value, &zv);
+ return 1;
}
-/* }}} */
/* {{{ Memcached::fetchAll()
Returns all the results from a previous delayed request */
PHP_METHOD(Memcached, fetchAll)
{
- const char *res_key = NULL;
- size_t res_key_len = 0;
- const char *payload = NULL;
- size_t payload_len = 0;
- zval *value, *entry;
- uint32_t flags;
- uint64_t cas = 0;
- memcached_result_st result;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
@@ -1106,53 +1725,19 @@
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
array_init(return_value);
- memcached_result_create(m_obj->memc, &result);
-
- while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) {
- payload = memcached_result_value(&result);
- payload_len = memcached_result_length(&result);
- flags = memcached_result_flags(&result);
- res_key = memcached_result_key_value(&result);
- res_key_len = memcached_result_key_length(&result);
- cas = memcached_result_cas(&result);
-
- ALLOC_INIT_ZVAL(value);
-
- if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
- memcached_result_free(&result);
- zval_ptr_dtor(&value);
- zval_dtor(return_value);
- i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
- RETURN_FALSE;
- }
-
- MAKE_STD_ZVAL(entry);
- array_init(entry);
- add_assoc_stringl_ex(entry, ZEND_STRS("key"), res_key, res_key_len, 1);
- add_assoc_zval_ex(entry, ZEND_STRS("value"), value);
- if (cas != 0) {
- /* XXX: also check against ULLONG_MAX or memc_behavior */
- add_assoc_double_ex(entry, ZEND_STRS("cas"), (double)cas);
- }
- if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) {
- add_assoc_long_ex(entry, ZEND_STRS("flags"), MEMC_VAL_GET_USER_FLAGS(flags));
- }
- add_next_index_zval(return_value, entry);
- }
-
- memcached_result_free(&result);
+ status = php_memc_result_apply(intern, s_fetch_all_apply, 0, return_value);
- if (status != MEMCACHED_END && php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
zval_dtor(return_value);
RETURN_FALSE;
}
}
/* }}} */
-/* {{{ Memcached::set(string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::set(string key, mixed value [, int expiration ])
Sets the value for the given key */
PHP_METHOD(Memcached, set)
{
@@ -1160,7 +1745,7 @@
}
/* }}} */
-/* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration ])
Sets the value for the given key on the server identified by the server key */
PHP_METHOD(Memcached, setByKey)
{
@@ -1173,7 +1758,7 @@
Sets a new expiration for the given key */
PHP_METHOD(Memcached, touch)
{
- php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 0);
+ php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 0);
}
/* }}} */
@@ -1181,13 +1766,13 @@
Sets a new expiration for the given key */
PHP_METHOD(Memcached, touchByKey)
{
- php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 1);
+ php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 1);
}
/* }}} */
#endif
-/* {{{ Memcached::setMulti(array items [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::setMulti(array items [, int expiration ])
Sets the keys/values specified in the items array */
PHP_METHOD(Memcached, setMulti)
{
@@ -1195,7 +1780,7 @@
}
/* }}} */
-/* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration ])
Sets the keys/values specified in the items array on the server identified by the given server key */
PHP_METHOD(Memcached, setMultiByKey)
{
@@ -1203,127 +1788,60 @@
}
/* }}} */
-#define PHP_MEMC_FAILOVER_RETRY \
- if (!by_key && retry < m_obj->store_retry_count) { \
- switch (i_obj->rescode) { \
- case MEMCACHED_HOST_LOOKUP_FAILURE: \
- case MEMCACHED_CONNECTION_FAILURE: \
- case MEMCACHED_CONNECTION_BIND_FAILURE: \
- case MEMCACHED_WRITE_FAILURE: \
- case MEMCACHED_READ_FAILURE: \
- case MEMCACHED_UNKNOWN_READ_FAILURE: \
- case MEMCACHED_PROTOCOL_ERROR: \
- case MEMCACHED_SERVER_ERROR: \
- case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: \
- case MEMCACHED_TIMEOUT: \
- case MEMCACHED_FAIL_UNIX_SOCKET: \
- case MEMCACHED_SERVER_MARKED_DEAD: \
- case MEMCACHED_SERVER_TEMPORARILY_DISABLED: \
- if (memcached_server_count(m_obj->memc) > 0) { \
- retry++; \
- i_obj->rescode = 0; \
- goto retry; \
- } \
- break; \
- } \
- }
-
/* {{{ -- php_memc_setMulti_impl */
static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
zval *entries;
- char *server_key = NULL;
- int server_key_len = 0;
+ zend_string *server_key = NULL;
time_t expiration = 0;
- long udf_flags = 0;
- zval **entry;
- char *str_key;
- uint str_key_len;
- ulong num_key;
- char *payload;
- size_t payload_len;
- uint32_t flags = 0;
- uint32_t retry = 0;
- memcached_return status;
- char tmp_key[MEMCACHED_MAX_KEY];
+ zval *value;
+ zend_string *skey;
+ zend_ulong num_key;
+ int tmp_len = 0;
MEMC_METHOD_INIT_VARS;
if (by_key) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|ll", &server_key,
- &server_key_len, &entries, &expiration, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|ll", &server_key,
+ &entries, &expiration) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ll", &entries, &expiration, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &entries, &expiration) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
-
- /*
- * php_memcached uses 16 bits internally to store type, compression and serialization info.
- * We use 16 upper bits to store user defined flags.
- */
- if (udf_flags > 0) {
- if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX);
- }
- }
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(entries));
- zend_hash_get_current_data(Z_ARRVAL_P(entries), (void**)&entry) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(entries))) {
- int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(entries), &str_key, &str_key_len, &num_key, 0, NULL);
-
- if (key_type == HASH_KEY_IS_LONG) {
- /* Array keys are unsigned, but php integers are signed.
- * Keys must be converted to signed strings that match
- * php integers. */
- assert(sizeof(tmp_key) >= sizeof(ZEND_TOSTR(LONG_MIN)));
-
- str_key_len = sprintf(tmp_key, "%ld", (long)num_key) + 1;
- str_key = (char *)tmp_key;
- } else if (key_type != HASH_KEY_IS_STRING) {
- continue;
- }
+ ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) {
+ zend_string *str_key = NULL;
- flags = 0;
- if (m_obj->compression) {
- MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED);
+ if (skey) {
+ str_key = skey;
}
+ else {
+ char tmp_key[64];
- if (udf_flags > 0) {
- MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags));
+ tmp_len = snprintf(tmp_key, sizeof(tmp_key) - 1, "%ld", (long)num_key);
+ str_key = zend_string_init(tmp_key, tmp_len, 0);
}
- payload = php_memc_zval_to_payload(*entry, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
- if (payload == NULL) {
- i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
- RETURN_FALSE;
+ if (!s_memc_write_zval (intern, MEMC_OP_SET, server_key, str_key, value, expiration)) {
+ php_error_docref(NULL, E_WARNING, "failed to set key %s", ZSTR_VAL(str_key));
}
-retry:
- if (!by_key) {
- status = memcached_set(m_obj->memc, str_key, str_key_len-1, payload, payload_len, expiration, flags);
- } else {
- status = memcached_set_by_key(m_obj->memc, server_key, server_key_len, str_key, str_key_len-1, payload, payload_len, expiration, flags);
+ if (!skey) {
+ zend_string_release (str_key);
}
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- PHP_MEMC_FAILOVER_RETRY
- efree(payload);
- RETURN_FALSE;
- }
- efree(payload);
- }
+ } ZEND_HASH_FOREACH_END();
- RETURN_TRUE;
+ RETURN_BOOL(!s_memc_status_has_error(intern));
}
/* }}} */
-/* {{{ Memcached::add(string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::add(string key, mixed value [, int expiration ])
Sets the value for the given key, failing if the key already exists */
PHP_METHOD(Memcached, add)
{
@@ -1331,7 +1849,7 @@
}
/* }}} */
-/* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration ])
Sets the value for the given key on the server identified by the sever key, failing if the key already exists */
PHP_METHOD(Memcached, addByKey)
{
@@ -1371,7 +1889,7 @@
}
/* }}} */
-/* {{{ Memcached::replace(string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::replace(string key, mixed value [, int expiration ])
Replaces the value for the given key, failing if the key doesn't exist */
PHP_METHOD(Memcached, replace)
{
@@ -1379,7 +1897,7 @@
}
/* }}} */
-/* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration ])
Replaces the value for the given key on the server identified by the server key, failing if the key doesn't exist */
PHP_METHOD(Memcached, replaceByKey)
{
@@ -1387,258 +1905,129 @@
}
/* }}} */
-
/* {{{ -- php_memc_store_impl */
static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key)
{
- char *key = NULL;
- int key_len = 0;
- char *server_key = NULL;
- int server_key_len = 0;
- char *s_value = NULL;
- int s_value_len = 0;
- zval s_zvalue;
- zval *value;
- long expiration = 0;
- long udf_flags = 0;
- char *payload = NULL;
- size_t payload_len;
- uint32_t flags = 0;
- uint32_t retry = 0;
- memcached_return status;
+ zend_string *key;
+ zend_string *server_key = NULL;
+ zend_string *s_value;
+ zval s_zvalue;
+ zval *value = NULL;
+ zend_long expiration = 0;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", &server_key,
- &server_key_len, &key, &key_len, &s_value, &s_value_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &server_key, &key, &s_value) == FAILURE) {
return;
}
- INIT_ZVAL(s_zvalue);
value = &s_zvalue;
- ZVAL_STRINGL(value, s_value, s_value_len, 0);
+ ZVAL_STR(value, s_value);
} else if (op == MEMC_OP_TOUCH) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &server_key,
- &server_key_len, &key, &key_len, &expiration) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssz|ll", &server_key,
- &server_key_len, &key, &key_len, &value, &expiration, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSz|l", &server_key, &key, &value, &expiration) == FAILURE) {
return;
}
}
} else {
if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &key, &key_len,
- &s_value, &s_value_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &key, &s_value) == FAILURE) {
return;
}
- INIT_ZVAL(s_zvalue);
value = &s_zvalue;
- ZVAL_STRINGL(value, s_value, s_value_len, 0);
+ ZVAL_STR(value, s_value);
} else if (op == MEMC_OP_TOUCH) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key,
- &key_len, &expiration) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|ll", &key, &key_len,
- &value, &expiration, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &key, &value, &expiration) == FAILURE) {
return;
}
}
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
-
- if (key_len == 0 || key_len > MEMC_OBJECT_KEY_MAX_LENGTH || strchr(key, ' ') || strchr(key, '\n')) {
- i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
- RETURN_FALSE;
- }
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
+ MEMC_CHECK_KEY(intern, key);
- if (m_obj->compression) {
+ if (memc_user_data->compression_enabled) {
/*
* When compression is enabled, we cannot do appends/prepends because that would
* corrupt the compressed values. It is up to the user to fetch the value,
* append/prepend new data, and store it again.
*/
if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot append/prepend with compression turned on");
- return;
+ php_error_docref(NULL, E_WARNING, "cannot append/prepend with compression turned on");
+ RETURN_NULL();
}
- MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED);
}
- /*
- * php_memcached uses 16 bits internally to store type, compression and serialization info.
- * We use 16 upper bits to store user defined flags.
- */
- if (udf_flags > 0) {
- if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX);
- }
- MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags));
- }
if (op == MEMC_OP_TOUCH) {
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016
- if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16");
- }
-#endif
- } else {
- payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
- if (payload == NULL) {
- i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
- RETURN_FALSE;
+ if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
+ php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16");
}
- }
-retry:
- switch (op) {
- case MEMC_OP_SET:
- if (!server_key) {
- status = memcached_set(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
- } else {
- status = memcached_set_by_key(m_obj->memc, server_key, server_key_len, key,
- key_len, payload, payload_len, expiration, flags);
- }
- break;
-#ifdef HAVE_MEMCACHED_TOUCH
- case MEMC_OP_TOUCH:
- if (!server_key) {
- status = memcached_touch(m_obj->memc, key, key_len, expiration);
- } else {
- status = memcached_touch_by_key(m_obj->memc, server_key, server_key_len, key,
- key_len, expiration);
- }
- break;
#endif
- case MEMC_OP_ADD:
- if (!server_key) {
- status = memcached_add(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
- } else {
- status = memcached_add_by_key(m_obj->memc, server_key, server_key_len, key,
- key_len, payload, payload_len, expiration, flags);
- }
- break;
-
- case MEMC_OP_REPLACE:
- if (!server_key) {
- status = memcached_replace(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
- } else {
- status = memcached_replace_by_key(m_obj->memc, server_key, server_key_len, key,
- key_len, payload, payload_len, expiration, flags);
- }
- break;
-
- case MEMC_OP_APPEND:
- if (!server_key) {
- status = memcached_append(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
- } else {
- status = memcached_append_by_key(m_obj->memc, server_key, server_key_len, key,
- key_len, payload, payload_len, expiration, flags);
- }
- break;
-
- case MEMC_OP_PREPEND:
- if (!server_key) {
- status = memcached_prepend(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
- } else {
- status = memcached_prepend_by_key(m_obj->memc, server_key, server_key_len, key,
- key_len, payload, payload_len, expiration, flags);
- }
- break;
-
- default:
- /* not reached */
- status = 0;
- assert(0);
- break;
- }
-
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- PHP_MEMC_FAILOVER_RETRY
- RETVAL_FALSE;
- } else {
- RETVAL_TRUE;
}
- if (payload) {
- efree(payload);
+ if (!s_memc_write_zval (intern, op, server_key, key, value, expiration)) {
+ RETURN_FALSE;
}
+ RETURN_TRUE;
}
/* }}} */
/* {{{ -- php_memc_cas_impl */
static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
- double cas_d;
+ zval *zv_cas;
uint64_t cas;
- char *key = NULL;
- int key_len = 0;
- char *server_key = NULL;
- int server_key_len = 0;
+ zend_string *key;
+ zend_string *server_key = NULL;
zval *value;
time_t expiration = 0;
- long udf_flags = 0;
- char *payload;
- size_t payload_len;
+ zend_string *payload;
uint32_t flags = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (by_key) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dssz|ll", &cas_d, &server_key,
- &server_key_len, &key, &key_len, &value, &expiration, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSSz|ll", &zv_cas, &server_key, &key,
+ &value, &expiration) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dsz|ll", &cas_d, &key, &key_len,
- &value, &expiration, &udf_flags) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSz|ll", &zv_cas, &key, &value,
+ &expiration) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
-
- if (key_len == 0 || key_len > MEMC_OBJECT_KEY_MAX_LENGTH || strchr(key, ' ') || strchr(key, '\n')) {
- i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
- RETURN_FALSE;
- }
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
+ MEMC_CHECK_KEY(intern, key);
- DVAL_TO_LVAL(cas_d, cas);
+ cas = s_zval_to_uint64(zv_cas);
- if (m_obj->compression) {
- MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED);
- }
-
- /*
- * php_memcached uses 16 bits internally to store type, compression and serialization info.
- * We use 16 upper bits to store user defined flags.
- */
- if (udf_flags > 0) {
- if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX);
- }
- MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags));
- }
-
- payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
+ payload = s_zval_to_payload(intern, value, &flags);
if (payload == NULL) {
- i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
+ intern->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FALSE;
}
if (by_key) {
- status = memcached_cas_by_key(m_obj->memc, server_key, server_key_len, key, key_len, payload, payload_len, expiration, flags, cas);
+ status = memcached_cas_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags, cas);
} else {
- status = memcached_cas(m_obj->memc, key, key_len, payload, payload_len, expiration, flags, cas);
+ status = memcached_cas(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags, cas);
}
- efree(payload);
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
+
+ zend_string_release(payload);
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
RETURN_FALSE;
}
@@ -1646,7 +2035,7 @@
}
/* }}} */
-/* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ])
Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */
PHP_METHOD(Memcached, cas)
{
@@ -1654,7 +2043,7 @@
}
/* }}} */
-/* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration [, int udf_flags ] ])
+/* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ])
Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */
PHP_METHOD(Memcached, casByKey)
{
@@ -1697,40 +2086,34 @@
/* {{{ -- php_memc_delete_impl */
static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
- char *key = NULL;
- int key_len = 0;
- char *server_key = NULL;
- int server_key_len = 0;
+ zend_string *key, *server_key;
time_t expiration = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (by_key) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &server_key,
- &server_key_len, &key, &key_len, &expiration) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len,
- &expiration) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) {
return;
}
- server_key = key;
- server_key_len = key_len;
+ server_key = key;
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
+ MEMC_CHECK_KEY(intern, key);
- if (key_len == 0 || key_len > MEMC_OBJECT_KEY_MAX_LENGTH || strchr(key, ' ') || strchr(key, '\n')) {
- i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
- RETURN_FALSE;
+ if (by_key) {
+ status = memcached_delete_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key),
+ ZSTR_LEN(key), expiration);
+ } else {
+ status = memcached_delete(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration);
}
- status = memcached_delete_by_key(m_obj->memc, server_key, server_key_len, key,
- key_len, expiration);
-
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
RETURN_FALSE;
}
@@ -1741,55 +2124,50 @@
/* {{{ -- php_memc_deleteMulti_impl */
static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
- zval *entries;
- char *server_key = NULL;
- int server_key_len = 0;
+ zval *entries, *zv, ret;
+ zend_string *server_key = NULL;
time_t expiration = 0;
- zval **entry;
+ zend_string *entry;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (by_key) {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|l", &server_key,
- &server_key_len, &entries, &expiration) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|l", &server_key, &entries, &expiration) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|l", &entries, &expiration) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &entries, &expiration) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
array_init(return_value);
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(entries));
- zend_hash_get_current_data(Z_ARRVAL_P(entries), (void**)&entry) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(entries))) {
-
- if (Z_TYPE_PP(entry) != IS_STRING) {
- convert_to_string_ex(entry);
- }
+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), zv) {
+ entry = zval_get_string(zv);
- if (Z_STRLEN_PP(entry) == 0) {
+ if (ZSTR_LEN(entry) == 0) {
+ zend_string_release(entry);
continue;
}
- if (!by_key) {
- server_key = Z_STRVAL_PP(entry);
- server_key_len = Z_STRLEN_PP(entry);
+ if (by_key) {
+ status = memcached_delete_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(entry), ZSTR_LEN(entry), expiration);
+ } else {
+ status = memcached_delete_by_key(intern->memc, ZSTR_VAL(entry), ZSTR_LEN(entry), ZSTR_VAL(entry), ZSTR_LEN(entry), expiration);
}
- status = memcached_delete_by_key(m_obj->memc, server_key, server_key_len, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), expiration);
-
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- add_assoc_long(return_value, Z_STRVAL_PP(entry), status);
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
+ ZVAL_LONG(&ret, status);
} else {
- add_assoc_bool(return_value, Z_STRVAL_PP(entry), 1);
+ ZVAL_TRUE(&ret);
}
- }
+ zend_symtable_update(Z_ARRVAL_P(return_value), entry, &ret);
+ zend_string_release(entry);
+ } ZEND_HASH_FOREACH_END();
return;
}
@@ -1798,77 +2176,80 @@
/* {{{ -- php_memc_incdec_impl */
static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr)
{
- char *key, *server_key;
- int key_len, server_key_len;
+ zend_string *key, *server_key = NULL;
long offset = 1;
- uint64_t value, initial = 0;
+ uint64_t value = UINT64_MAX, initial = 0;
time_t expiry = 0;
memcached_return status;
int n_args = ZEND_NUM_ARGS();
- uint32_t retry = 0;
MEMC_METHOD_INIT_VARS;
if (!by_key) {
- if (zend_parse_parameters(n_args TSRMLS_CC, "s|lll", &key, &key_len, &offset, &initial, &expiry) == FAILURE) {
+ if (zend_parse_parameters(n_args, "S|lll", &key, &offset, &initial, &expiry) == FAILURE) {
return;
}
} else {
- if (zend_parse_parameters(n_args TSRMLS_CC, "ss|lll", &server_key, &server_key_len, &key, &key_len, &offset, &initial, &expiry) == FAILURE) {
+ if (zend_parse_parameters(n_args, "SS|lll", &server_key, &key, &offset, &initial, &expiry) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
-
- if (key_len == 0 || key_len > MEMC_OBJECT_KEY_MAX_LENGTH || strchr(key, ' ') || strchr(key, '\n')) {
- i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
- RETURN_FALSE;
- }
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
+ MEMC_CHECK_KEY(intern, key);
if (offset < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset has to be > 0");
+ php_error_docref(NULL, E_WARNING, "offset has to be > 0");
RETURN_FALSE;
}
-retry:
if ((!by_key && n_args < 3) || (by_key && n_args < 4)) {
if (by_key) {
if (incr) {
- status = memcached_increment_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, &value);
+ status = memcached_increment_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
} else {
- status = memcached_decrement_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, &value);
+ status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
}
} else {
if (incr) {
- status = memcached_increment(m_obj->memc, key, key_len, (unsigned int)offset, &value);
+ status = memcached_increment(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
} else {
- status = memcached_decrement(m_obj->memc, key, key_len, (unsigned int)offset, &value);
+ status = memcached_decrement(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value);
}
}
+
} else {
- if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Initial value is only supported with binary protocol");
+ zend_long retries = memc_user_data->store_retry_count;
+
+retry_inc_dec:
+ if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
+ php_error_docref(NULL, E_WARNING, "Initial value is only supported with binary protocol");
RETURN_FALSE;
}
if (by_key) {
if (incr) {
- status = memcached_increment_with_initial_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, initial, expiry, &value);
+ status = memcached_increment_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
} else {
- status = memcached_decrement_with_initial_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, initial, expiry, &value);
+ status = memcached_decrement_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
}
} else {
if (incr) {
- status = memcached_increment_with_initial(m_obj->memc, key, key_len, (unsigned int)offset, initial, expiry, &value);
+ status = memcached_increment_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
} else {
- status = memcached_decrement_with_initial(m_obj->memc, key, key_len, (unsigned int)offset, initial, expiry, &value);
+ status = memcached_decrement_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value);
}
}
+ if (s_should_retry_write(intern, status) && retries-- > 0) {
+ goto retry_inc_dec;
+ }
+ }
+
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
+ RETURN_FALSE;
}
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- PHP_MEMC_FAILOVER_RETRY
+ if (value == UINT64_MAX) {
RETURN_FALSE;
}
@@ -1912,33 +2293,31 @@
Adds the given memcache server to the list */
PHP_METHOD(Memcached, addServer)
{
- char *host;
- int host_len;
+ zend_string *host;
long port, weight = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &host, &host_len,
- &port, &weight) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l", &host, &port, &weight) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002
- if (host[0] == '/') { /* unix domain socket */
- status = memcached_server_add_unix_socket_with_weight(m_obj->memc, host, weight);
- } else if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_USE_UDP)) {
- status = memcached_server_add_udp_with_weight(m_obj->memc, host, port, weight);
+ if (ZSTR_VAL(host)[0] == '/') { /* unix domain socket */
+ status = memcached_server_add_unix_socket_with_weight(intern->memc, ZSTR_VAL(host), weight);
+ } else if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_USE_UDP)) {
+ status = memcached_server_add_udp_with_weight(intern->memc, ZSTR_VAL(host), port, weight);
} else {
- status = memcached_server_add_with_weight(m_obj->memc, host, port, weight);
+ status = memcached_server_add_with_weight(intern->memc, ZSTR_VAL(host), port, weight);
}
#else
- status = memcached_server_add_with_weight(m_obj->memc, host, port, weight);
+ status = memcached_server_add_with_weight(intern->memc, ZSTR_VAL(host), port, weight);
#endif
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
RETURN_FALSE;
}
@@ -1951,78 +2330,83 @@
PHP_METHOD(Memcached, addServers)
{
zval *servers;
- zval **entry;
- zval **z_host, **z_port, **z_weight = NULL;
- uint32_t weight = 0;
+ zval *entry;
+ zval *z_host, *z_port, *z_weight = NULL;
+ HashPosition pos;
int entry_size, i = 0;
memcached_server_st *list = NULL;
memcached_return status;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &servers) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &servers) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
-
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(servers)), i = 0;
- zend_hash_get_current_data(Z_ARRVAL_P(servers), (void **)&entry) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(servers)), i++) {
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
- if (Z_TYPE_PP(entry) != IS_ARRAY) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "server list entry #%d is not an array", i+1);
+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(servers), entry) {
+ if (Z_TYPE_P(entry) != IS_ARRAY) {
+ php_error_docref(NULL, E_WARNING, "server list entry #%d is not an array", i+1);
+ i++;
continue;
}
- entry_size = zend_hash_num_elements(Z_ARRVAL_PP(entry));
+ entry_size = zend_hash_num_elements(Z_ARRVAL_P(entry));
if (entry_size > 1) {
- zend_hash_internal_pointer_reset(Z_ARRVAL_PP(entry));
+ zend_string *host;
+ zend_long port;
+ uint32_t weight;
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos);
/* Check that we have a host */
- if (zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_host) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server host for entry #%d", i+1);
+ if ((z_host = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) {
+ php_error_docref(NULL, E_WARNING, "could not get server host for entry #%d", i+1);
+ i++;
continue;
}
/* Check that we have a port */
- if (zend_hash_move_forward(Z_ARRVAL_PP(entry)) == FAILURE ||
- zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_port) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server port for entry #%d", i+1);
+ if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE ||
+ (z_port = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) {
+ php_error_docref(NULL, E_WARNING, "could not get server port for entry #%d", i+1);
+ i++;
continue;
}
- convert_to_string_ex(z_host);
- convert_to_long_ex(z_port);
+ host = zval_get_string(z_host);
+ port = zval_get_long(z_port);
weight = 0;
if (entry_size > 2) {
/* Try to get weight */
- if (zend_hash_move_forward(Z_ARRVAL_PP(entry)) == FAILURE ||
- zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_weight) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server weight for entry #%d", i+1);
+ if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE ||
+ (z_weight = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) {
+ php_error_docref(NULL, E_WARNING, "could not get server weight for entry #%d", i+1);
}
- convert_to_long_ex(z_weight);
- weight = Z_LVAL_PP(z_weight);
+ weight = zval_get_long(z_weight);
}
- list = memcached_server_list_append_with_weight(list, Z_STRVAL_PP(z_host),
- Z_LVAL_PP(z_port), weight, &status);
+ list = memcached_server_list_append_with_weight(list, ZSTR_VAL(host), port, weight, &status);
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) == 0) {
+ zend_string_release(host);
+
+ if (s_memc_status_handle_result_code(intern, status) == SUCCESS) {
+ i++;
continue;
}
}
-
+ i++;
/* catch-all for all errors */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not add entry #%d to the server list", i+1);
- }
+ php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i + 1);
+ } ZEND_HASH_FOREACH_END();
- status = memcached_server_push(m_obj->memc, list);
+ status = memcached_server_push(intern->memc, list);
memcached_server_list_free(list);
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
RETURN_FALSE;
}
@@ -2030,12 +2414,10 @@
}
/* }}} */
-
/* {{{ Memcached::getServerList()
Returns the list of the memcache servers in use */
PHP_METHOD(Memcached, getServerList)
{
- struct callbackContext context = {0};
memcached_server_function callbacks[1];
MEMC_METHOD_INIT_VARS;
@@ -2045,10 +2427,9 @@
MEMC_METHOD_FETCH_OBJECT;
- callbacks[0] = php_memc_do_serverlist_callback;
+ callbacks[0] = s_server_cursor_list_servers_cb;
array_init(return_value);
- context.return_value = return_value;
- memcached_server_cursor(m_obj->memc, callbacks, &context, 1);
+ memcached_server_cursor(intern->memc, callbacks, return_value, 1);
}
/* }}} */
@@ -2056,32 +2437,26 @@
Returns the server identified by the given server key */
PHP_METHOD(Memcached, getServerByKey)
{
- char *server_key;
- int server_key_len;
+ zend_string *server_key;
php_memcached_instance_st server_instance;
memcached_return error;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &server_key, &server_key_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &server_key) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
-
- if (server_key_len == 0 || strchr(server_key, ' ')) {
- i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
- RETURN_FALSE;
- }
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
- server_instance = memcached_server_by_key(m_obj->memc, server_key, server_key_len, &error);
+ server_instance = memcached_server_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), &error);
if (server_instance == NULL) {
- php_memc_handle_error(i_obj, error TSRMLS_CC);
+ s_memc_status_handle_result_code(intern, error);
RETURN_FALSE;
}
array_init(return_value);
- add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance), 1);
+ add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance));
add_assoc_long(return_value, "port", memcached_server_port(server_instance));
add_assoc_long(return_value, "weight", 0);
}
@@ -2091,16 +2466,16 @@
Reset the server list in use */
PHP_METHOD(Memcached, resetServerList)
{
- MEMC_METHOD_INIT_VARS;
+ MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
- MEMC_METHOD_FETCH_OBJECT;
+ MEMC_METHOD_FETCH_OBJECT;
- memcached_servers_reset(m_obj->memc);
- RETURN_TRUE;
+ memcached_servers_reset(intern->memc);
+ RETURN_TRUE;
}
/* }}} */
@@ -2108,16 +2483,16 @@
Close any open connections */
PHP_METHOD(Memcached, quit)
{
- MEMC_METHOD_INIT_VARS;
+ MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
- MEMC_METHOD_FETCH_OBJECT;
+ MEMC_METHOD_FETCH_OBJECT;
- memcached_quit(m_obj->memc);
- RETURN_TRUE;
+ memcached_quit(intern->memc);
+ RETURN_TRUE;
}
/* }}} */
@@ -2131,8 +2506,8 @@
return;
}
- MEMC_METHOD_FETCH_OBJECT;
- RETURN_BOOL(memcached_flush_buffers(m_obj->memc) == MEMCACHED_SUCCESS);
+ MEMC_METHOD_FETCH_OBJECT;
+ RETURN_BOOL(memcached_flush_buffers(intern->memc) == MEMCACHED_SUCCESS);
}
/* }}} */
@@ -2149,7 +2524,7 @@
MEMC_METHOD_FETCH_OBJECT;
- RETURN_STRING(memcached_last_error_message(m_obj->memc), 1);
+ RETURN_STRING(memcached_last_error_message(intern->memc));
}
/* }}} */
@@ -2165,7 +2540,7 @@
MEMC_METHOD_FETCH_OBJECT;
- RETURN_LONG(memcached_last_error(m_obj->memc));
+ RETURN_LONG(memcached_last_error(intern->memc));
}
/* }}} */
@@ -2181,7 +2556,7 @@
MEMC_METHOD_FETCH_OBJECT;
- RETURN_LONG(memcached_last_error_errno(m_obj->memc));
+ RETURN_LONG(memcached_last_error_errno(intern->memc));
}
/* }}} */
#endif
@@ -2200,25 +2575,91 @@
MEMC_METHOD_FETCH_OBJECT;
- server_instance = memcached_server_get_last_disconnect(m_obj->memc);
+ server_instance = memcached_server_get_last_disconnect(intern->memc);
if (server_instance == NULL) {
RETURN_FALSE;
}
array_init(return_value);
- add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance), 1);
+ add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance));
add_assoc_long(return_value, "port", memcached_server_port(server_instance));
}
/* }}} */
+
+
+static
+zend_bool s_long_value(const char *str, zend_long *value)
+{
+ char *end = (char *) str;
+
+ errno = 0;
+ *value = strtol(str, &end, 10);
+
+ if (errno || str == end || *end != '\0') {
+ return 0;
+ }
+ return 1;
+}
+
+static
+zend_bool s_double_value(const char *str, double *value)
+{
+ char *end = (char *) str;
+
+ errno = 0;
+ *value = strtod(str, &end);
+
+ if (errno || str == end || *end != '\0') {
+ return 0;
+ }
+ return 1;
+}
+
+static
+memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const char *key, size_t key_length, const char *value, size_t value_length, void *context)
+{
+ zend_string *server_key;
+ zend_long long_val;
+ double d_val;
+ char *buffer;
+
+ zval *return_value = (zval *) context;
+ zval *server_values;
+
+ server_key = strpprintf(0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance));
+ server_values = zend_hash_find(Z_ARRVAL_P(return_value), server_key);
+
+ if (!server_values) {
+ zval zv;
+ array_init(&zv);
+
+ server_values = zend_hash_add(Z_ARRVAL_P(return_value), server_key, &zv);
+ }
+
+ spprintf (&buffer, 0, "%.*s", value_length, value);
+
+ /* Check type */
+ if (s_long_value (buffer, &long_val)) {
+ add_assoc_long(server_values, key, long_val);
+ }
+ else if (s_double_value (buffer, &d_val)) {
+ add_assoc_double(server_values, key, d_val);
+ }
+ else {
+ add_assoc_stringl_ex(server_values, key, key_length, (char*)value, value_length);
+ }
+ efree (buffer);
+ zend_string_release(server_key);
+
+ return MEMCACHED_SUCCESS;
+}
+
/* {{{ Memcached::getStats()
Returns statistics for the memcache servers */
PHP_METHOD(Memcached, getStats)
{
- memcached_stat_st *stats;
memcached_return status;
- struct callbackContext context = {0};
- memcached_server_function callbacks[1];
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
@@ -2227,29 +2668,12 @@
MEMC_METHOD_FETCH_OBJECT;
- if (memcached_server_count(m_obj->memc) == 0) {
- array_init(return_value);
- return;
- }
-
- stats = memcached_stat(m_obj->memc, NULL, &status);
- php_memc_handle_error(i_obj, status TSRMLS_CC);
- if (stats == NULL) {
- RETURN_FALSE;
- } else if (status != MEMCACHED_SUCCESS && status != MEMCACHED_SOME_ERRORS) {
- memcached_stat_free(m_obj->memc, stats);
+ array_init(return_value);
+ status = memcached_stat_execute(intern->memc, NULL, s_stat_execute_cb, return_value);
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
+ zval_ptr_dtor(return_value);
RETURN_FALSE;
}
-
- array_init(return_value);
-
- callbacks[0] = php_memc_do_stats_callback;
- context.i = 0;
- context.stats = stats;
- context.return_value = return_value;
- memcached_server_cursor(m_obj->memc, callbacks, &context, 1);
-
- memcached_stat_free(m_obj->memc, stats);
}
/* }}} */
@@ -2257,8 +2681,7 @@
Returns the version of each memcached server in the pool */
PHP_METHOD(Memcached, getVersion)
{
- memcached_return status = MEMCACHED_SUCCESS;
- struct callbackContext context = {0};
+ memcached_return status;
memcached_server_function callbacks[1];
MEMC_METHOD_INIT_VARS;
@@ -2268,28 +2691,29 @@
MEMC_METHOD_FETCH_OBJECT;
- array_init(return_value);
-
- status = memcached_version(m_obj->memc);
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
- zval_dtor(return_value);
+ status = memcached_version(intern->memc);
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
RETURN_FALSE;
}
- callbacks[0] = php_memc_do_version_callback;
- context.return_value = return_value;
+ callbacks[0] = s_server_cursor_version_cb;
- memcached_server_cursor(m_obj->memc, callbacks, &context, 1);
+ array_init(return_value);
+ status = memcached_server_cursor(intern->memc, callbacks, return_value, 1);
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
+ zval_dtor(return_value);
+ RETURN_FALSE;
+ }
}
/* }}} */
/* {{{ Memcached::getAllKeys()
Returns the keys stored on all the servers */
-static memcached_return php_memc_dump_func_callback(const memcached_st *ptr __attribute__((unused)), \
- const char *key, size_t key_length, void *context)
+static
+memcached_return s_dump_keys_cb(const memcached_st *ptr, const char *key, size_t key_length, void *in_context)
{
- zval *ctx = (zval*) context;
- add_next_index_string(ctx, (char*) key, 1);
+ zval *return_value = (zval*) in_context;
+ add_next_index_stringl(return_value, key, key_length);
return MEMCACHED_SUCCESS;
}
@@ -2300,12 +2724,17 @@
memcached_dump_func callback[1];
MEMC_METHOD_INIT_VARS;
- callback[0] = php_memc_dump_func_callback;
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ callback[0] = s_dump_keys_cb;
MEMC_METHOD_FETCH_OBJECT;
array_init(return_value);
- rc = memcached_dump(m_obj->memc, callback, return_value, 1);
- if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) {
+
+ rc = memcached_dump(intern->memc, callback, return_value, 1);
+ if (s_memc_status_handle_result_code(intern, rc) == FAILURE) {
zval_dtor(return_value);
RETURN_FALSE;
}
@@ -2320,15 +2749,15 @@
memcached_return status;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &delay) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &delay) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
- i_obj->rescode = MEMCACHED_SUCCESS;
+ s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
- status = memcached_flush(m_obj->memc, delay);
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
+ status = memcached_flush(intern->memc, delay);
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
RETURN_FALSE;
}
@@ -2345,7 +2774,7 @@
memcached_behavior flag;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &option) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &option) == FAILURE) {
return;
}
@@ -2353,22 +2782,22 @@
switch (option) {
case MEMC_OPT_COMPRESSION_TYPE:
- RETURN_LONG(m_obj->compression_type);
+ RETURN_LONG(memc_user_data->compression_type);
case MEMC_OPT_COMPRESSION:
- RETURN_BOOL(m_obj->compression);
+ RETURN_BOOL(memc_user_data->compression_enabled);
case MEMC_OPT_PREFIX_KEY:
{
memcached_return retval;
char *result;
- result = memcached_callback_get(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval);
+ result = memcached_callback_get(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval);
if (retval == MEMCACHED_SUCCESS && result) {
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000
- RETURN_STRINGL(result, strlen(result) - 1, 1);
+ RETURN_STRINGL(result, strlen(result));
#else
- RETURN_STRING(result, 1);
+ RETURN_STRING(result);
#endif
} else {
RETURN_EMPTY_STRING();
@@ -2376,17 +2805,21 @@
}
case MEMC_OPT_SERIALIZER:
- RETURN_LONG((long)m_obj->serializer);
+ RETURN_LONG((long)memc_user_data->serializer);
+ break;
+
+ case MEMC_OPT_USER_FLAGS:
+ RETURN_LONG(memc_user_data->set_udf_flags);
break;
case MEMC_OPT_STORE_RETRY_COUNT:
- RETURN_LONG((long)m_obj->store_retry_count);
+ RETURN_LONG((long)memc_user_data->store_retry_count);
break;
case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
- if (memcached_server_count(m_obj->memc) == 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "no servers defined");
+ if (memcached_server_count(intern->memc) == 0) {
+ php_error_docref(NULL, E_WARNING, "no servers defined");
return;
}
@@ -2395,44 +2828,46 @@
* Assume that it's a libmemcached behavior option.
*/
flag = (memcached_behavior) option;
- result = memcached_behavior_get(m_obj->memc, flag);
+ result = memcached_behavior_get(intern->memc, flag);
RETURN_LONG((long)result);
}
}
/* }}} */
-static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRMLS_DC)
+static
+int php_memc_set_option(php_memc_object_t *intern, long option, zval *value)
{
+ zend_long lval;
memcached_return rc = MEMCACHED_FAILURE;
memcached_behavior flag;
- struct memc_obj *m_obj = i_obj->obj;
+ php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc);
switch (option) {
case MEMC_OPT_COMPRESSION:
- convert_to_long(value);
- m_obj->compression = Z_LVAL_P(value) ? 1 : 0;
+ memc_user_data->compression_enabled = zval_get_long(value) ? 1 : 0;
break;
case MEMC_OPT_COMPRESSION_TYPE:
- convert_to_long(value);
- if (Z_LVAL_P(value) == COMPRESSION_TYPE_FASTLZ ||
- Z_LVAL_P(value) == COMPRESSION_TYPE_ZLIB) {
- m_obj->compression_type = Z_LVAL_P(value);
+ lval = zval_get_long(value);
+ if (lval == COMPRESSION_TYPE_FASTLZ ||
+ lval == COMPRESSION_TYPE_ZLIB) {
+ memc_user_data->compression_type = lval;
} else {
/* invalid compression type */
- i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS;
+ intern->rescode = MEMCACHED_INVALID_ARGUMENTS;
return 0;
}
break;
case MEMC_OPT_PREFIX_KEY:
{
+ zend_string *str;
char *key;
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000
char tmp[MEMCACHED_PREFIX_KEY_MAX_SIZE - 1];
#endif
- convert_to_string(value);
- if (Z_STRLEN_P(value) == 0) {
+ str = zval_get_string(value);
+ if (ZSTR_VAL(str) == 0) {
key = NULL;
} else {
/*
@@ -2440,28 +2875,30 @@
character of the key prefix, to avoid the issue we pad it with a '0'
*/
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000
- snprintf(tmp, sizeof(tmp), "%s0", Z_STRVAL_P(value));
+ snprintf(tmp, sizeof(tmp), "%s0", ZSTR_VAL(str));
key = tmp;
#else
- key = Z_STRVAL_P(value);
+ key = ZSTR_VAL(str);
#endif
}
- if (memcached_callback_set(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) {
- i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS;
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "bad key provided");
+ if (memcached_callback_set(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) {
+ zend_string_release(str);
+ intern->rescode = MEMCACHED_INVALID_ARGUMENTS;
+ php_error_docref(NULL, E_WARNING, "bad key provided");
return 0;
}
+ zend_string_release(str);
}
break;
case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
flag = (memcached_behavior) option;
- convert_to_long(value);
- rc = memcached_behavior_set(m_obj->memc, flag, (uint64_t) Z_LVAL_P(value));
+ lval = zval_get_long(value);
+ rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval);
- if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc));
+ if (s_memc_status_handle_result_code(intern, rc) == FAILURE) {
+ php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc));
return 0;
}
@@ -2470,55 +2907,70 @@
* options on false case, like it does for MEMCACHED_BEHAVIOR_KETAMA
* (non-weighted) case. We have to clean up ourselves.
*/
- if (!Z_LVAL_P(value)) {
+ if (!lval) {
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX > 0x00037000
- (void)memcached_behavior_set_key_hash(m_obj->memc, MEMCACHED_HASH_DEFAULT);
- (void)memcached_behavior_set_distribution_hash(m_obj->memc, MEMCACHED_HASH_DEFAULT);
- (void)memcached_behavior_set_distribution(m_obj->memc, MEMCACHED_DISTRIBUTION_MODULA);
+ (void)memcached_behavior_set_key_hash(intern->memc, MEMCACHED_HASH_DEFAULT);
+ (void)memcached_behavior_set_distribution_hash(intern->memc, MEMCACHED_HASH_DEFAULT);
+ (void)memcached_behavior_set_distribution(intern->memc, MEMCACHED_DISTRIBUTION_MODULA);
#else
- m_obj->memc->hash = 0;
- m_obj->memc->distribution = 0;
+ intern->memc->hash = 0;
+ intern->memc->distribution = 0;
#endif
}
break;
case MEMC_OPT_SERIALIZER:
{
- convert_to_long(value);
+ lval = zval_get_long(value);
/* igbinary serializer */
#ifdef HAVE_MEMCACHED_IGBINARY
- if (Z_LVAL_P(value) == SERIALIZER_IGBINARY) {
- m_obj->serializer = SERIALIZER_IGBINARY;
+ if (lval == SERIALIZER_IGBINARY) {
+ memc_user_data->serializer = SERIALIZER_IGBINARY;
} else
#endif
#ifdef HAVE_JSON_API
- if (Z_LVAL_P(value) == SERIALIZER_JSON) {
- m_obj->serializer = SERIALIZER_JSON;
- } else if (Z_LVAL_P(value) == SERIALIZER_JSON_ARRAY) {
- m_obj->serializer = SERIALIZER_JSON_ARRAY;
+ if (lval == SERIALIZER_JSON) {
+ memc_user_data->serializer = SERIALIZER_JSON;
+ } else if (lval == SERIALIZER_JSON_ARRAY) {
+ memc_user_data->serializer = SERIALIZER_JSON_ARRAY;
} else
#endif
/* msgpack serializer */
#ifdef HAVE_MEMCACHED_MSGPACK
- if (Z_LVAL_P(value) == SERIALIZER_MSGPACK) {
- m_obj->serializer = SERIALIZER_MSGPACK;
+ if (lval == SERIALIZER_MSGPACK) {
+ memc_user_data->serializer = SERIALIZER_MSGPACK;
} else
#endif
/* php serializer */
- if (Z_LVAL_P(value) == SERIALIZER_PHP) {
- m_obj->serializer = SERIALIZER_PHP;
+ if (lval == SERIALIZER_PHP) {
+ memc_user_data->serializer = SERIALIZER_PHP;
} else {
- m_obj->serializer = SERIALIZER_PHP;
- i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS;
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid serializer provided");
+ memc_user_data->serializer = SERIALIZER_PHP;
+ intern->rescode = MEMCACHED_INVALID_ARGUMENTS;
+ php_error_docref(NULL, E_WARNING, "invalid serializer provided");
return 0;
}
break;
}
+ case MEMC_OPT_USER_FLAGS:
+ lval = zval_get_long(value);
+
+ if (lval < 0) {
+ memc_user_data->set_udf_flags = -1;
+ return 1;
+ }
+
+ if (lval > MEMC_VAL_USER_FLAGS_MAX) {
+ php_error_docref(NULL, E_WARNING, "MEMC_OPT_USER_FLAGS must be < %u", MEMC_VAL_USER_FLAGS_MAX);
+ return 0;
+ }
+ memc_user_data->set_udf_flags = lval;
+ break;
+
case MEMC_OPT_STORE_RETRY_COUNT:
- convert_to_long(value);
- m_obj->store_retry_count = Z_LVAL_P(value);
+ lval = zval_get_long(value);
+ memc_user_data->store_retry_count = lval;
break;
default:
@@ -2530,18 +2982,18 @@
}
else {
flag = (memcached_behavior) option;
- convert_to_long(value);
+ lval = zval_get_long(value);
if (flag < MEMCACHED_BEHAVIOR_MAX) {
- rc = memcached_behavior_set(m_obj->memc, flag, (uint64_t) Z_LVAL_P(value));
+ rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval);
}
else {
rc = MEMCACHED_INVALID_ARGUMENTS;
}
}
- if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc));
+ if (s_memc_status_handle_result_code(intern, rc) == FAILURE) {
+ php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc));
return 0;
}
break;
@@ -2550,9 +3002,9 @@
}
static
-uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements TSRMLS_DC)
+uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements)
{
- zval **ppzval;
+ zval *pzval;
uint32_t *retval;
size_t i = 0;
@@ -2564,34 +3016,19 @@
retval = ecalloc(*num_elements, sizeof(uint32_t));
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(input));
- zend_hash_get_current_data(Z_ARRVAL_P(input), (void **) &ppzval) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(input)), i++) {
-
- long value = 0;
-
- if (Z_TYPE_PP(ppzval) == IS_LONG) {
- value = Z_LVAL_PP(ppzval);
- }
- else {
- zval tmp_zval, *tmp_pzval;
- tmp_zval = **ppzval;
- zval_copy_ctor(&tmp_zval);
- tmp_pzval = &tmp_zval;
- convert_to_long(tmp_pzval);
-
- value = (Z_LVAL_P(tmp_pzval) > 0) ? Z_LVAL_P(tmp_pzval) : 0;
- zval_dtor(tmp_pzval);
- }
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), pzval) {
+ zend_long value = 0;
+ value = zval_get_long(pzval);
if (value < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "the map must contain positive integers");
+ php_error_docref(NULL, E_WARNING, "the map must contain positive integers");
efree (retval);
*num_elements = 0;
return NULL;
}
retval [i] = (uint32_t) value;
- }
+ i++;
+ } ZEND_HASH_FOREACH_END();
return retval;
}
@@ -2610,35 +3047,35 @@
memcached_return rc;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "aa!l", &zserver_map, &zforward_map, &replicas) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa!l", &zserver_map, &zforward_map, &replicas) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
if (zend_hash_num_elements (Z_ARRVAL_P(zserver_map)) == 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "server map cannot be empty");
+ php_error_docref(NULL, E_WARNING, "server map cannot be empty");
RETURN_FALSE;
}
if (zforward_map && zend_hash_num_elements (Z_ARRVAL_P(zserver_map)) != zend_hash_num_elements (Z_ARRVAL_P(zforward_map))) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "forward_map length must match the server_map length");
+ php_error_docref(NULL, E_WARNING, "forward_map length must match the server_map length");
RETURN_FALSE;
}
if (replicas < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "replicas must be larger than zero");
+ php_error_docref(NULL, E_WARNING, "replicas must be larger than zero");
RETURN_FALSE;
}
- server_map = s_zval_to_uint32_array (zserver_map, &server_map_len TSRMLS_CC);
+ server_map = s_zval_to_uint32_array (zserver_map, &server_map_len);
if (!server_map) {
RETURN_FALSE;
}
if (zforward_map) {
- forward_map = s_zval_to_uint32_array (zforward_map, &forward_map_len TSRMLS_CC);
+ forward_map = s_zval_to_uint32_array (zforward_map, &forward_map_len);
if (!forward_map) {
efree (server_map);
@@ -2646,9 +3083,9 @@
}
}
- rc = memcached_bucket_set (m_obj->memc, server_map, forward_map, (uint32_t) server_map_len, replicas);
+ rc = memcached_bucket_set (intern->memc, server_map, forward_map, (uint32_t) server_map_len, replicas);
- if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) {
+ if (s_memc_status_handle_result_code(intern, rc) == FAILURE) {
retval = 0;;
}
@@ -2667,38 +3104,28 @@
{
zval *options;
zend_bool ok = 1;
- uint key_len;
- char *key;
+ zend_string *key;
ulong key_index;
- zval **value;
+ zval *value;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &options) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &options) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
- for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(options));
- zend_hash_get_current_data(Z_ARRVAL_P(options), (void *) &value) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(options))) {
-
- if (zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &key, &key_len, &key_index, 0, NULL) == HASH_KEY_IS_LONG) {
- zval copy = **value;
- zval_copy_ctor(©);
- INIT_PZVAL(©);
-
- if (!php_memc_set_option(i_obj, (long) key_index, © TSRMLS_CC)) {
+ ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), key_index, key, value) {
+ if (key) {
+ php_error_docref(NULL, E_WARNING, "invalid configuration option");
+ ok = 0;
+ } else {
+ if (!php_memc_set_option(intern, (long) key_index, value)) {
ok = 0;
}
-
- zval_dtor(©);
- } else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid configuration option");
- ok = 0;
}
- }
+ } ZEND_HASH_FOREACH_END();
RETURN_BOOL(ok);
}
@@ -2712,13 +3139,13 @@
zval *value;
MEMC_METHOD_INIT_VARS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz/", &option, &value) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/", &option, &value) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
- RETURN_BOOL(php_memc_set_option(i_obj, option, value TSRMLS_CC));
+ RETURN_BOOL(php_memc_set_option(intern, option, value));
}
/* }}} */
@@ -2729,29 +3156,26 @@
{
MEMC_METHOD_INIT_VARS;
memcached_return status;
+ zend_string *user, *pass;
- char *user, *pass;
- int user_len, pass_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &user, &user_len, &pass, &pass_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &user, &pass) == FAILURE) {
return;
}
- if (!MEMC_G(use_sasl)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "SASL support (memcached.use_sasl) isn't enabled in php.ini");
+ if (!php_memc_init_sasl_if_needed()) {
RETURN_FALSE;
}
MEMC_METHOD_FETCH_OBJECT;
- if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "SASL is only supported with binary protocol");
+ if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
+ php_error_docref(NULL, E_WARNING, "SASL is only supported with binary protocol");
RETURN_FALSE;
}
- m_obj->has_sasl_data = 1;
- status = memcached_set_sasl_auth_data(m_obj->memc, user, pass);
+ memc_user_data->has_sasl_data = 1;
+ status = memcached_set_sasl_auth_data(intern->memc, ZSTR_VAL(user), ZSTR_VAL(pass));
- if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
+ if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
RETURN_FALSE;
}
RETURN_TRUE;
@@ -2771,7 +3195,7 @@
MEMC_METHOD_FETCH_OBJECT;
- RETURN_LONG(i_obj->rescode);
+ RETURN_LONG(intern->rescode);
}
/* }}} */
@@ -2787,24 +3211,22 @@
MEMC_METHOD_FETCH_OBJECT;
- switch (i_obj->rescode) {
+ switch (intern->rescode) {
case MEMC_RES_PAYLOAD_FAILURE:
- RETURN_STRING("PAYLOAD FAILURE", 1);
+ RETURN_STRING("PAYLOAD FAILURE");
break;
case MEMCACHED_ERRNO:
case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
case MEMCACHED_UNKNOWN_READ_FAILURE:
- if (i_obj->memc_errno) {
- char *str;
- int str_len;
- str_len = spprintf(&str, 0, "%s: %s", memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode),
- strerror(i_obj->memc_errno));
- RETURN_STRINGL(str, str_len, 0);
+ if (intern->memc_errno) {
+ zend_string *str = strpprintf(0, "%s: %s",
+ memcached_strerror(intern->memc, (memcached_return)intern->rescode), strerror(intern->memc_errno));
+ RETURN_STR(str);
}
/* Fall through */
default:
- RETURN_STRING(memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode), 1);
+ RETURN_STRING(memcached_strerror(intern->memc, (memcached_return)intern->rescode));
break;
}
@@ -2823,7 +3245,7 @@
MEMC_METHOD_FETCH_OBJECT;
- RETURN_BOOL(i_obj->is_persistent);
+ RETURN_BOOL(memc_user_data->is_persistent);
}
/* }}} */
@@ -2839,7 +3261,7 @@
MEMC_METHOD_FETCH_OBJECT;
- RETURN_BOOL(i_obj->is_pristine);
+ RETURN_BOOL(intern->is_pristine);
}
/* }}} */
@@ -2847,516 +3269,198 @@
Internal support code
****************************************/
-/* {{{ constructor/destructor */
-static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS_DC)
-{
-#if HAVE_MEMCACHED_SASL
- if (m_obj->has_sasl_data) {
- memcached_destroy_sasl_auth_data(m_obj->memc);
- }
-#endif
- if (m_obj->memc) {
- memcached_free(m_obj->memc);
- }
-
- pefree(m_obj, persistent);
-}
-
-static void php_memc_free_storage(php_memc_t *i_obj TSRMLS_DC)
-{
- zend_object_std_dtor(&i_obj->zo TSRMLS_CC);
-
- if (i_obj->obj && !i_obj->is_persistent) {
- php_memc_destroy(i_obj->obj, 0 TSRMLS_CC);
- }
-
- i_obj->obj = NULL;
- efree(i_obj);
-}
-
-zend_object_value php_memc_new(zend_class_entry *ce TSRMLS_DC)
-{
- zend_object_value retval;
- php_memc_t *i_obj;
-
- i_obj = ecalloc(1, sizeof(*i_obj));
- zend_object_std_init( &i_obj->zo, ce TSRMLS_CC );
-#if PHP_VERSION_ID >= 50400
- object_properties_init( (zend_object *) i_obj, ce);
-#else
- {
- zval *tmp;
- zend_hash_copy(i_obj->zo.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
- }
-#endif
-
- retval.handle = zend_objects_store_put(i_obj, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_free_storage, NULL TSRMLS_CC);
- retval.handlers = &memcached_object_handlers;
-
- return retval;
-}
-
-#ifdef HAVE_MEMCACHED_PROTOCOL
-static
-void php_memc_server_free_storage(php_memc_server_t *intern TSRMLS_DC)
-{
- zend_object_std_dtor(&intern->zo TSRMLS_CC);
- efree (intern);
-}
-
-zend_object_value php_memc_server_new(zend_class_entry *ce TSRMLS_DC)
-{
- zend_object_value retval;
- php_memc_server_t *intern;
- zval *tmp;
-
- intern = ecalloc(1, sizeof(php_memc_server_t));
- zend_object_std_init (&intern->zo, ce TSRMLS_CC);
-#if PHP_VERSION_ID >= 50400
- object_properties_init( (zend_object *) intern, ce);
-#else
- zend_hash_copy(intern->zo.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
-#endif
-
- intern->handler = php_memc_proto_handler_new ();
-
- retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_server_free_storage, NULL TSRMLS_CC);
- retval.handlers = &memcached_server_object_handlers;
-
- return retval;
-}
-#endif
-
-ZEND_RSRC_DTOR_FUNC(php_memc_dtor)
-{
- if (rsrc->ptr) {
- struct memc_obj *m_obj = (struct memc_obj *)rsrc->ptr;
- php_memc_destroy(m_obj, 1 TSRMLS_CC);
- rsrc->ptr = NULL;
- }
-}
-
-ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor)
-{
- if (rsrc->ptr) {
- memcached_sess *memc_sess = (memcached_sess *)rsrc->ptr;
- memcached_free(memc_sess->memc_sess);
- pefree(rsrc->ptr, 1);
- rsrc->ptr = NULL;
- }
-}
-/* }}} */
-
-/* {{{ internal API functions */
-static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
-{
- struct callbackContext* context = (struct callbackContext*) in_context;
- zval *array;
-
- MAKE_STD_ZVAL(array);
- array_init(array);
- add_assoc_string(array, "host", (char*) memcached_server_name(instance), 1);
- add_assoc_long(array, "port", memcached_server_port(instance));
- /*
- * API does not allow to get at this field.
- add_assoc_long(array, "weight", instance->weight);
- */
-
- add_next_index_zval(context->return_value, array);
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
-{
- char *hostport = NULL;
- int hostport_len;
- struct callbackContext* context = (struct callbackContext*) in_context;
- zval *entry;
- hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance));
-
- MAKE_STD_ZVAL(entry);
- array_init(entry);
-
- add_assoc_long(entry, "pid", context->stats[context->i].pid);
- add_assoc_long(entry, "uptime", context->stats[context->i].uptime);
- add_assoc_long(entry, "threads", context->stats[context->i].threads);
- add_assoc_long(entry, "time", context->stats[context->i].time);
- add_assoc_long(entry, "pointer_size", context->stats[context->i].pointer_size);
- add_assoc_long(entry, "rusage_user_seconds", context->stats[context->i].rusage_user_seconds);
- add_assoc_long(entry, "rusage_user_microseconds", context->stats[context->i].rusage_user_microseconds);
- add_assoc_long(entry, "rusage_system_seconds", context->stats[context->i].rusage_system_seconds);
- add_assoc_long(entry, "rusage_system_microseconds", context->stats[context->i].rusage_system_microseconds);
- add_assoc_long(entry, "curr_items", context->stats[context->i].curr_items);
- add_assoc_long(entry, "total_items", context->stats[context->i].total_items);
- add_assoc_long(entry, "limit_maxbytes", context->stats[context->i].limit_maxbytes);
- add_assoc_long(entry, "curr_connections", context->stats[context->i].curr_connections);
- add_assoc_long(entry, "total_connections", context->stats[context->i].total_connections);
- add_assoc_long(entry, "connection_structures", context->stats[context->i].connection_structures);
- add_assoc_long(entry, "bytes", context->stats[context->i].bytes);
- add_assoc_long(entry, "cmd_get", context->stats[context->i].cmd_get);
- add_assoc_long(entry, "cmd_set", context->stats[context->i].cmd_set);
- add_assoc_long(entry, "get_hits", context->stats[context->i].get_hits);
- add_assoc_long(entry, "get_misses", context->stats[context->i].get_misses);
- add_assoc_long(entry, "evictions", context->stats[context->i].evictions);
- add_assoc_long(entry, "bytes_read", context->stats[context->i].bytes_read);
- add_assoc_long(entry, "bytes_written", context->stats[context->i].bytes_written);
- add_assoc_stringl(entry, "version", context->stats[context->i].version, strlen(context->stats[context->i].version), 1);
-
- add_assoc_zval_ex(context->return_value, hostport, hostport_len+1, entry);
- efree(hostport);
-
- /* Increment the server count in our context structure. Failure to do so will cause only the stats for the last server to get displayed. */
- context->i++;
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
-{
- char *hostport = NULL;
- char version[16];
- int hostport_len, version_len;
- struct callbackContext* context = (struct callbackContext*) in_context;
-
- hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance));
-#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009
- version_len = snprintf(version, sizeof(version), "%d.%d.%d",
- memcached_server_major_version(instance),
- memcached_server_minor_version(instance),
- memcached_server_micro_version(instance));
-#else
- version_len = snprintf(version, sizeof(version), "%d.%d.%d",
- instance->major_version,
- instance->minor_version,
- instance->micro_version);
-#endif
-
- add_assoc_stringl_ex(context->return_value, hostport, hostport_len+1, version, version_len, 1);
- efree(hostport);
- return MEMCACHED_SUCCESS;
-}
-
-static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status TSRMLS_DC)
-{
- int result = 0;
-
- switch (status) {
- case MEMCACHED_SUCCESS:
- case MEMCACHED_STORED:
- case MEMCACHED_DELETED:
- case MEMCACHED_STAT:
- result = 0;
- i_obj->memc_errno = 0;
- break;
-
- case MEMCACHED_END:
- case MEMCACHED_BUFFERED:
- i_obj->rescode = status;
- i_obj->memc_errno = 0;
- result = 0;
- break;
-
- case MEMCACHED_SOME_ERRORS:
- i_obj->rescode = status;
-#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
- i_obj->memc_errno = memcached_last_error_errno(i_obj->obj->memc);
-#else
- i_obj->memc_errno = i_obj->obj->memc->cached_errno; /* Hnngghgh! */
-
-#endif
- result = 0;
- break;
-
- default:
- i_obj->rescode = status;
-#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
- i_obj->memc_errno = memcached_last_error_errno(i_obj->obj->memc);
-#else
- i_obj->memc_errno = i_obj->obj->memc->cached_errno; /* Hnngghgh! */
-
-#endif
- result = -1;
- break;
- }
-
- return result;
-}
-
-static
-char *s_compress_value (enum memcached_compression_type compression_type, const char *payload, size_t *payload_len, uint32_t *flags TSRMLS_DC)
-{
- /* status */
- zend_bool compress_status = 0;
-
- /* Additional 5% for the data */
- size_t buffer_size = (size_t) (((double) *payload_len * 1.05) + 1.0);
- char *buffer = emalloc(sizeof(uint32_t) + buffer_size);
-
- /* Store compressed size here */
- size_t compressed_size = 0;
- uint32_t plen = *payload_len;
-
- /* Copy the uin32_t at the beginning */
- memcpy(buffer, &plen, sizeof(uint32_t));
- buffer += sizeof(uint32_t);
-
- switch (compression_type) {
-
- case COMPRESSION_TYPE_FASTLZ:
- compress_status = ((compressed_size = fastlz_compress(payload, *payload_len, buffer)) > 0);
- MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_FASTLZ);
- break;
-
- case COMPRESSION_TYPE_ZLIB:
- /* ZLIB returns the compressed size in this buffer */
- compressed_size = buffer_size;
-
- compress_status = (compress((Bytef *)buffer, &compressed_size, (Bytef *)payload, *payload_len) == Z_OK);
- MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_ZLIB);
- break;
-
- default:
- compress_status = 0;
- break;
- }
- buffer -= sizeof(uint32_t);
- *payload_len = compressed_size + sizeof(uint32_t);
-
- if (!compress_status) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not compress value");
- MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED);
-
- efree (buffer);
- *payload_len = 0;
- return NULL;
+/* {{{ constructor/destructor */
+static
+void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data)
+{
+#ifdef HAVE_MEMCACHED_SASL
+ if (memc_user_data->has_sasl_data) {
+ memcached_destroy_sasl_auth_data(memc);
}
+#endif
- else if (*payload_len > (compressed_size * MEMC_G(compression_factor))) {
- MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED);
- efree (buffer);
- *payload_len = 0;
- return NULL;
- }
- return buffer;
+ memcached_free(memc);
+ pefree(memc_user_data, memc_user_data->is_persistent);
}
static
-zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, smart_str *buf, uint32_t *flags TSRMLS_DC)
+void php_memc_object_free_storage(zend_object *object)
{
- switch (serializer) {
+ php_memc_object_t *intern = php_memc_fetch_object(object);
- /*
- Igbinary serialization
- */
-#ifdef HAVE_MEMCACHED_IGBINARY
- case SERIALIZER_IGBINARY:
- if (igbinary_serialize((uint8_t **) &buf->c, &buf->len, value TSRMLS_CC) != 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value with igbinary");
- return 0;
- }
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY);
- break;
-#endif
+ if (intern->memc) {
+ php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc);
- /*
- JSON serialization
- */
-#ifdef HAVE_JSON_API
- case SERIALIZER_JSON:
- case SERIALIZER_JSON_ARRAY:
- {
-#if HAVE_JSON_API_5_2
- php_json_encode(buf, value TSRMLS_CC);
-#elif HAVE_JSON_API_5_3
- php_json_encode(buf, value, 0 TSRMLS_CC); /* options */
-#endif
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON);
+ if (!memc_user_data->is_persistent) {
+ php_memc_destroy(intern->memc, memc_user_data);
}
- break;
-#endif
+ }
- /*
- msgpack serialization
- */
-#ifdef HAVE_MEMCACHED_MSGPACK
- case SERIALIZER_MSGPACK:
- php_msgpack_serialize(buf, value TSRMLS_CC);
- if (!buf->c) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value with msgpack");
- return 0;
- }
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_MSGPACK);
- break;
-#endif
+ intern->memc = NULL;
+ zend_object_std_dtor(&intern->zo);
+}
- /*
- PHP serialization
- */
- default:
- {
- php_serialize_data_t var_hash;
- PHP_VAR_SERIALIZE_INIT(var_hash);
- php_var_serialize(buf, &value, &var_hash TSRMLS_CC);
- PHP_VAR_SERIALIZE_DESTROY(var_hash);
+static
+zend_object *php_memc_object_new(zend_class_entry *ce)
+{
+ php_memc_object_t *intern = ecalloc(1, sizeof(php_memc_object_t) + zend_object_properties_size(ce));
- if (!buf->c) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value");
- return 0;
- }
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED);
- }
- break;
- }
+ zend_object_std_init(&intern->zo, ce);
+ object_properties_init(&intern->zo, ce);
- /* Check for exceptions caused by serializers */
- if (EG(exception) && buf->len) {
- return 0;
- }
- return 1;
+ intern->zo.handlers = &memcached_object_handlers;
+ return &intern->zo;
}
+#ifdef HAVE_MEMCACHED_PROTOCOL
static
-char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type TSRMLS_DC)
+void php_memc_server_free_storage(zend_object *object)
{
- const char *pl;
- size_t pl_len = 0;
-
- char *payload = NULL;
- smart_str buf = {0};
- char tmp[40] = {0};
+ php_memc_server_t *intern = php_memc_server_fetch_object(object);
+ zend_object_std_dtor(&intern->zo);
+}
- switch (Z_TYPE_P(value)) {
+zend_object *php_memc_server_new(zend_class_entry *ce)
+{
+ php_memc_server_t *intern;
- case IS_STRING:
- pl = Z_STRVAL_P(value);
- pl_len = Z_STRLEN_P(value);
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING);
- break;
+ intern = ecalloc(1, sizeof(php_memc_server_t) + zend_object_properties_size(ce));
- case IS_LONG:
- pl_len = sprintf(tmp, "%ld", Z_LVAL_P(value));
- pl = tmp;
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG);
- break;
+ zend_object_std_init(&intern->zo, ce);
+ object_properties_init(&intern->zo, ce);
- case IS_DOUBLE:
- php_memcached_g_fmt(tmp, Z_DVAL_P(value));
- pl = tmp;
- pl_len = strlen(tmp);
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE);
- break;
+ intern->zo.handlers = &memcached_server_object_handlers;
- case IS_BOOL:
- if (Z_BVAL_P(value)) {
- pl_len = 1;
- tmp[0] = '1';
- tmp[1] = '\0';
- } else {
- pl_len = 0;
- tmp[0] = '\0';
- }
- pl = tmp;
- MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL);
- break;
+ return &intern->zo;
+}
+#endif
- default:
- if (!s_serialize_value (serializer, value, &buf, flags TSRMLS_CC)) {
- smart_str_free (&buf);
- return NULL;
- }
- pl = buf.c;
- pl_len = buf.len;
- break;
+ZEND_RSRC_DTOR_FUNC(php_memc_dtor)
+{
+ if (res->ptr) {
+ memcached_st *memc = (memcached_st *) res->ptr;
+ php_memc_destroy(memc, memcached_get_user_data(memc));
+ res->ptr = NULL;
}
+}
- /* turn off compression for values below the threshold */
- if (MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED) && pl_len < MEMC_G(compression_threshold)) {
- MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED);
- }
+/* }}} */
- /* If we have compression flag, compress the value */
- if (MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED)) {
- /* status */
- *payload_len = pl_len;
- payload = s_compress_value (compression_type, pl, payload_len, flags TSRMLS_CC);
- }
+/* {{{ internal API functions */
+static
+memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
+{
+ zval array;
+ zval *return_value = (zval *) in_context;
- /* If compression failed or value is below threshold we just use plain value */
- if (!payload || !MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED)) {
- *payload_len = (uint32_t) pl_len;
- payload = estrndup(pl, pl_len);
- }
+ array_init(&array);
+ add_assoc_string(&array, "host", (char*)memcached_server_name(instance));
+ add_assoc_long(&array, "port", memcached_server_port(instance));
+ add_assoc_string(&array, "type", (char*)memcached_server_type(instance));
+ /*
+ * API does not allow to get at this field.
+ add_assoc_long(array, "weight", instance->weight);
+ */
- if (buf.len) {
- smart_str_free(&buf);
- }
- return payload;
+ add_next_index_zval(return_value, &array);
+ return MEMCACHED_SUCCESS;
}
static
-char *s_decompress_value (const char *payload, size_t *payload_len, uint32_t flags TSRMLS_DC)
+memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
{
- char *buffer = NULL;
- uint32_t len;
+ zend_string *address, *version;
+ zval rv, *return_value = (zval *)in_context;
+
+#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009
+ version = strpprintf(0, "%d.%d.%d",
+ memcached_server_major_version(instance),
+ memcached_server_minor_version(instance),
+ memcached_server_micro_version(instance));
+#else
+ version = strpprintf(0, "%d.%d.%d",
+ instance->major_version,
+ instance->minor_version,
+ instance->micro_version);
+#endif
+
+ address = strpprintf(0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1);
+
+ ZVAL_STR(&rv, version);
+ zend_hash_add(Z_ARRVAL_P(return_value), address, &rv);
+
+ zend_string_release(address);
+
+ return MEMCACHED_SUCCESS;
+}
+
+
+static
+zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32_t flags)
+{
+ zend_string *buffer;
+
+ uint32_t stored_length;
unsigned long length;
zend_bool decompress_status = 0;
+ zend_bool is_fastlz = 0, is_zlib = 0;
- /* Stored with newer memcached extension? */
- if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_FASTLZ) || MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZLIB)) {
- /* This is copied from Ilia's patch */
- memcpy(&len, payload, sizeof(uint32_t));
- buffer = emalloc(len + 1);
- *payload_len -= sizeof(uint32_t);
- payload += sizeof(uint32_t);
- length = len;
-
- if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_FASTLZ)) {
- decompress_status = ((length = fastlz_decompress(payload, *payload_len, buffer, len)) > 0);
- } else if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZLIB)) {
- decompress_status = (uncompress((Bytef *)buffer, &length, (Bytef *)payload, *payload_len) == Z_OK);
- }
+ if (payload_len < sizeof (uint32_t)) {
+ return NULL;
}
- /* Fall back to 'old style decompression' */
- if (!decompress_status) {
- unsigned int factor = 1, maxfactor = 16;
- int status;
+ is_fastlz = MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_FASTLZ);
+ is_zlib = MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZLIB);
+
+ if (!is_fastlz && !is_zlib) {
+ php_error_docref(NULL, E_WARNING, "could not decompress value: unrecognised encryption type");
+ return NULL;
+ }
- do {
- length = (unsigned long)*payload_len * (1 << factor++);
- buffer = erealloc(buffer, length + 1);
- memset(buffer, 0, length + 1);
- status = uncompress((Bytef *)buffer, (uLongf *)&length, (const Bytef *)payload, *payload_len);
- } while ((status==Z_BUF_ERROR) && (factor < maxfactor));
+ memcpy(&stored_length, payload, sizeof (uint32_t));
- if (status == Z_OK) {
- decompress_status = 1;
- }
+ payload += sizeof (uint32_t);
+ payload_len -= sizeof (uint32_t);
+
+ buffer = zend_string_alloc (stored_length, 0);
+
+ if (is_fastlz) {
+ decompress_status = ((length = fastlz_decompress(payload, payload_len, &buffer->val, buffer->len)) > 0);
+ }
+ else if (is_zlib) {
+ decompress_status = (uncompress((Bytef *) buffer->val, &buffer->len, (Bytef *)payload, payload_len) == Z_OK);
}
+ ZSTR_VAL(buffer)[stored_length] = '\0';
+
if (!decompress_status) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not decompress value");
- efree(buffer);
+ php_error_docref(NULL, E_WARNING, "could not decompress value");
+ zend_string_release (buffer);
return NULL;
}
- buffer [length] = '\0';
- *payload_len = length;
+
+ zend_string_forget_hash_val(buffer);
return buffer;
}
static
-zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_type, zval *value, const char *payload, size_t payload_len TSRMLS_DC)
+zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *payload, zval *return_value)
{
switch (val_type) {
case MEMC_VAL_IS_SERIALIZED:
{
- const char *payload_tmp = payload;
php_unserialize_data_t var_hash;
+ const unsigned char *p, *max;
+
+ p = (const unsigned char *) ZSTR_VAL(payload);
+ max = p + ZSTR_LEN(payload);
PHP_VAR_UNSERIALIZE_INIT(var_hash);
- if (!php_var_unserialize(&value, (const unsigned char **)&payload_tmp, (const unsigned char *)payload_tmp + payload_len, &var_hash TSRMLS_CC)) {
- ZVAL_FALSE(value);
+ if (!php_var_unserialize(return_value, &p, max, &var_hash)) {
+ zval_ptr_dtor(return_value);
+ ZVAL_FALSE(return_value);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value");
+ php_error_docref(NULL, E_WARNING, "could not unserialize value");
return 0;
}
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
@@ -3365,38 +3469,37 @@
case MEMC_VAL_IS_IGBINARY:
#ifdef HAVE_MEMCACHED_IGBINARY
- if (igbinary_unserialize((uint8_t *)payload, payload_len, &value TSRMLS_CC)) {
- ZVAL_FALSE(value);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value with igbinary");
+ if (igbinary_unserialize((uint8_t *) ZSTR_VAL(payload), ZSTR_LEN(payload), return_value)) {
+ ZVAL_FALSE(return_value);
+ php_error_docref(NULL, E_WARNING, "could not unserialize value with igbinary");
return 0;
}
#else
- ZVAL_FALSE(value);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support");
+ ZVAL_FALSE(return_value);
+ php_error_docref(NULL, E_WARNING, "could not unserialize value, no igbinary support");
return 0;
#endif
break;
case MEMC_VAL_IS_JSON:
#ifdef HAVE_JSON_API
-# if HAVE_JSON_API_5_2
- php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY) TSRMLS_CC);
-# elif HAVE_JSON_API_5_3
- php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH TSRMLS_CC);
-# endif
+ {
+ php_memc_user_data_t *memc_user_data = memcached_get_user_data(memc);
+ php_json_decode(return_value, ZSTR_VAL(payload), ZSTR_LEN(payload), (memc_user_data->serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH);
+ }
#else
- ZVAL_FALSE(value);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no json support");
+ ZVAL_FALSE(return_value);
+ php_error_docref(NULL, E_WARNING, "could not unserialize value, no json support");
return 0;
#endif
break;
- case MEMC_VAL_IS_MSGPACK:
+ case MEMC_VAL_IS_MSGPACK:
#ifdef HAVE_MEMCACHED_MSGPACK
- php_msgpack_unserialize(value, payload, payload_len TSRMLS_CC);
+ php_msgpack_unserialize(return_value, ZSTR_VAL(payload), ZSTR_LEN(payload));
#else
- ZVAL_FALSE(value);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no msgpack support");
+ ZVAL_FALSE(return_value);
+ php_error_docref(NULL, E_WARNING, "could not unserialize value, no msgpack support");
return 0;
#endif
break;
@@ -3404,122 +3507,81 @@
return 1;
}
-/* The caller MUST free the payload */
-static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC)
+static
+zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *result, zval *return_value)
{
- /*
- A NULL payload is completely valid if length is 0, it is simply empty.
- */
- int retval = 0;
- zend_bool payload_emalloc = 0;
- char *pl = NULL;
-
- if (payload_in == NULL && payload_len > 0) {
- ZVAL_FALSE(value);
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "Could not handle non-existing value of length %zu", payload_len);
- return -1;
- } else if (payload_in == NULL) {
- if (MEMC_VAL_GET_TYPE(flags) == MEMC_VAL_IS_BOOL) {
- ZVAL_FALSE(value);
- } else {
- ZVAL_EMPTY_STRING(value);
- }
+ zend_string *data;
+ const char *payload;
+ size_t payload_len;
+ uint32_t flags;
+ zend_bool retval = 1;
+
+ payload = memcached_result_value(result);
+ payload_len = memcached_result_length(result);
+ flags = memcached_result_flags(result);
+
+ if (!payload && payload_len > 0) {
+ php_error_docref(NULL, E_WARNING, "Could not handle non-existing value of length %zu", payload_len);
return 0;
}
if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSED)) {
- char *datas = s_decompress_value (payload_in, &payload_len, flags TSRMLS_CC);
- if (!datas) {
- ZVAL_FALSE(value);
- return -1;
+ data = s_decompress_value (payload, payload_len, flags);
+ if (!data) {
+ return 0;
}
- pl = datas;
- payload_emalloc = 1;
} else {
- pl = (char *) payload_in;
+ data = zend_string_init(payload, payload_len, 0);
}
switch (MEMC_VAL_GET_TYPE(flags)) {
+
case MEMC_VAL_IS_STRING:
- if (payload_emalloc) {
- ZVAL_STRINGL(value, pl, payload_len, 0);
- payload_emalloc = 0;
- } else {
- ZVAL_STRINGL(value, pl, payload_len, 1);
- }
+ ZVAL_STR_COPY(return_value, data);
break;
case MEMC_VAL_IS_LONG:
- {
- long lval;
- char conv_buf [128];
-
- if (payload_len >= 128) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not read long value, too big");
- retval = -1;
- }
- else {
- memcpy (conv_buf, pl, payload_len);
- conv_buf [payload_len] = '\0';
-
- lval = strtol(conv_buf, NULL, 10);
- ZVAL_LONG(value, lval);
- }
- }
+ ZVAL_LONG(return_value, strtol(ZSTR_VAL(data), NULL, 10));
break;
case MEMC_VAL_IS_DOUBLE:
{
- char conv_buf [128];
-
- if (payload_len >= 128) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not read double value, too big");
- retval = -1;
+ if (zend_string_equals_literal(data, "Infinity")) {
+ ZVAL_DOUBLE(return_value, php_get_inf());
+ }
+ else if (zend_string_equals_literal(data, "-Infinity")) {
+ ZVAL_DOUBLE(return_value, -php_get_inf());
+ }
+ else if (zend_string_equals_literal(data, "NaN")) {
+ ZVAL_DOUBLE(return_value, php_get_nan());
}
else {
- memcpy (conv_buf, pl, payload_len);
- conv_buf [payload_len] = '\0';
-
- if (payload_len == 8 && memcmp(conv_buf, "Infinity", 8) == 0) {
- ZVAL_DOUBLE(value, php_get_inf());
- } else if (payload_len == 9 && memcmp(conv_buf, "-Infinity", 9) == 0) {
- ZVAL_DOUBLE(value, -php_get_inf());
- } else if (payload_len == 3 && memcmp(conv_buf, "NaN", 3) == 0) {
- ZVAL_DOUBLE(value, php_get_nan());
- } else {
- ZVAL_DOUBLE(value, zend_strtod(conv_buf, NULL));
- }
+ ZVAL_DOUBLE(return_value, zend_strtod(ZSTR_VAL(data), NULL));
}
}
break;
case MEMC_VAL_IS_BOOL:
- ZVAL_BOOL(value, payload_len > 0 && pl[0] == '1');
+ ZVAL_BOOL(return_value, payload_len > 0 && ZSTR_VAL(data)[0] == '1');
break;
case MEMC_VAL_IS_SERIALIZED:
case MEMC_VAL_IS_IGBINARY:
case MEMC_VAL_IS_JSON:
case MEMC_VAL_IS_MSGPACK:
- if (!s_unserialize_value (serializer, MEMC_VAL_GET_TYPE(flags), value, pl, payload_len TSRMLS_CC)) {
- retval = -1;
- }
+ retval = s_unserialize_value (memc, MEMC_VAL_GET_TYPE(flags), data, return_value);
break;
default:
- ZVAL_FALSE(value);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown payload type");
- retval = -1;
+ php_error_docref(NULL, E_WARNING, "unknown payload type");
break;
}
+ zend_string_release(data);
- if (payload_emalloc) {
- efree(pl);
- }
return retval;
}
+
PHP_MEMCACHED_API
zend_class_entry *php_memc_get_ce(void)
{
@@ -3533,175 +3595,29 @@
}
PHP_MEMCACHED_API
-zend_class_entry *php_memc_get_exception_base(int root TSRMLS_DC)
+zend_class_entry *php_memc_get_exception_base(int root)
{
-#if HAVE_SPL
+#ifdef HAVE_SPL
if (!root) {
if (!spl_ce_RuntimeException) {
- zend_class_entry **pce;
+ zend_class_entry *pce;
+ zval *pce_z;
- if (zend_hash_find(CG(class_table), "runtimeexception",
- sizeof("RuntimeException"), (void **) &pce) == SUCCESS) {
- spl_ce_RuntimeException = *pce;
- return *pce;
+ if ((pce_z = zend_hash_str_find(CG(class_table),
+ "runtimeexception",
+ sizeof("RuntimeException") - 1)) != NULL) {
+ pce = Z_CE_P(pce_z);
+ spl_ce_RuntimeException = pce;
+ return pce;
}
} else {
return spl_ce_RuntimeException;
}
}
#endif
-#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 2)
return zend_exception_get_default();
-#else
- return zend_exception_get_default(TSRMLS_C);
-#endif
-}
-
-static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_info *fci,
- zend_fcall_info_cache *fcc, char *key,
- size_t key_len, zval *value TSRMLS_DC)
-{
- char *payload = NULL;
- size_t payload_len = 0;
- zval **params[4];
- zval *retval;
- zval *z_key;
- zval *z_expiration;
-
- uint32_t flags = 0;
- memcached_return rc;
- php_memc_t* i_obj;
- memcached_return status = MEMCACHED_SUCCESS;
- int result;
-
- MAKE_STD_ZVAL(z_key);
- MAKE_STD_ZVAL(z_expiration);
- ZVAL_STRINGL(z_key, key, key_len, 1);
- ZVAL_NULL(value);
- ZVAL_LONG(z_expiration, 0);
-
- params[0] = &zmemc_obj;
- params[1] = &z_key;
- params[2] = &value;
- params[3] = &z_expiration;
-
- fci->retval_ptr_ptr = &retval;
- fci->params = params;
- fci->param_count = sizeof(params) / sizeof(params[0]);
-
- result = zend_call_function(fci, fcc TSRMLS_CC);
- if (result == SUCCESS && retval) {
- i_obj = (php_memc_t *) zend_object_store_get_object(zmemc_obj TSRMLS_CC);
- struct memc_obj *m_obj = i_obj->obj;
-
- if (zend_is_true(retval)) {
- time_t expiration;
-
- if (Z_TYPE_P(z_expiration) != IS_LONG) {
- convert_to_long(z_expiration);
- }
-
- expiration = Z_LVAL_P(z_expiration);
-
- payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
- if (payload == NULL) {
- status = (memcached_return)MEMC_RES_PAYLOAD_FAILURE;
- } else {
- rc = memcached_set(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
- if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) {
- status = rc;
- }
- efree(payload);
- }
- } else {
- status = MEMCACHED_NOTFOUND;
- zval_dtor(value);
- ZVAL_NULL(value);
- }
-
- } else {
- if (result == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not invoke cache callback");
- }
- status = MEMCACHED_FAILURE;
- zval_dtor(value);
- ZVAL_NULL(value);
- }
-
- if (retval) {
- zval_ptr_dtor(&retval);
- }
-
- zval_ptr_dtor(&z_key);
- zval_ptr_dtor(&z_expiration);
-
- return status;
}
-static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci,
- zend_fcall_info_cache *fcc,
- memcached_result_st *result TSRMLS_DC)
-{
- const char *res_key = NULL;
- size_t res_key_len = 0;
- const char *payload = NULL;
- size_t payload_len = 0;
- zval *value, *retval = NULL;
- uint64_t cas = 0;
- zval **params[2];
- zval *z_result;
- uint32_t flags = 0;
- int rc = 0;
- php_memc_t *i_obj = NULL;
-
- params[0] = &zmemc_obj;
- params[1] = &z_result;
-
- fci->retval_ptr_ptr = &retval;
- fci->params = params;
- fci->param_count = 2;
-
- payload = memcached_result_value(result);
- payload_len = memcached_result_length(result);
- flags = memcached_result_flags(result);
- res_key = memcached_result_key_value(result);
- res_key_len = memcached_result_key_length(result);
- cas = memcached_result_cas(result);
-
- ALLOC_INIT_ZVAL(value);
-
- i_obj = (php_memc_t *) zend_object_store_get_object(zmemc_obj TSRMLS_CC);
-
- if (php_memc_zval_from_payload(value, payload, payload_len, flags, i_obj->obj->serializer TSRMLS_CC) < 0) {
- zval_ptr_dtor(&value);
- i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
- return -1;
- }
-
- MAKE_STD_ZVAL(z_result);
- array_init(z_result);
- add_assoc_stringl_ex(z_result, ZEND_STRS("key"), res_key, res_key_len, 1);
- add_assoc_zval_ex(z_result, ZEND_STRS("value"), value);
- if (cas != 0) {
- add_assoc_double_ex(z_result, ZEND_STRS("cas"), (double)cas);
- }
- if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) {
- add_assoc_long_ex(z_result, ZEND_STRS("flags"), MEMC_VAL_GET_USER_FLAGS(flags));
- }
-
- if (zend_call_function(fci, fcc TSRMLS_CC) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not invoke result callback");
- rc = -1;
- }
-
- if (retval) {
- zval_ptr_dtor(&retval);
- }
- zval_ptr_dtor(&z_result);
-
- return rc;
-}
-/* }}} */
#ifdef HAVE_MEMCACHED_PROTOCOL
@@ -3710,8 +3626,8 @@
{
if (fci->size > 0) {
zval_ptr_dtor(&fci->function_name);
- if (fci->object_ptr != NULL) {
- zval_ptr_dtor(&fci->object_ptr);
+ if (fci->object) {
+ OBJ_RELEASE(fci->object);
}
}
}
@@ -3721,20 +3637,19 @@
{
int i;
zend_bool rc;
- char *address;
- int address_len;
+ zend_string *address;
php_memc_server_t *intern;
- intern = (php_memc_server_t *) zend_object_store_get_object(getThis() TSRMLS_CC);
+ intern = Z_MEMC_SERVER_P(getThis());
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &address, &address_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &address) == FAILURE) {
return;
}
- rc = php_memc_proto_handler_run (intern->handler, address);
+ rc = php_memc_proto_handler_run(intern->handler, address);
for (i = MEMC_SERVER_ON_MIN + 1; i < MEMC_SERVER_ON_MAX; i++) {
- s_destroy_cb (&MEMC_G(server.callbacks) [i].fci);
+ s_destroy_cb(&MEMC_SERVER_G(callbacks) [i].fci);
}
RETURN_BOOL(rc);
@@ -3748,7 +3663,7 @@
zend_fcall_info_cache fci_cache;
zend_bool rc = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lf!", &event, &fci, &fci_cache) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "lf!", &event, &fci, &fci_cache) == FAILURE) {
return;
}
@@ -3757,14 +3672,14 @@
}
if (fci.size > 0) {
- s_destroy_cb (&MEMC_G(server.callbacks) [event].fci);
+ s_destroy_cb (&MEMC_SERVER_G(callbacks) [event].fci);
- MEMC_G(server.callbacks) [event].fci = fci;
- MEMC_G(server.callbacks) [event].fci_cache = fci_cache;
+ MEMC_SERVER_G(callbacks) [event].fci = fci;
+ MEMC_SERVER_G(callbacks) [event].fci_cache = fci_cache;
- Z_ADDREF_P (fci.function_name);
- if (fci.object_ptr) {
- Z_ADDREF_P (fci.object_ptr);
+ Z_TRY_ADDREF(fci.function_name);
+ if (fci.object) {
+ GC_REFCOUNT(fci.object)++;
}
}
RETURN_BOOL(rc);
@@ -3787,31 +3702,25 @@
ZEND_BEGIN_ARG_INFO_EX(arginfo_get, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, cache_cb)
- ZEND_ARG_INFO(2, cas_token)
- ZEND_ARG_INFO(1, udf_flags)
+ ZEND_ARG_INFO(0, get_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_getByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, cache_cb)
- ZEND_ARG_INFO(2, cas_token)
- ZEND_ARG_INFO(1, udf_flags)
+ ZEND_ARG_INFO(0, get_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_getMulti, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, keys, 0)
- ZEND_ARG_INFO(2, cas_tokens)
- ZEND_ARG_INFO(0, flags)
- ZEND_ARG_INFO(1, udf_flags)
+ ZEND_ARG_INFO(0, get_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_getMultiByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_ARRAY_INFO(0, keys, 0)
- ZEND_ARG_INFO(2, cas_tokens)
- ZEND_ARG_INFO(0, flags)
- ZEND_ARG_INFO(1, udf_flags)
+ ZEND_ARG_INFO(0, get_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_getDelayed, 0, 0, 1)
@@ -3837,7 +3746,6 @@
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_setByKey, 0, 0, 3)
@@ -3845,7 +3753,6 @@
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_touch, 0, 0, 2)
@@ -3862,21 +3769,18 @@
ZEND_BEGIN_ARG_INFO_EX(arginfo_setMulti, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, items, 0)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_setMultiByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_ARRAY_INFO(0, items, 0)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_add, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_addByKey, 0, 0, 3)
@@ -3884,14 +3788,12 @@
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_replace, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_replaceByKey, 0, 0, 3)
@@ -3899,7 +3801,6 @@
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_append, 0, 0, 2)
@@ -3933,7 +3834,6 @@
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_casByKey, 0, 0, 4)
@@ -3942,7 +3842,6 @@
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
- ZEND_ARG_INFO(0, udf_flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_delete, 0, 0, 1)
@@ -4151,7 +4050,7 @@
MEMC_ME(setOptions, arginfo_setOptions)
MEMC_ME(setBucket, arginfo_setBucket)
#ifdef HAVE_MEMCACHED_SASL
- MEMC_ME(setSaslAuthData, arginfo_setSaslAuthData)
+ MEMC_ME(setSaslAuthData, arginfo_setSaslAuthData)
#endif
MEMC_ME(isPersistent, arginfo_isPersistent)
MEMC_ME(isPristine, arginfo_isPristine)
@@ -4198,39 +4097,45 @@
PHP_GINIT_FUNCTION(php_memcached)
{
#ifdef HAVE_MEMCACHED_SESSION
- php_memcached_globals->sess_locking_enabled = 1;
- php_memcached_globals->sess_binary_enabled = 1;
- php_memcached_globals->sess_consistent_hash_enabled = 0;
- php_memcached_globals->sess_number_of_replicas = 0;
- php_memcached_globals->sess_remove_failed_enabled = 0;
- php_memcached_globals->sess_prefix = NULL;
- php_memcached_globals->sess_lock_wait = 0;
- php_memcached_globals->sess_lock_max_wait = 0;
- php_memcached_globals->sess_lock_expire = 0;
- php_memcached_globals->sess_locked = 0;
- php_memcached_globals->sess_lock_key = NULL;
- php_memcached_globals->sess_lock_key_len = 0;
- php_memcached_globals->sess_randomize_replica_read = 0;
- php_memcached_globals->sess_connect_timeout = 1000;
-#if HAVE_MEMCACHED_SASL
- php_memcached_globals->sess_sasl_username = NULL;
- php_memcached_globals->sess_sasl_password = NULL;
- php_memcached_globals->sess_sasl_data = 0;
-#endif
-#endif
- php_memcached_globals->serializer_name = NULL;
- php_memcached_globals->serializer = SERIALIZER_DEFAULT;
- php_memcached_globals->compression_type = NULL;
- php_memcached_globals->compression_type_real = COMPRESSION_TYPE_FASTLZ;
- php_memcached_globals->compression_factor = 1.30;
-#if HAVE_MEMCACHED_SASL
- php_memcached_globals->use_sasl = 0;
-#endif
- php_memcached_globals->store_retry_count = 2;
+
+ php_memcached_globals->session.lock_enabled = 0;
+ php_memcached_globals->session.lock_wait_max = 2000;
+ php_memcached_globals->session.lock_wait_min = 1000;
+ php_memcached_globals->session.lock_retries = 5;
+ php_memcached_globals->session.lock_expiration = 30;
+ php_memcached_globals->session.binary_protocol_enabled = 1;
+ php_memcached_globals->session.consistent_hash_enabled = 1;
+ php_memcached_globals->session.number_of_replicas = 0;
+ php_memcached_globals->session.server_failure_limit = 1;
+ php_memcached_globals->session.randomize_replica_read_enabled = 1;
+ php_memcached_globals->session.remove_failed_servers_enabled = 1;
+ php_memcached_globals->session.connect_timeout = 1000;
+ php_memcached_globals->session.prefix = NULL;
+ php_memcached_globals->session.persistent_enabled = 0;
+ php_memcached_globals->session.sasl_username = NULL;
+ php_memcached_globals->session.sasl_password = NULL;
+
+#endif
+ php_memcached_globals->memc.serializer_name = NULL;
+ php_memcached_globals->memc.serializer_type = SERIALIZER_DEFAULT;
+ php_memcached_globals->memc.compression_name = NULL;
+ php_memcached_globals->memc.compression_threshold = 2000;
+ php_memcached_globals->memc.compression_type = COMPRESSION_TYPE_FASTLZ;
+ php_memcached_globals->memc.compression_factor = 1.30;
+ php_memcached_globals->memc.store_retry_count = 2;
+
+ php_memcached_globals->memc.sasl_initialised = 0;
+ php_memcached_globals->no_effect = 0;
+
+ /* Defaults for certain options */
+ php_memcached_globals->memc.default_behavior.consistent_hash_enabled = 0;
+ php_memcached_globals->memc.default_behavior.binary_protocol_enabled = 0;
+ php_memcached_globals->memc.default_behavior.connect_timeout = 0;
}
zend_module_entry memcached_module_entry = {
- STANDARD_MODULE_HEADER,
+ STANDARD_MODULE_HEADER_EX, NULL,
+ memcached_deps,
"memcached",
NULL,
PHP_MINIT(memcached),
@@ -4247,12 +4152,13 @@
};
/* }}} */
+
/* {{{ php_memc_register_constants */
static void php_memc_register_constants(INIT_FUNC_ARGS)
{
- #define REGISTER_MEMC_CLASS_CONST_LONG(name, value) zend_declare_class_constant_long(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value TSRMLS_CC)
- #define REGISTER_MEMC_CLASS_CONST_BOOL(name, value) zend_declare_class_constant_bool(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value TSRMLS_CC)
- #define REGISTER_MEMC_CLASS_CONST_NULL(name) zend_declare_class_constant_null(php_memc_get_ce() , ZEND_STRS( #name ) - 1 TSRMLS_CC)
+ #define REGISTER_MEMC_CLASS_CONST_LONG(name, value) zend_declare_class_constant_long(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value)
+ #define REGISTER_MEMC_CLASS_CONST_BOOL(name, value) zend_declare_class_constant_bool(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value)
+ #define REGISTER_MEMC_CLASS_CONST_NULL(name) zend_declare_class_constant_null(php_memc_get_ce() , ZEND_STRS( #name ) - 1)
/*
* Class options
@@ -4263,6 +4169,8 @@
REGISTER_MEMC_CLASS_CONST_LONG(OPT_COMPRESSION_TYPE, MEMC_OPT_COMPRESSION_TYPE);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_PREFIX_KEY, MEMC_OPT_PREFIX_KEY);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERIALIZER, MEMC_OPT_SERIALIZER);
+
+ REGISTER_MEMC_CLASS_CONST_LONG(OPT_USER_FLAGS, MEMC_OPT_USER_FLAGS);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_STORE_RETRY_COUNT, MEMC_OPT_STORE_RETRY_COUNT);
/*
@@ -4283,9 +4191,9 @@
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_JSON, 0);
#endif
- /*
- * Indicate whether msgpack serializer is available
- */
+ /*
+ * Indicate whether msgpack serializer is available
+ */
#ifdef HAVE_MEMCACHED_MSGPACK
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_MSGPACK, 1);
#else
@@ -4395,7 +4303,6 @@
REGISTER_MEMC_CLASS_CONST_LONG(RES_MEMORY_ALLOCATION_FAILURE, MEMCACHED_MEMORY_ALLOCATION_FAILURE);
REGISTER_MEMC_CLASS_CONST_LONG(RES_CONNECTION_SOCKET_CREATE_FAILURE, MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE);
- REGISTER_MEMC_CLASS_CONST_LONG(RES_BAD_KEY_PROVIDED, MEMCACHED_BAD_KEY_PROVIDED);
REGISTER_MEMC_CLASS_CONST_LONG(RES_E2BIG, MEMCACHED_E2BIG);
REGISTER_MEMC_CLASS_CONST_LONG(RES_KEY_TOO_BIG, MEMCACHED_KEY_TOO_BIG);
REGISTER_MEMC_CLASS_CONST_LONG(RES_SERVER_TEMPORARILY_DISABLED, MEMCACHED_SERVER_TEMPORARILY_DISABLED);
@@ -4404,7 +4311,7 @@
REGISTER_MEMC_CLASS_CONST_LONG(RES_SERVER_MEMORY_ALLOCATION_FAILURE, MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE);
#endif
-#if HAVE_MEMCACHED_SASL
+#ifdef HAVE_MEMCACHED_SASL
REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_PROBLEM, MEMCACHED_AUTH_PROBLEM);
REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_FAILURE, MEMCACHED_AUTH_FAILURE);
REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_CONTINUE, MEMCACHED_AUTH_CONTINUE);
@@ -4419,11 +4326,11 @@
/*
* Serializer types.
*/
- REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP);
- REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY);
- REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON);
+ REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP);
+ REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY);
+ REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON);
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON_ARRAY, SERIALIZER_JSON_ARRAY);
- REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_MSGPACK, SERIALIZER_MSGPACK);
+ REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_MSGPACK, SERIALIZER_MSGPACK);
/*
* Compression types
@@ -4435,6 +4342,7 @@
* Flags.
*/
REGISTER_MEMC_CLASS_CONST_LONG(GET_PRESERVE_ORDER, MEMC_GET_PRESERVE_ORDER);
+ REGISTER_MEMC_CLASS_CONST_LONG(GET_EXTENDED, MEMC_GET_EXTENDED);
#ifdef HAVE_MEMCACHED_PROTOCOL
/*
@@ -4483,55 +4391,44 @@
}
/* }}} */
-int php_memc_sess_list_entry(void)
-{
- return le_memc_sess;
-}
-
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(memcached)
{
zend_class_entry ce;
memcpy(&memcached_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ memcached_object_handlers.offset = XtOffsetOf(php_memc_object_t, zo);
memcached_object_handlers.clone_obj = NULL;
+ memcached_object_handlers.free_obj = php_memc_object_free_storage;
le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number);
- le_memc_sess = zend_register_list_destructors_ex(NULL, php_memc_sess_dtor, "Memcached Sessions persistent connection", module_number);
INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_methods);
- memcached_ce = zend_register_internal_class(&ce TSRMLS_CC);
- memcached_ce->create_object = php_memc_new;
+ memcached_ce = zend_register_internal_class(&ce);
+ memcached_ce->create_object = php_memc_object_new;
#ifdef HAVE_MEMCACHED_PROTOCOL
memcpy(&memcached_server_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ memcached_server_object_handlers.offset = XtOffsetOf(php_memc_server_t, zo);
memcached_server_object_handlers.clone_obj = NULL;
+ memcached_server_object_handlers.free_obj = php_memc_server_free_storage;
INIT_CLASS_ENTRY(ce, "MemcachedServer", memcached_server_class_methods);
- memcached_server_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ memcached_server_ce = zend_register_internal_class(&ce);
memcached_server_ce->create_object = php_memc_server_new;
#endif
INIT_CLASS_ENTRY(ce, "MemcachedException", NULL);
- memcached_exception_ce = zend_register_internal_class_ex(&ce, php_memc_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC);
+ memcached_exception_ce = zend_register_internal_class_ex(&ce, php_memc_get_exception_base(0));
/* TODO
* possibly declare custom exception property here
*/
php_memc_register_constants(INIT_FUNC_ARGS_PASSTHRU);
+ REGISTER_INI_ENTRIES();
#ifdef HAVE_MEMCACHED_SESSION
- php_session_register_module(ps_memcached_ptr);
-#endif
-
- REGISTER_INI_ENTRIES();
-#if HAVE_MEMCACHED_SASL
- if (MEMC_G(use_sasl)) {
- if (sasl_client_init(NULL) != SASL_OK) {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize SASL library");
- return FAILURE;
- }
- }
+ php_memc_session_minit(module_number);
#endif
return SUCCESS;
}
@@ -4540,8 +4437,8 @@
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(memcached)
{
-#if HAVE_MEMCACHED_SASL
- if (MEMC_G(use_sasl)) {
+#ifdef HAVE_MEMCACHED_SASL
+ if (MEMC_G(sasl_initialised)) {
sasl_done();
}
#endif
@@ -4559,7 +4456,7 @@
php_info_print_table_row(2, "Version", PHP_MEMCACHED_VERSION);
php_info_print_table_row(2, "libmemcached version", memcached_lib_version());
-#if HAVE_MEMCACHED_SASL
+#ifdef HAVE_MEMCACHED_SASL
php_info_print_table_row(2, "SASL support", "yes");
#else
php_info_print_table_row(2, "SASL support", "no");
|