package.xml0000644000076500000240000000723211530776271013063 0ustar mkoppanenstaff tokyo_tyrant pecl.php.net Provides a wrapper to the Tokyo Tyrant client library. tokyo_tyrant extension provides object oriented API for communicating with Tokyo Tyrant key-value store. This extension requires Tokyo Cabinet, Tokyo Tyrant and PHP version 5.2.0+. Mikko Koppanen mkoppanen mkoppanen@php.net yes 2011-02-22 0.6.0 0.6.0 beta beta PHP License - Fixes PECL Bug #18005 - Fixes PECL Bug #18344 - Fix memory allocation error - Binary safety fixes (Isamu Arimoto) - TokyoTyrantTable::put cuts integer key of 2nd argment array. (Isamu Arimoto) 5.2.0 1.4.0 tokyo_tyrant tokyo_tyrant-0.6.0/config.m40000644000076500000240000001020011530776271015647 0ustar mkoppanenstaffPHP_ARG_WITH(tokyo-tyrant, whether to enable tokyo tyrant support, [ --with-tokyo-tyrant[=DIR] Enable tokyo tyrant support. DIR is the prefix to Tokyo Tyrant installation directory.], yes) PHP_ARG_WITH(tokyo-cabinet-dir, directory of the Tokyo Cabinet installation, [ --with-tokyo-cabinet-dir[=DIR] DIR is the prefix to Tokyo Cabinet installation directory.], yes) PHP_ARG_ENABLE(tokyo-tyrant-session, whether to enable tokyo tyrant session handler support, [ --disable-tokyo-tyrant-session Disables tokyo tyrant session handler support], yes, no) if test "$PHP_TOKYO_TYRANT" != "no"; then dnl Check PHP version dnl Get PHP version depending on shared/static build AC_MSG_CHECKING([PHP version is at least 5.2.0]) if test -z "${PHP_VERSION_ID}"; then if test -z "${PHP_CONFIG}"; then AC_MSG_ERROR([php-config not found]) fi PHP_TT_FOUND_VERNUM=`${PHP_CONFIG} --vernum`; PHP_TT_FOUND_VERSION=`${PHP_CONFIG} --version` else PHP_TT_FOUND_VERNUM="${PHP_VERSION_ID}" PHP_TT_FOUND_VERSION="${PHP_VERSION}" fi if test "$PHP_TT_FOUND_VERNUM" -ge "50200"; then AC_MSG_RESULT(yes. found $PHP_TT_FOUND_VERSION) else AC_MSG_ERROR(no. found $PHP_TT_FOUND_VERSION) fi dnl Add dependency to date extension if PHP >= 5.3.0 is used if test $PHP_TT_FOUND_VERNUM -ge 50300; then PHP_ADD_EXTENSION_DEP(tokyo_tyrant, date) fi dnl Tokyo Tyrant parts AC_PATH_PROG(PKG_CONFIG, pkg-config, no) if test "x$PKG_CONFIG" = "xno"; then AC_MSG_RESULT([pkg-config not found]) AC_MSG_ERROR([Please reinstall the pkg-config distribution]) fi ORIG_PKG_CONFIG_PATH=$PKG_CONFIG_PATH dnl Tokyo Tyrant PKG_CONFIG if test "$PHP_TOKYO_TYRANT" = "yes"; then export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/lib/pkgconfig:/opt/local/lib/pkgconfig else export PKG_CONFIG_PATH=$PHP_TOKYO_TYRANT:$PHP_TOKYO_TYRANT/lib/pkgconfig fi AC_MSG_CHECKING([for Tokyo Tyrant]) if $PKG_CONFIG --exists tokyotyrant; then PHP_TYRANT_INCS=`$PKG_CONFIG tokyotyrant --cflags` PHP_TYRANT_LIBS=`$PKG_CONFIG tokyotyrant --libs` PHP_TYRANT_VERSION_STRING=`$PKG_CONFIG tokyotyrant --modversion` PHP_EVAL_LIBLINE($PHP_TYRANT_LIBS, TOKYO_TYRANT_SHARED_LIBADD) PHP_EVAL_INCLINE($PHP_TYRANT_INCS) AC_MSG_RESULT([yes, ${PHP_TYRANT_VERSION_STRING}]) else AC_MSG_RESULT([not found]) AC_MSG_ERROR([Please reinstall the Tokyo Tyrant distribution]) fi AC_MSG_CHECKING([that Tokyo Tyrant is at least version 1.1.24]) `$PKG_CONFIG --atleast-version=1.1.24 tokyotyrant` if test $? != 0; then AC_MSG_ERROR(no) fi AC_MSG_RESULT(yes) PHP_TYRANT_VERSION_MASK=`echo ${PHP_TYRANT_VERSION_STRING} | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` AC_DEFINE_UNQUOTED(PHP_TOKYO_TYRANT_VERSION, $PHP_TYRANT_VERSION_MASK, [ ]) dnl Tokyo Cabinet header dnl Tokyo Tyrant PKG_CONFIG if test "$PHP_TOKYO_CABINET_DIR" = "yes"; then export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/lib/pkgconfig:/opt/local/lib/pkgconfig else export PKG_CONFIG_PATH=$PHP_TOKYO_CABINET_DIR:$PHP_TOKYO_CABINET_DIR/lib/pkgconfig fi AC_MSG_CHECKING([for Tokyo Cabinet]) if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists tokyocabinet; then PHP_CABINET_INCS=`$PKG_CONFIG tokyocabinet --cflags` PHP_CABINET_LIBS=`$PKG_CONFIG tokyocabinet --libs` PHP_CABINET_VERSION=`$PKG_CONFIG tokyocabinet --modversion` PHP_EVAL_LIBLINE($PHP_CABINET_LIBS, TOKYO_TYRANT_SHARED_LIBADD) PHP_EVAL_INCLINE($PHP_CABINET_INCS) AC_MSG_RESULT([yes, ${PHP_CABINET_VERSION}]) else AC_MSG_RESULT([not found]) AC_MSG_ERROR([Please reinstall the Tokyo Cabinet distribution]) fi TOKYO_EXT_FILES="tokyo_tyrant.c tokyo_tyrant_funcs.c connection.c" if test "$PHP_TOKYO_TYRANT_SESSION" != "no"; then AC_DEFINE(HAVE_PHP_TOKYO_TYRANT_SESSION,1,[ ]) TOKYO_EXT_FILES="${TOKYO_EXT_FILES} session_funcs.c server_pool.c failover.c session.c" fi PHP_NEW_EXTENSION(tokyo_tyrant, $TOKYO_EXT_FILES, $ext_shared) AC_DEFINE(HAVE_PHP_TOKYO_TYRANT,1,[ ]) PHP_SUBST(TOKYO_TYRANT_SHARED_LIBADD) export PKG_CONFIG_PATH="$ORIG_PKG_CONFIG_PATH" fi tokyo_tyrant-0.6.0/connection.c0000644000076500000240000001344111530776271016455 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #include "php_tokyo_tyrant.h" #include "php_tokyo_tyrant_private.h" #include "php_tokyo_tyrant_connection.h" php_tt_conn *php_tt_conn_init(TSRMLS_D) { php_tt_conn *conn = emalloc(sizeof(php_tt_conn)); conn->connected = 0; conn->persistent = 0; conn->rdb = NULL; return conn; } void php_tt_disconnect_ex(php_tt_conn *conn, zend_bool dealloc_rdb TSRMLS_DC) { if (conn->rdb && dealloc_rdb) { tcrdbdel(conn->rdb); conn->rdb = NULL; } conn->connected = 0; } void php_tt_conn_deinit(php_tt_conn *conn TSRMLS_DC) { if (!conn->persistent && conn->rdb) { php_tt_disconnect_ex(conn, 1 TSRMLS_CC); } efree(conn); } char *php_tt_hash_key(char *host, int port, double timeout, int *key_len TSRMLS_DC) { char *buffer = NULL; *key_len = spprintf(&buffer, strlen(host) + 256, "%s %d %f", host, port, timeout); return buffer; } static void php_tt_alloc_pool(TSRMLS_D) { TOKYO_G(connections) = malloc(sizeof(HashTable)); if (!TOKYO_G(connections)) php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to allocate memory for the connection pool"); zend_hash_init(TOKYO_G(connections), 0, NULL, NULL, 1); } static TCRDB *php_tt_get_persistent(char *host, int port, double timeout TSRMLS_DC) { TCRDB **conn; int key_len; char *key; /* Make sure that connection pool is allocated */ if (!TOKYO_G(connections)) php_tt_alloc_pool(TSRMLS_C); key = php_tt_hash_key(host, port, timeout, &key_len TSRMLS_CC); if (zend_hash_find(TOKYO_G(connections), key, key_len + 1, (void **)&conn) == SUCCESS) { efree(key); return *conn; } efree(key); return NULL; } static zend_bool php_tt_set_persistent(char *host, int port, double timeout, TCRDB *conn TSRMLS_DC) { int key_len; char *key; if (!TOKYO_G(connections)) php_tt_alloc_pool(TSRMLS_C); key = php_tt_hash_key(host, port, timeout, &key_len TSRMLS_CC); if (zend_hash_update(TOKYO_G(connections), key, key_len + 1, (void *)&conn, sizeof(TCRDB *), NULL) == SUCCESS) { efree(key); return 0; } efree(key); return 1; } zend_bool php_tt_connect_ex(php_tt_conn *conn, char *host, int port, double timeout, zend_bool persistent TSRMLS_DC) { int options = 0; assert(conn->connected == 0); if (persistent) { if ((conn->rdb = php_tt_get_persistent(host, port, timeout TSRMLS_CC))) { conn->persistent = 1; conn->connected = 1; return 1; } } /* Init rdb object */ conn->rdb = tcrdbnew(); if (timeout < 0.0) { timeout = TOKYO_G(default_timeout); } if (persistent) { options |= RDBTRECON; } /* Set options and try to connect */ tcrdbtune(conn->rdb, timeout, options); if (!tcrdbopen(conn->rdb, host, port)) { conn->connected = 0; return 0; } else { conn->persistent = persistent; conn->connected = 1; /* Persist */ if (persistent) { php_tt_set_persistent(host, port, timeout, conn->rdb TSRMLS_CC); } } return 1; } zend_bool php_tt_connect(php_tokyo_tyrant_object *intern, char *host, int port, zval *params TSRMLS_DC) { zend_bool persistent = 0; int options = RDBTRECON; double timeout = TOKYO_G(default_timeout); /* Parse args if provided */ if (params && (Z_TYPE_P(params) == IS_OBJECT || Z_TYPE_P(params) == IS_ARRAY)) { zval **param = NULL; if (zend_hash_find(HASH_OF(params), "persistent", sizeof("persistent"), (void **) ¶m) != FAILURE) { convert_to_boolean_ex(param); persistent = Z_BVAL_PP(param); } if (zend_hash_find(HASH_OF(params), "timeout", sizeof("timeout"), (void **) ¶m) != FAILURE) { convert_to_double_ex(param); if (Z_DVAL_PP(param) > 0) { timeout = Z_DVAL_PP(param); } } if (zend_hash_find(HASH_OF(params), "reconnect", sizeof("reconnect"), (void **) ¶m) != FAILURE) { convert_to_boolean_ex(param); if (!(Z_BVAL_PP(param))) { options = 0; } } } if (port <= 0) { port = PHP_TOKYO_TYRANT_DEFAULT_PORT; } if (intern->conn->connected) { php_tt_disconnect_ex(intern->conn, (intern->conn->persistent == 0) TSRMLS_CC); } return php_tt_connect_ex(intern->conn, host, port, timeout, persistent TSRMLS_CC); } zend_bool php_tt_connect2(php_tokyo_tyrant_object *intern, php_url *url TSRMLS_DC) { int code = 0; if (url->query != NULL) { zval *params; MAKE_STD_ZVAL(params); array_init(params); sapi_module.treat_data(PARSE_STRING, estrdup(url->query), params TSRMLS_CC); code = php_tt_connect(intern, url->host, url->port, params TSRMLS_CC); zval_ptr_dtor(¶ms); } else { code = php_tt_connect(intern, url->host, url->port, NULL TSRMLS_CC); } return code; } tokyo_tyrant-0.6.0/failover.c0000644000076500000240000001040111530776271016116 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #include "php_tokyo_tyrant_session.h" #include "ext/standard/php_rand.h" long php_tt_server_fail(int op, char *host, int port TSRMLS_DC) { char *key = NULL; zend_bool result; int key_len; zval *fail_count, **ptrptr; if (!TOKYO_G(failures)) { TOKYO_G(failures) = malloc(sizeof(HashTable)); if (!TOKYO_G(failures)) { return 0; } zend_hash_init(TOKYO_G(failures), 5, NULL, ZVAL_INTERNAL_PTR_DTOR, 1); } key = php_tt_hash_key(host, port, 0.0, &key_len TSRMLS_CC); if (zend_hash_find(TOKYO_G(failures), key, key_len + 1, (void **)&ptrptr) == SUCCESS) { fail_count = *ptrptr; if (op == PHP_TT_GET) { efree(key); return Z_LVAL_P(fail_count); } else if (op == PHP_TT_INCR) { Z_LVAL_P(fail_count)++; } else { Z_LVAL_P(fail_count)--; } } else { if (op == PHP_TT_GET) { efree(key); return 0; } fail_count = malloc(sizeof(zval)); INIT_PZVAL(fail_count); ZVAL_LONG(fail_count, (op == PHP_TT_INCR) ? 1 : 0); } result = (zend_hash_update(TOKYO_G(failures), key, key_len + 1, (void *)&fail_count, sizeof(zval *), NULL) == SUCCESS); efree(key); return Z_LVAL_P(fail_count); } void php_tt_server_fail_incr(char *host, int port TSRMLS_DC) { php_tt_server_fail(PHP_TT_INCR, host, port TSRMLS_CC); } void php_tt_server_fail_decr(char *host, int port TSRMLS_DC) { php_tt_server_fail(PHP_TT_DECR, host, port TSRMLS_CC); } zend_bool php_tt_server_ok(char *host, int port TSRMLS_DC) { long fail_count = php_tt_server_fail(PHP_TT_GET, host, port TSRMLS_CC); /* Server is always ok if failover is disabled */ if (!TOKYO_G(allow_failover)) { return 1; } /* If this matches, execute a health check on servers and restore them to pool if they are fine */ if ((php_rand(TSRMLS_C) % TOKYO_G(health_check_divisor)) == (php_rand(TSRMLS_C) % TOKYO_G(health_check_divisor))) { php_tt_health_check(TSRMLS_C); } if (fail_count < TOKYO_G(fail_threshold)) { return 1; } else { return 0; } } static int _php_tt_check_servers(zval **ppzval TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) { char *key, host[4096]; double timeout; int port; if (hash_key->nKeyLength == 0 || hash_key->nKeyLength >= 4096) { return ZEND_HASH_APPLY_REMOVE; } key = estrdup(hash_key->arKey); memset(host, '\0', 4096); if (sscanf(key, "%s %d %lf", host, &port, &timeout) == 3) { int value; uint_fast64_t index; TCRDB *rdb = tcrdbnew(); value = tcrdbopen(rdb, host, port); if (!value) { efree(key); tcrdbdel(rdb); return ZEND_HASH_APPLY_KEEP; } index = tcrdbtblgenuid(rdb); tcrdbdel(rdb); if (index == -1) { efree(key); return ZEND_HASH_APPLY_KEEP; } } efree(key); return ZEND_HASH_APPLY_REMOVE; } void php_tt_health_check(TSRMLS_D) { if (TOKYO_G(failures) && zend_hash_num_elements(TOKYO_G(failures)) > 0) { zend_hash_apply_with_arguments(TOKYO_G(failures) TSRMLS_CC, (apply_func_args_t)_php_tt_check_servers, 0); } } tokyo_tyrant-0.6.0/server_pool.c0000644000076500000240000001027411530776271016656 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #include "php_tokyo_tyrant_session.h" #include "ext/standard/php_rand.h" static php_tt_server *php_tt_server_init(char *host, int port) { php_tt_server *server = emalloc(sizeof(*server)); server->host = estrdup(host); server->port = port; return server; } static void php_tt_server_deinit(php_tt_server *server TSRMLS_DC) { efree(server->host); efree(server); } php_tt_server_pool *php_tt_pool_init(TSRMLS_D) { php_tt_server_pool *pool = emalloc(sizeof(php_tt_server_pool)); pool->servers = emalloc(sizeof(php_tt_server *)); pool->num_servers = 0; return pool; } void php_tt_pool_append(php_tt_server_pool *pool, php_tt_server *server TSRMLS_DC) { pool->servers = erealloc(pool->servers, (pool->num_servers + 1) * sizeof(php_tt_server)); pool->servers[pool->num_servers] = server; pool->num_servers += 1; } void php_tt_pool_append2(php_tt_server_pool *pool, char *host, int port TSRMLS_DC) { php_tt_server *server = php_tt_server_init(host, port); php_tt_pool_append(pool, server TSRMLS_CC); } void php_tt_pool_deinit(php_tt_server_pool *pool TSRMLS_DC) { if (pool->num_servers > 0) { int i; for (i = 0; i < pool->num_servers; i++) { php_tt_server_deinit(pool->servers[i] TSRMLS_CC); pool->servers[i] = NULL; } efree(pool->servers); } efree(pool); } php_tt_server_pool *php_tt_pool_init2(const char *save_path TSRMLS_DC) { php_tt_server_pool *pool = php_tt_pool_init(TSRMLS_C); php_url *url = NULL; char *ptr = NULL, *pch = NULL; ptr = estrdup(save_path); pch = strtok(ptr, ","); while (pch != NULL) { url = php_url_parse(pch); if (!url) { goto failure; } if (!url->host || !url->port) { php_url_free(url); goto failure; } php_tt_pool_append2(pool, url->host, url->port TSRMLS_CC); php_url_free(url); url = NULL; pch = strtok(NULL, ","); } efree(ptr); return pool; failure: if (ptr) efree(ptr); return NULL; } int php_tt_pool_map(php_tt_server_pool *pool, char *key TSRMLS_DC) { php_tt_server *server; int idx = -1; if (pool->num_servers == 0) { return -1; } idx = php_rand(TSRMLS_C) % pool->num_servers; server = pool->servers[idx]; /* Server has failed. Get a new random server */ if (!php_tt_server_ok(server->host, server->port TSRMLS_CC)) { int i, x = php_rand(TSRMLS_C) % pool->num_servers; for (i = x; i < pool->num_servers; i++) { if (i != idx) { server = pool->servers[i]; if (php_tt_server_ok(server->host, server->port TSRMLS_CC)) { return i; } } } for (i = x; i >= 0; i--) { if (i != idx) { server = pool->servers[i]; if (php_tt_server_ok(server->host, server->port TSRMLS_CC)) { return i; } } } idx = -1; } return idx; } php_tt_server *php_tt_pool_get_server(php_tt_server_pool *pool, int idx TSRMLS_DC) { if (idx >= pool->num_servers || idx < 0) { return NULL; } return pool->servers[idx]; }tokyo_tyrant-0.6.0/session.c0000644000076500000240000002167411530776271016010 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #include "php_tokyo_tyrant_session.h" #include "php_tokyo_tyrant_session_funcs.h" ps_module ps_mod_tokyo_tyrant = { PS_MOD_SID(tokyo_tyrant) }; #define TT_SESS_DATA php_tt_session *session = PS_GET_MOD_DATA(); /* {{{ Create new session id */ PS_CREATE_SID_FUNC(tokyo_tyrant) { php_tt_conn *conn; php_tt_server *server; php_tt_server_pool *pool; char *current_rand = NULL; char *sess_rand, *sid, *pk = NULL; int idx = -1, pk_len; zend_bool is_regenerated = 0; if (!TOKYO_G(salt)) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "tokyo_tyrant.session_salt needs to be set in order to use the session handler"); } /* Session id is being regenerated. Need to copy some data */ if (PS(session_status) == php_session_active) { TT_SESS_DATA; if (!session) { /* This is a situation where session_regenerate_id(TRUE) is called */ is_regenerated = 1; } else { /* Use old values unless regeneration is forced */ if (session->remap == 0) { idx = session->idx; pk = estrdup(session->pk); current_rand = estrdup(session->sess_rand); } else { session->remap = 0; } } } /* Create the random part of the session id */ sess_rand = php_session_create_id(PS(mod_data), NULL TSRMLS_CC); if (!sess_rand) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to generate session id"); } /* Init the server pool */ pool = php_tt_pool_init2(PS(save_path) TSRMLS_CC); if (!pool) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to parse session.save_path"); } /* Create idx if there isn't one already */ if (idx == -1) { idx = php_tt_pool_map(pool, sess_rand TSRMLS_CC); if (idx < 0) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to map the session to a server"); } } /* Get the server for the node */ server = php_tt_pool_get_server(pool, idx TSRMLS_CC); if (!server) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: idx does not map to a server (should not happen)"); } /* Create connection to the server */ conn = php_tt_conn_init(TSRMLS_C); if (!php_tt_connect_ex(conn, server->host, server->port, TOKYO_G(default_timeout), 1 TSRMLS_CC)) { php_tt_server_fail_incr(server->host, server->port TSRMLS_CC); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to the session server"); } if (!pk) { pk = php_tt_create_pk(conn, &pk_len TSRMLS_CC); if (!pk) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to create a primary key. Not connected to a table database?"); } } else { if (!php_tt_sess_touch(conn, current_rand, sess_rand, pk, strlen(pk) TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to update the session"); } efree(current_rand); } sid = php_tt_create_sid(sess_rand, idx, pk, TOKYO_G(salt) TSRMLS_CC); efree(sess_rand); efree(pk); php_tt_conn_deinit(conn TSRMLS_CC); php_tt_pool_deinit(pool TSRMLS_CC); /* This is a situation where session_regenerate_id(TRUE) is called */ if (is_regenerated) { int ret = ps_open_tokyo_tyrant(mod_data, PS(save_path), PS(session_name) TSRMLS_CC); if (ret == SUCCESS) { char *dummy_val = NULL; int val_len = 0; ret = ps_read_tokyo_tyrant(mod_data, sid, &dummy_val, &val_len TSRMLS_CC); if (ret != SUCCESS) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read session data during regeneration"); } if (dummy_val) { efree(dummy_val); } } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open the session during regeneration"); } } return sid; } /* }}} */ /* {{{ PS_OPEN */ PS_OPEN_FUNC(tokyo_tyrant) { php_tt_session *session = php_tt_session_init(TSRMLS_C); if (!session) { PS_SET_MOD_DATA(NULL); return FAILURE; } session->pool = php_tt_pool_init2(PS(save_path) TSRMLS_CC); if (!session->pool) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to parse session.save_path"); } PS_SET_MOD_DATA(session); return SUCCESS; } /* }}} */ PS_READ_FUNC(tokyo_tyrant) { TT_SESS_DATA; php_tt_server *server; zend_bool mismatch; /* Try to tokenize session id */ if (!php_tt_tokenize((char *)key, &(session->sess_rand), &(session->checksum), &(session->idx), &(session->pk) TSRMLS_CC)) { session->remap = 1; PS(invalid_session_id) = 1; return FAILURE; } /* Set additional data */ session->sess_rand_len = strlen(session->sess_rand); session->checksum_len = strlen(session->checksum); session->pk_len = strlen(session->pk); /* Validate the session id */ if (!php_tt_validate(session->sess_rand, session->checksum, session->idx, session->pk, TOKYO_G(salt) TSRMLS_CC)) { session->remap = 1; PS(invalid_session_id) = 1; return FAILURE; } server = php_tt_pool_get_server(session->pool, session->idx TSRMLS_CC); if (!server) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal error: idx does not map to a server"); session->remap = 1; PS(invalid_session_id) = 1; return FAILURE; } session->conn = php_tt_conn_init(TSRMLS_C); if (!php_tt_connect_ex(session->conn, server->host, server->port, TOKYO_G(default_timeout), 1 TSRMLS_CC)) { php_tt_server_fail_incr(server->host, server->port TSRMLS_CC); /* Remap if the server has been failed */ if (!php_tt_server_ok(server->host, server->port TSRMLS_CC)) { session->remap = 1; PS(invalid_session_id) = 1; return FAILURE; } } *val = php_tt_get_sess_data(session->conn, session->sess_rand, session->pk, session->pk_len, vallen, &mismatch TSRMLS_CC); if (*val == NULL) { /* Session got mapped to wrong server */ if (mismatch) { session->remap = 1; PS(invalid_session_id) = 1; return FAILURE; } /* Return empty data */ *val = estrdup(""); } return SUCCESS; } PS_WRITE_FUNC(tokyo_tyrant) { TT_SESS_DATA; php_tt_server *server; /* Try to tokenize session id */ efree(session->sess_rand); efree(session->checksum); efree(session->pk); if (!php_tt_tokenize((char *)key, &(session->sess_rand), &(session->checksum), &(session->idx), &(session->pk) TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse the session id"); session->remap = 1; PS(invalid_session_id) = 1; return FAILURE; } /* Set additional data */ session->sess_rand_len = strlen(session->sess_rand); session->checksum_len = strlen(session->checksum); session->pk_len = strlen(session->pk); if (!php_tt_validate(session->sess_rand, session->checksum, session->idx, session->pk, TOKYO_G(salt) TSRMLS_CC)) { return FAILURE; } if (!php_tt_save_sess_data(session->conn, session->sess_rand, session->pk, strlen(session->pk), val, vallen TSRMLS_CC)) { server = php_tt_pool_get_server(session->pool, session->idx TSRMLS_CC); php_tt_server_fail_incr(server->host, server->port TSRMLS_CC); /* Remap if the server has been marked as failed */ if (!php_tt_server_ok(server->host, server->port TSRMLS_CC)) { session->remap = 1; PS(invalid_session_id) = 1; return FAILURE; } return FAILURE; } return SUCCESS; } PS_DESTROY_FUNC(tokyo_tyrant) { TT_SESS_DATA; zend_bool res; res = php_tt_sess_destroy(session->conn, session->pk, session->pk_len TSRMLS_CC); php_tt_session_deinit(session TSRMLS_CC); session = NULL; PS_SET_MOD_DATA(NULL); if (!res) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to destroy the session"); return FAILURE; } return SUCCESS; } PS_GC_FUNC(tokyo_tyrant) { /* Handle expiration on PHP side? */ if (TOKYO_G(php_expiration)) { TT_SESS_DATA; return php_tt_gc(session->pool TSRMLS_CC); } return SUCCESS; } PS_CLOSE_FUNC(tokyo_tyrant) { TT_SESS_DATA; php_tt_session_deinit(session TSRMLS_CC); session = NULL; PS_SET_MOD_DATA(NULL); return SUCCESS; }tokyo_tyrant-0.6.0/session_funcs.c0000644000076500000240000001761411530776271017205 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #include "php_tokyo_tyrant_session.h" #include "ext/standard/sha1.h" #define PHP_TT_CHECKSUM_LEN 41 php_tt_session *php_tt_session_init(TSRMLS_D) { php_tt_session *session = emalloc(sizeof(php_tt_session)); session->pool = NULL; session->conn = NULL; session->pk = NULL; session->pk_len = 0; session->sess_rand = NULL; session->sess_rand_len = 0; session->checksum = NULL; session->checksum_len = 0; session->remap = 0; return session; } void php_tt_session_deinit(php_tt_session *session TSRMLS_DC) { if (session->conn) { php_tt_conn_deinit(session->conn TSRMLS_CC); session->conn = NULL; } if (session->pool) { php_tt_pool_deinit(session->pool TSRMLS_CC); session->pool = NULL; } if (session->pk) { efree(session->pk); session->pk = NULL; } if (session->sess_rand) { efree(session->sess_rand); session->sess_rand = NULL; } if (session->checksum) { efree(session->checksum); session->checksum = NULL; } efree(session); } static void php_tt_checksum(char *sess_rand, int idx, char *pk, char *salt, char checksum[PHP_TT_CHECKSUM_LEN]) { PHP_SHA1_CTX context; char pk_src[512]; int pk_src_len; unsigned char digest[20]; /* This is what we need to hash */ pk_src_len = snprintf(pk_src, 512, "#%s# #%s# #%d# #%s#", sess_rand, salt, idx, pk); /* sha1 hash the pk_src and compare to session_hash */ PHP_SHA1Init(&context); PHP_SHA1Update(&context, (unsigned char *)pk_src, pk_src_len); PHP_SHA1Final(digest, &context); make_sha1_digest(checksum, digest); checksum[40] = '\0'; } char *php_tt_create_sid(char *sess_rand, int idx, char *pk, char *salt) { char *tmp, buffer[PHP_TT_CHECKSUM_LEN]; php_tt_checksum(sess_rand, idx, pk, salt, buffer); spprintf(&tmp, 512, "%s-%s-%d-%s", sess_rand, buffer, idx, pk); return tmp; } char *php_tt_create_pk(php_tt_conn *conn, int *pk_len) { long pk = -1; char *pk_str; pk = (long)tcrdbtblgenuid(conn->rdb); *pk_len = 0; if (pk == -1) { return NULL; } *pk_len = spprintf(&pk_str, 256, "%ld", pk); return pk_str; } zend_bool php_tt_tokenize(char *session_id, char **sess_rand, char **checksum, int *idx, char **pk_str) { int i, matches = 0, ptr_len; char *ptr = NULL; /* Should be a fairly sensible limitation */ if (!session_id || strlen(session_id) >= 512) { return 0; } ptr = estrdup(session_id); ptr_len = strlen(ptr); /* Make it easy to sscanf */ for (i = 0; i < ptr_len; i++) { if (ptr[i] == '-') { ptr[i] = ' '; } } *sess_rand = emalloc(65); *checksum = emalloc(41); *pk_str = emalloc(65); memset(*sess_rand, '\0', 65); memset(*checksum, '\0', 41); memset(*pk_str, '\0', 65); /* TODO: does this cost alot? */ matches = sscanf(ptr, "%64s %40s %d %64s", *sess_rand, *checksum, &(*idx), *pk_str); efree(ptr); if (matches == 4) { return 1; } efree(*sess_rand); *sess_rand = NULL; efree(*checksum); *checksum = NULL; efree(*pk_str); *pk_str = NULL; return 0; } zend_bool php_tt_validate(char *sess_rand, char *checksum, int idx, char *pk, char *salt TSRMLS_DC) { int code = 0; char buffer[PHP_TT_CHECKSUM_LEN]; php_tt_checksum(sess_rand, idx, pk, salt, buffer); if (strlen(checksum) == strlen(buffer)) { if (strcmp(checksum, buffer) == 0) { code = 1; } } return code; } char *php_tt_get_sess_data(php_tt_conn *conn, char *sess_rand, const char *pk, int pk_len, int *data_len, zend_bool *mismatch TSRMLS_DC) { TCMAP *cols; char *buffer = NULL; *data_len = 0; *mismatch = 0; cols = tcrdbtblget(conn->rdb, pk, pk_len); if (cols) { const char *checksum = tcmapget2(cols, "hash"); /* Make sure that we get back the expected session */ if (strcmp(checksum, sess_rand) == 0) { const char *data; data = tcmapget(cols, "data", sizeof("data") - 1, data_len); if (data) { buffer = emalloc(*data_len); memcpy(buffer, data, *data_len); } } else { *mismatch = 1; } tcmapdel(cols); } return buffer; } zend_bool php_tt_save_sess_data(php_tt_conn *conn, char *rand_part, char *pk, int pk_len, const char *data, int data_len TSRMLS_DC) { TCMAP *cols; char timestamp[64]; time_t expiration; if (!data) { return 1; } /* Expiration is handled by lua script */ expiration = SG(global_request_time) + PS(gc_maxlifetime); memset(timestamp, '\0', 64); sprintf(timestamp, "%ld", expiration); /* store a record */ cols = tcmapnew(); tcmapput(cols, "data", sizeof("data") - 1, data, data_len); tcmapput2(cols, "hash", rand_part); tcmapput2(cols, "ts", timestamp); if (!tcrdbtblput(conn->rdb, pk, pk_len, cols)) { tcmapdel(cols); return 0; } tcmapdel(cols); return 1; } zend_bool php_tt_sess_touch(php_tt_conn *conn, char *current_rand, char *sess_rand, char *pk, int pk_len TSRMLS_DC) { char *data; int data_len; zend_bool mismatch; data = php_tt_get_sess_data(conn, current_rand, pk, pk_len, &data_len, &mismatch TSRMLS_CC); if (!data) { return 1; } return php_tt_save_sess_data(conn, sess_rand, pk, pk_len, data, data_len TSRMLS_CC); } zend_bool php_tt_sess_destroy(php_tt_conn *conn, char *pk, int pk_len TSRMLS_DC) { if (tcrdbtblout(conn->rdb, pk, pk_len)) { return 1; } else { /* TTENOREC means that record did not exist. This should not cause error */ if (tcrdbecode(conn->rdb) == TTENOREC) { return 1; } } return 0; } zend_bool php_tt_gc(php_tt_server_pool *pool TSRMLS_DC) { int i; zend_bool overal_res = SUCCESS; char timestamp[64]; memset(timestamp, '\0', 64); sprintf(timestamp, "%ld", SG(global_request_time)); for (i = 0; i < pool->num_servers; i++) { php_tt_server *server; php_tt_conn *conn; RDBQRY *query; server = php_tt_pool_get_server(pool, i TSRMLS_CC); conn = php_tt_conn_init(TSRMLS_C); if (!php_tt_connect_ex(conn, server->host, server->port, TOKYO_G(default_timeout), 1 TSRMLS_CC)) { overal_res = FAILURE; continue; } query = tcrdbqrynew(conn->rdb); tcrdbqryaddcond(query, "ts", RDBQCNUMLT, timestamp); if (!tcrdbqrysearchout(query)) { php_tt_server_fail_incr(server->host, server->port TSRMLS_CC); overal_res = FAILURE; break; } tcrdbqrydel(query); php_tt_conn_deinit(conn TSRMLS_CC); } return overal_res; } #if 0 void php_tt_regen_id(php_tt_session *session TSRMLS_DC) { zval *fname, retval; /* Force regeneration of id and force session to be active */ session->remap = 1; PS(session_status) = php_session_active; MAKE_STD_ZVAL(fname); ZVAL_STRING(fname, "session_regenerate_id", 1); call_user_function(EG(function_table), NULL, fname, &retval, 0, NULL TSRMLS_CC); session->remap = 0; zval_dtor(fname); FREE_ZVAL(fname); } #endiftokyo_tyrant-0.6.0/tokyo_tyrant.c0000644000076500000240000020457511530776271017076 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #include "php_tokyo_tyrant.h" #include "php_tokyo_tyrant_private.h" #include "php_tokyo_tyrant_funcs.h" #include "php_tokyo_tyrant_connection.h" #include "SAPI.h" #include "php_variables.h" #include "ext/standard/info.h" #include "Zend/zend_exceptions.h" #include "Zend/zend_interfaces.h" #if PHP_MAJOR_VERSION >=5 && PHP_MINOR_VERSION >= 3 # include "ext/date/php_date.h" #endif zend_class_entry *php_tokyo_tyrant_sc_entry; zend_class_entry *php_tokyo_tyrant_table_sc_entry; zend_class_entry *php_tokyo_tyrant_query_sc_entry; zend_class_entry *php_tokyo_tyrant_iterator_sc_entry; zend_class_entry *php_tokyo_tyrant_exception_sc_entry; static zend_object_handlers tokyo_tyrant_object_handlers; static zend_object_handlers tokyo_tyrant_table_object_handlers; static zend_object_handlers tokyo_tyrant_query_object_handlers; static zend_object_handlers tokyo_tyrant_iterator_object_handlers; ZEND_DECLARE_MODULE_GLOBALS(tokyo_tyrant); /* {{{ TokyoTyrant TokyoTyrant::__construct([string host, int port, array params]); The constructor @throws TokyoTyrantException if host is set and database connection fails */ PHP_METHOD(tokyotyrant, __construct) { php_tokyo_tyrant_object *intern; char *host = NULL; int host_len, port = PHP_TOKYO_TYRANT_DEFAULT_PORT; zval *params = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla!", &host, &host_len, &port, ¶ms) == FAILURE) { return; } intern = PHP_TOKYO_OBJECT; if (host && !php_tt_connect(intern, host, port, params TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to connect to database: %s"); } return; } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::connect(string host, int port[, array params]); Connect to a database @throws TokyoTyrantException if disconnecting previous connection fails @throws TokyoTyrantException if connection fails */ PHP_METHOD(tokyotyrant, connect) { php_tokyo_tyrant_object *intern; char *host = NULL; int host_len, port = PHP_TOKYO_TYRANT_DEFAULT_PORT; zval *params = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!", &host, &host_len, &port, ¶ms) == FAILURE) { return; } intern = PHP_TOKYO_OBJECT; if (!php_tt_connect(intern, host, port, params TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to connect to database: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::connectUri(string uri); Connect to a database using uri tcp://hostname:port?persistent=1&timeout=2.2&reconnect=true @throws TokyoTyrantException if disconnecting previous connection fails @throws TokyoTyrantException if connection fails */ PHP_METHOD(tokyotyrant, connecturi) { php_tokyo_tyrant_object *intern; char *uri; int uri_len; php_url *url; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &uri, &uri_len) == FAILURE) { return; } if (!(url = php_url_parse(uri))) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Failed to parse the uri"); } intern = PHP_TOKYO_OBJECT; if (!php_tt_connect2(intern, url TSRMLS_CC)) { php_url_free(url); PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to connect to database: %s"); } php_url_free(url); PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ static int _php_tt_real_write(TCRDB *rdb, long type, char *key, int key_len, char *value, int value_len TSRMLS_DC) */ static int _php_tt_real_write(TCRDB *rdb, long type, char *key, int key_len, char *value, int value_len TSRMLS_DC) { int code = 0; int new_len; char *kbuf = php_tt_prefix(key, key_len, &new_len TSRMLS_CC); switch (type) { case PHP_TOKYO_TYRANT_OP_PUT: code = tcrdbput(rdb, kbuf, new_len, value, value_len); break; case PHP_TOKYO_TYRANT_OP_PUTKEEP: code = tcrdbputkeep(rdb, kbuf, new_len, value, value_len); break; case PHP_TOKYO_TYRANT_OP_PUTCAT: code = tcrdbputcat(rdb, kbuf, new_len, value, value_len); break; case PHP_TOKYO_TYRANT_OP_PUTNR: code = tcrdbputnr(rdb, kbuf, new_len, value, value_len); break; case PHP_TOKYO_TYRANT_OP_OUT: code = tcrdbout(rdb, kbuf, new_len); break; case PHP_TOKYO_TYRANT_OP_TBLOUT: code = tcrdbtblout(rdb, kbuf, new_len); break; } efree(kbuf); /* TODO: maybe add strict flag but ignore non-existent keys for now */ if (!code) { if (tcrdbecode(rdb) == TTENOREC) { code = 1; } } return code; } /* }}} */ /* {{{ static int _php_tt_op_many(zval **ppzval TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) */ static int _php_tt_op_many(zval **ppzval TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) { zval tmpcopy; php_tokyo_tyrant_object *intern; int type, *code, key_len; char *key, key_buf[256]; if (num_args != 3) { return 0; } intern = va_arg(args, php_tokyo_tyrant_object *); type = va_arg(args, int); code = va_arg(args, int *); if (hash_key->nKeyLength == 0) { key_buf[0] = '\0'; key_len = snprintf(key_buf, 256, "%ld", hash_key->h); key = key_buf; } else { key = hash_key->arKey; key_len = hash_key->nKeyLength - 1; } tmpcopy = **ppzval; zval_copy_ctor(&tmpcopy); INIT_PZVAL(&tmpcopy); convert_to_string(&tmpcopy); if (type == PHP_TOKYO_TYRANT_OP_OUT || type == PHP_TOKYO_TYRANT_OP_TBLOUT) { *code = _php_tt_real_write(intern->conn->rdb, type, Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy), NULL, 0 TSRMLS_CC); } else { *code = _php_tt_real_write(intern->conn->rdb, type, key, key_len, Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy) TSRMLS_CC); } zval_dtor(&tmpcopy); if (!(*code)) { return ZEND_HASH_APPLY_STOP; } return ZEND_HASH_APPLY_KEEP; } /* }}} */ /* {{{ static void _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAMETERS, long type) */ static void _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAMETERS, long type) { php_tokyo_tyrant_object *intern; zval *key, *value = NULL; int code; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z!", &key, &value) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (Z_TYPE_P(key) == IS_ARRAY) { zend_hash_apply_with_arguments(Z_ARRVAL_P(key) TSRMLS_CC, (apply_func_args_t) _php_tt_op_many, 3, intern, type, &code); if (!code) { if (type == PHP_TOKYO_TYRANT_OP_OUT || type == PHP_TOKYO_TYRANT_OP_TBLOUT) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to remove the records: %s"); } else { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to put the records: %s"); } } } else { zval key_cp; key_cp = *key; zval_copy_ctor(&key_cp); convert_to_string(&key_cp); if (type == PHP_TOKYO_TYRANT_OP_OUT || type == PHP_TOKYO_TYRANT_OP_TBLOUT) { if (!_php_tt_real_write(intern->conn->rdb, type, Z_STRVAL(key_cp), Z_STRLEN(key_cp), NULL, 0 TSRMLS_CC)) { zend_throw_exception_ex(php_tokyo_tyrant_exception_sc_entry, tcrdbecode(intern->conn->rdb) TSRMLS_CC, "Unable to remove the record '%s': %s", Z_STRVAL(key_cp), tcrdberrmsg(tcrdbecode(intern->conn->rdb))); zval_dtor(&key_cp); return; } } else { zval value_cp; if (!value) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unable to store the record: no value provided"); } value_cp = *value; zval_copy_ctor(&value_cp); convert_to_string(&value_cp); if (!_php_tt_real_write(intern->conn->rdb, type, Z_STRVAL(key_cp), Z_STRLEN(key_cp), Z_STRVAL(value_cp), Z_STRLEN(value_cp) TSRMLS_CC)) { zend_throw_exception_ex(php_tokyo_tyrant_exception_sc_entry, tcrdbecode(intern->conn->rdb) TSRMLS_CC, "Unable to store the record '%s': %s", Z_STRVAL(key_cp), tcrdberrmsg(tcrdbecode(intern->conn->rdb))); zval_dtor(&key_cp); zval_dtor(&value_cp); return; } zval_dtor(&value_cp); } zval_dtor(&key_cp); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::put(mixed key[, string value]); Stores a string record @throws TokyoTyrantException if put fails @throws TokyoTyrantException if key is not an array and not value is provided */ PHP_METHOD(tokyotyrant, put) { _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_PUT); } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::putkeep(mixed key[, string value]); Stores a string record if not exists @throws TokyoTyrantException if put fails @throws TokyoTyrantException if key is not an array and not value is provided */ PHP_METHOD(tokyotyrant, putkeep) { _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_PUTKEEP); } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::putcat(mixed key[, string value]); Concatenate a string value @throws TokyoTyrantException if put fails @throws TokyoTyrantException if key is not an array and not value is provided */ PHP_METHOD(tokyotyrant, putcat) { _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_PUTCAT); } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::putnr(mixed key[, string value]); Put a record and don't wait for server to respond @throws TokyoTyrantException if put fails @throws TokyoTyrantException if key is not an array and not value is provided */ PHP_METHOD(tokyotyrant, putnr) { _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_PUTNR); } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::putshl(string key, string value, int width); Concatenate a string value and shift to left @throws TokyoTyrantException if put fails @throws TokyoTyrantException if key is not an array and not value is provided */ PHP_METHOD(tokyotyrant, putshl) { php_tokyo_tyrant_object *intern; char *kbuf, *key, *value; int code, key_len, value_len, new_len; long width; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssl", &key, &key_len, &value, &value_len, &width) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); /* Create a prefix */ kbuf = php_tt_prefix(key, key_len, &new_len TSRMLS_CC); code = tcrdbputshl(intern->conn->rdb, kbuf, new_len, value, value_len, width); efree(kbuf); if (!code) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to putshl the record: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::out(mixed key); Removes a record @throws TokyoTyrantException if remove fails */ PHP_METHOD(tokyotyrant, out) { _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_OUT); } /* }}} */ /* {{{ TokyoTyrantIterator TokyoTyrant::getIterator(); Get iterator object @throws TokyoTyrantException if not connected to a database */ PHP_METHOD(tokyotyrant, getiterator) { php_tokyo_tyrant_object *intern; php_tokyo_tyrant_iterator_object *intern_iterator; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); object_init_ex(return_value, php_tokyo_tyrant_iterator_sc_entry); intern_iterator = (php_tokyo_tyrant_iterator_object *)zend_object_store_get_object(return_value TSRMLS_CC); if (!php_tt_iterator_object_init(intern_iterator, getThis() TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Failed to initialize the iterator: %s"); } return; } /* }}} */ /* {{{ mixed TokyoTyrant::get(mixed key); Gets string record(s) @throws TokyoTyrantException if get fails */ PHP_METHOD(tokyotyrant, get) { php_tokyo_tyrant_object *intern; zval *key; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (Z_TYPE_P(key) == IS_ARRAY) { TCMAP *map = php_tt_zval_to_tcmap(key, 1 TSRMLS_CC); tcrdbget3(intern->conn->rdb, map); if (!map) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the records: %s"); } php_tt_tcmap_to_zval(map, return_value TSRMLS_CC); tcmapdel(map); } else { zval tmpcopy; char *value, *kbuf; int new_len, value_len; tmpcopy = *key; zval_copy_ctor(&tmpcopy); INIT_PZVAL(&tmpcopy); convert_to_string(&tmpcopy); kbuf = php_tt_prefix(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy), &new_len TSRMLS_CC); value = tcrdbget(intern->conn->rdb, kbuf, new_len, &value_len); zval_dtor(&tmpcopy); efree(kbuf); if (!value) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the record: %s"); } RETVAL_STRINGL(value, value_len, 1); free(value); } return; } /* }}} */ /* {{{ int TokyoTyrant::add(string key, mixed value[, CONST type]); Add to a key @throws TokyoTyrantException if sync fails */ PHP_METHOD(tokyotyrant, add) { php_tokyo_tyrant_object *intern; char *key, *kbuf; int key_len = 0, new_len, retint; long type = 0; zval *value; double retdouble; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &key, &key_len, &value, &type) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); kbuf = php_tt_prefix(key, key_len, &new_len TSRMLS_CC); if (type == 0) { if (Z_TYPE_P(value) == IS_DOUBLE) { type = PHP_TOKYO_TYRANT_RECTYPE_DOUBLE; } else { type = PHP_TOKYO_TYRANT_RECTYPE_INT; } } switch (type) { case PHP_TOKYO_TYRANT_RECTYPE_INT: convert_to_long(value); retint = tcrdbaddint(intern->conn->rdb, kbuf, new_len, Z_LVAL_P(value)); if (retint == INT_MIN) { RETURN_NULL(); } RETVAL_LONG(retint); break; case PHP_TOKYO_TYRANT_RECTYPE_DOUBLE: convert_to_double(value); retdouble = tcrdbadddouble(intern->conn->rdb, kbuf, new_len, Z_DVAL_P(value)); if (isnan(retdouble)) { RETURN_NULL(); } RETVAL_DOUBLE(retdouble); break; default: efree(kbuf); PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unknown record type"); break; } efree(kbuf); return; } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::sync(); Flushes the changes to disk @throws TokyoTyrantException if sync fails */ PHP_METHOD(tokyotyrant, sync) { php_tokyo_tyrant_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (!tcrdbsync(intern->conn->rdb)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to synchronise the database: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::tune(float timeout[, int options]); Tunes to options / timeout @throws TokyoTyrantException if sync fails */ PHP_METHOD(tokyotyrant, tune) { php_tokyo_tyrant_object *intern; double timeout; long options = RDBTRECON; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l", &timeout, &options) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (!tcrdbtune(intern->conn->rdb, timeout, options)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to tune the database options: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ TokyoTyrant TokyoTyrant::vanish(); Empties the remote database */ PHP_METHOD(tokyotyrant, vanish) { php_tokyo_tyrant_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (!tcrdbvanish(intern->conn->rdb)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to empty the database: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ string TokyoTyrant::stat(); Gets the status string of the remote database */ PHP_METHOD(tokyotyrant, stat) { php_tokyo_tyrant_object *intern; char *status = NULL, *ptr; char k[1024], v[1024]; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); status = tcrdbstat(intern->conn->rdb); if (!status) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the status string: %s"); } array_init(return_value); /* add elements */ ptr = strtok(status, "\n"); while (ptr) { if (strlen(ptr) >= 1024) { continue; } memset(k, '\0', 1024); memset(v, '\0', 1024); if (sscanf(ptr, "%s %s", k, v) != 2) { continue; } add_assoc_string(return_value, k, v, 1); ptr = strtok(NULL, "\n"); } free(status); return; } /* }}} */ /* {{{ int TokyoTyrant::size(string key); Get the size of a row */ PHP_METHOD(tokyotyrant, size) { php_tokyo_tyrant_object *intern; char *key, *kbuf; int key_len, new_len; long rec_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &key, &key_len) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); kbuf = php_tt_prefix(key, key_len, &new_len TSRMLS_CC); rec_len = tcrdbvsiz2(intern->conn->rdb, kbuf); efree(kbuf); if (rec_len == -1) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the record size: %s"); } RETURN_LONG(rec_len); } /* }}} */ /* {{{ int TokyoTyrant::num(); Number of records in the database */ PHP_METHOD(tokyotyrant, num) { php_tokyo_tyrant_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); RETURN_LONG(tcrdbrnum(intern->conn->rdb)); } /* }}} */ /* {{{ array TokyoTyrant::fwmkeys(string prefix, int max_records) */ PHP_METHOD(tokyotyrant, fwmkeys) { php_tokyo_tyrant_object *intern; char *prefix, *kbuf; int prefix_len, new_len; long max_recs; TCLIST *res = NULL; const char *rbuf; int i, rsiz; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &prefix, &prefix_len, &max_recs) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); res = tcrdbfwmkeys2(intern->conn->rdb, prefix, max_recs); array_init(return_value); for (i = 0; i < tclistnum(res); i++) { rbuf = tclistval(res, i, &rsiz); kbuf = php_tt_prefix((char *)rbuf, rsiz, &new_len TSRMLS_CC); add_next_index_stringl(return_value, kbuf, new_len, 0); } tclistdel(res); return; } /* }}} */ /* {{{ string TokyoTyrant::ext(string name, CONST opts, string key, string value); Get the size of a row */ PHP_METHOD(tokyotyrant, ext) { php_tokyo_tyrant_object *intern; char *name, *key, *value, *response; int name_len, key_len, value_len; long opts; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slss", &name, &name_len, &opts, &key, &key_len, &value, &value_len) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); response = tcrdbext2(intern->conn->rdb, name, opts, key, value); if (!response) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to execute the remote script: %s"); } RETVAL_STRING(response, 1); free(response); return; } /* }}} */ /* {{{ int TokyoTyrant::copy(string path); Copy the database */ PHP_METHOD(tokyotyrant, copy) { php_tokyo_tyrant_object *intern; char *path; int path_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (!tcrdbcopy(intern->conn->rdb, path)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to copy the database: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ #if PHP_MAJOR_VERSION >=5 && PHP_MINOR_VERSION >= 3 static uint_fast64_t _php_tt_get_ts(zval *date_param TSRMLS_DC) { zval *fname, retval, *params[1]; uint_fast64_t ts; MAKE_STD_ZVAL(fname); ZVAL_STRING(fname, "date_timestamp_get", 1); params[0] = date_param; call_user_function(EG(function_table), NULL, fname, &retval, 1, params TSRMLS_CC); zval_dtor(fname); FREE_ZVAL(fname); if (Z_TYPE(retval) != IS_LONG) { return 0; } /* Microseconds */ ts = (uint_fast64_t) Z_LVAL(retval); return (ts * 1000 * 1000); } /* {{{ TokyoTyrant TokyoTyrant::restore(string log_dir, mixed timestamp[, bool check_consistency = true]); restore the database */ PHP_METHOD(tokyotyrant, restore) { zval *date_param; php_tokyo_tyrant_object *intern; char *path; int path_len, opts; uint_fast64_t ts; zend_bool check_consistency = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &path, &path_len, &date_param, &check_consistency) == FAILURE) { return; } #if !defined(__LP64__) && !defined(__ILP64__) PHP_TOKYO_TYRANT_EXCEPTION_MSG("TokyoTyrant::restore is not supported on a 32bit platform"); #endif PHP_TOKYO_CONNECTED_OBJECT(intern); if (Z_TYPE_P(date_param) == IS_OBJECT) { zend_class_entry *date_ce_date = php_date_get_date_ce(); if (!instanceof_function_ex(Z_OBJCE_P(date_param), date_ce_date, 0 TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("The timestamp parameter must be instanceof DateTime"); } ts = _php_tt_get_ts(date_param TSRMLS_CC); if (ts == 0) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Failed to get timestamp from the DateTime object"); } } else { convert_to_long(date_param); ts = (uint_fast64_t) Z_LVAL_P(date_param); } if (check_consistency) { opts |= RDBROCHKCON; } if (!tcrdbrestore(intern->conn->rdb, path, ts, opts)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to restore the database: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ #else /* {{{ TokyoTyrant TokyoTyrant::restore(string log_dir, int timestamp[, bool check_consistency = true]); restore the database */ PHP_METHOD(tokyotyrant, restore) { php_tokyo_tyrant_object *intern; char *path; int path_len, opts; long ts; zend_bool check_consistency = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|b", &path, &path_len, &ts, &check_consistency) == FAILURE) { return; } #if !defined(__LP64__) && !defined(__ILP64__) PHP_TOKYO_TYRANT_EXCEPTION_MSG("TokyoTyrant::restore is not supported on a 32bit platform"); #endif PHP_TOKYO_CONNECTED_OBJECT(intern); if (check_consistency) { opts |= RDBROCHKCON; } if (!tcrdbrestore(intern->conn->rdb, path, (uint_fast64_t)ts, opts)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to restore the database: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ #endif #if PHP_MAJOR_VERSION >=5 && PHP_MINOR_VERSION >= 3 /* {{{ TokyoTyrant TokyoTyrant::setMaster(string host, int port, mixed timestamp[, zend_bool check_consistency]); Set the master */ PHP_METHOD(tokyotyrant, setmaster) { zval *date_param; php_tokyo_tyrant_object *intern; char *host; int host_len, code, opts; long port; uint_fast64_t ts; zend_bool check_consistency = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slz|b", &host, &host_len, &port, &date_param, &check_consistency) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (Z_TYPE_P(date_param) == IS_OBJECT) { zend_class_entry *date_ce_date = php_date_get_date_ce(); if (!instanceof_function_ex(Z_OBJCE_P(date_param), date_ce_date, 0 TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("The timestamp parameter must be instanceof DateTime"); } ts = _php_tt_get_ts(date_param TSRMLS_CC); if (ts == 0) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Failed to get timestamp from the DateTime object"); } } else { convert_to_long(date_param); ts = Z_LVAL_P(date_param); } if (check_consistency) { opts |= RDBROCHKCON; } if (host_len == 0) { code = tcrdbsetmst(intern->conn->rdb, NULL, 0, ts, opts); } else { code = tcrdbsetmst(intern->conn->rdb, host, port, ts, opts); } if (!code) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to set the master: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ #else /* {{{ TokyoTyrant TokyoTyrant::setMaster(string host, int port, int timestamp[, zend_bool check_consistency]); Set the master */ PHP_METHOD(tokyotyrant, setmaster) { php_tokyo_tyrant_object *intern; char *host; int host_len, code; long ts, opts = 0, port; zend_bool check_consistency = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll|b", &host, &host_len, &port, &ts, &check_consistency) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (check_consistency) { opts |= RDBROCHKCON; } if (host_len == 0) { code = tcrdbsetmst(intern->conn->rdb, NULL, 0, (uint_fast64_t)ts, opts); } else { code = tcrdbsetmst(intern->conn->rdb, host, port, (uint_fast64_t)ts, opts); } if (!code) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to set the master: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ #endif /** -------- Begin table api -------- **/ /* {{{ TokyoTyrantQuery TokyoTyrantTable::getquery(); Get query object @throws TokyoTyrantException if not connected to a database */ PHP_METHOD(tokyotyranttable, getquery) { php_tokyo_tyrant_object *intern; php_tokyo_tyrant_query_object *intern_query; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); object_init_ex(return_value, php_tokyo_tyrant_query_sc_entry); intern_query = (php_tokyo_tyrant_query_object *)zend_object_store_get_object(return_value TSRMLS_CC); if (!php_tt_query_object_init(intern_query, getThis() TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to initialize the query: %s"); } return; } /* }}} */ /* {{{ TokyoTyrantQuery TokyoTyrantTable::genUid(); Generate unique PK @throws TokyoTyrantException if not connected to a database @throws TokyoTyrantException if uid generation fails */ PHP_METHOD(tokyotyranttable, genuid) { php_tokyo_tyrant_object *intern; long pk = -1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); pk = (long)tcrdbtblgenuid(intern->conn->rdb); if (pk == -1) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unable to generate a primary key. Not connected to a table database?"); } RETURN_LONG(pk); } /* }}} */ static void _php_tt_table_write_wrapper(INTERNAL_FUNCTION_PARAMETERS, long type) { php_tokyo_tyrant_object *intern; zval *keys; TCMAP *map; char *key = NULL, *kbuf = NULL; int key_len = 0, new_len, code = 0; long pk = -1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!a", &key, &key_len, &keys) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (key) { kbuf = php_tt_prefix(key, key_len, &new_len TSRMLS_CC); } else { char buf[256]; int len; pk = (long)tcrdbtblgenuid(intern->conn->rdb); if (pk == -1) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unable to generate a primary key. Not connected to a table database?"); } len = snprintf(buf, 256, "%ld", pk); kbuf = php_tt_prefix(buf, len, &new_len TSRMLS_CC); } map = php_tt_zval_to_tcmap(keys, 0 TSRMLS_CC); if (!map) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unable to get values from the argument"); } switch (type) { case PHP_TOKYO_TYRANT_OP_TBLPUT: code = tcrdbtblput(intern->conn->rdb, kbuf, new_len, map); break; case PHP_TOKYO_TYRANT_OP_TBLPUTKEEP: code = tcrdbtblputkeep(intern->conn->rdb, kbuf, new_len, map); break; case PHP_TOKYO_TYRANT_OP_TBLPUTCAT: code = tcrdbtblputcat(intern->conn->rdb, kbuf, new_len, map); break; default: tcmapdel(map); efree(kbuf); PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unknown operation type (should not happen)"); break; } tcmapdel(map); if (!code) { efree(kbuf); PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to store columns: %s"); } if (pk > 0) { RETVAL_LONG(pk); efree(kbuf); } else { RETVAL_STRINGL(kbuf, new_len, 0); } return; } /* {{{ int TokyoTyrantTable::put(string pk, array row); put a row. if pk = null new key is generated @throws TokyoTyrantException if not connected to a database @throws TokyoTyrantException if get fails */ PHP_METHOD(tokyotyranttable, put) { _php_tt_table_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_TBLPUT); } /* }}} */ /* {{{ int TokyoTyrantTable::putkeep(string pk, array row); put a row @throws TokyoTyrantException if not connected to a database @throws TokyoTyrantException if get fails */ PHP_METHOD(tokyotyranttable, putkeep) { _php_tt_table_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_TBLPUTKEEP); } /* }}} */ /* {{{ int TokyoTyrantTable::putcat(string pk, array row); put a row @throws TokyoTyrantException if not connected to a database @throws TokyoTyrantException if get fails */ PHP_METHOD(tokyotyranttable, putcat) { _php_tt_table_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_TBLPUTCAT); } /* }}} */ /* {{{ int TokyoTyrantTable::add(void); not supported */ PHP_METHOD(tokyotyranttable, add) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("add operation is not supported with table databases"); } /* }}} */ /* {{{ int TokyoTyrantTable::putShl(void); not supported */ PHP_METHOD(tokyotyranttable, putshl) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("putShl operation is not supported with table databases"); } /* }}} */ /* {{{ int TokyoTyrantTable::putnr(void); not supported */ PHP_METHOD(tokyotyranttable, putnr) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("putNr operation is not supported with table databases"); } /* }}} */ /* {{{ int TokyoTyrantTable::get(mixed pk); Get a table entry @throws TokyoTyrantException if not connected to a database @throws TokyoTyrantException if get fails */ PHP_METHOD(tokyotyranttable, get) { php_tokyo_tyrant_object *intern; TCMAP *map; zval *key; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if(Z_TYPE_P(key) == IS_ARRAY){ map = php_tt_zval_to_tcmap(key, 1 TSRMLS_CC); tcrdbget3(intern->conn->rdb, map); if (!map) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the records: %s"); } php_tt_tcmapstring_to_zval(map, return_value TSRMLS_CC); tcmapdel(map); }else{ zval tmpcopy; char *kbuf; int new_len; tmpcopy = *key; zval_copy_ctor(&tmpcopy); INIT_PZVAL(&tmpcopy); convert_to_string(&tmpcopy); kbuf = php_tt_prefix(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy), &new_len TSRMLS_CC); map = tcrdbtblget(intern->conn->rdb, kbuf, new_len); zval_dtor(&tmpcopy); efree(kbuf); if (!map) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the record: %s"); } php_tt_tcmap_to_zval(map, return_value TSRMLS_CC); } return; } /* }}} */ /* {{{ boolean TokyoTyrantTable::out(mixed pk); Remove an entry @throws TokyoTyrantException if not connected to a database @throws TokyoTyrantException if get fails */ PHP_METHOD(tokyotyranttable, out) { _php_tt_write_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_TOKYO_TYRANT_OP_TBLOUT); } /* }}} */ /* {{{ boolean TokyoTyrantTable::setIndex(string name, CONST type); Set index @throws TokyoTyrantException if not connected to a database @throws TokyoTyrantException if get fails */ PHP_METHOD(tokyotyranttable, setindex) { php_tokyo_tyrant_object *intern; char *name; int name_len; long type; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &name, &name_len, &type) == FAILURE) { return; } PHP_TOKYO_CONNECTED_OBJECT(intern); if (!tcrdbtblsetindex(intern->conn->rdb, name, type)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to set index: %s"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /** -------- end table api -------- **/ /** -------- Begin Table Query API --------- **/ /* {{{ string TokyoTyrantQuery::__construct(TokyoTyrant conn); construct a query */ PHP_METHOD(tokyotyrantquery, __construct) { zval *objvar; php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &objvar, php_tokyo_tyrant_sc_entry) == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; if (!php_tt_query_object_init(intern, objvar TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to initialize the query: %s"); } return; } /* }}} */ /* {{{ string TokyoTyrantQuery::setLimit([int max, int skip]); Set the limit on the query */ PHP_METHOD(tokyotyrantquery, setlimit) { php_tokyo_tyrant_query_object *intern; zval *max = NULL, *skip = NULL; long l_max = -1, l_skip = -1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!z!", &max, &skip) == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; if (max) { if (Z_TYPE_P(max) != IS_LONG) { convert_to_long(max); } l_max = Z_LVAL_P(max); } if (skip) { if (Z_TYPE_P(skip) != IS_LONG) { convert_to_long(skip); } l_skip = Z_LVAL_P(skip); } tcrdbqrysetlimit(intern->qry, l_max, l_skip); PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ string TokyoTyrantQuery::setOrder(string name, int type); Set the order of a query */ PHP_METHOD(tokyotyrantquery, setorder) { php_tokyo_tyrant_query_object *intern; char *name; int name_len; long type; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &name, &name_len, &type) == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; tcrdbqrysetorder(intern->qry, name, type); PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /* {{{ string TokyoTyrantQuery::addCond(string column, int operator, string expression); Add a condition */ PHP_METHOD(tokyotyrantquery, addcond) { php_tokyo_tyrant_query_object *intern; char *name, *expr; int name_len, expr_len; long op; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls", &name, &name_len, &op, &expr, &expr_len) == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; tcrdbqryaddcond(intern->qry, name, op, expr); PHP_TOKYO_CHAIN_METHOD; } /* }}} */ #if PHP_TOKYO_TYRANT_VERSION >= 1001033 /* {{{ string TokyoTyrantQuery::hint(); Get the hint string of a query object */ PHP_METHOD(tokyotyrantquery, hint) { php_tokyo_tyrant_query_object *intern; const char *hint; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; hint = tcrdbqryhint(intern->qry); RETURN_STRING((char *)hint, 1); } /* }}} */ /* {{{ string TokyoTyrantQuery::metaSearch(array queries, int type); Retrieve records with multiple query objects */ PHP_METHOD(tokyotyrantquery, metasearch) { php_tokyo_tyrant_query_object *intern; zval *queries; long type; RDBQRY **qrys; int num_qrys, i = 0; TCLIST *res; HashPosition pos; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al", &queries, &type) == FAILURE) { return; } /* Queries in array and self */ num_qrys = zend_hash_num_elements(Z_ARRVAL_P(queries)) + 1; qrys = emalloc(num_qrys * sizeof(RDBQRY *)); /* Self is always the 'left-most' */ intern = PHP_TOKYO_QUERY_OBJECT; qrys[i++] = intern->qry; for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(queries), &pos); zend_hash_has_more_elements_ex(Z_ARRVAL_P(queries), &pos) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(queries), &pos)) { zval **ppzval; if (zend_hash_get_current_data_ex(Z_ARRVAL_P(queries), (void**)&ppzval, &pos) == SUCCESS && Z_TYPE_PP(ppzval) == IS_OBJECT && instanceof_function_ex(Z_OBJCE_PP(ppzval), php_tokyo_tyrant_query_sc_entry, 0 TSRMLS_CC)) { php_tokyo_tyrant_query_object *intern_query; zval tmpcopy = **ppzval; zval_copy_ctor(&tmpcopy); INIT_PZVAL(&tmpcopy); intern_query = (php_tokyo_tyrant_query_object *)zend_object_store_get_object(&tmpcopy TSRMLS_CC); qrys[i++] = intern_query->qry; zval_dtor(&tmpcopy); } else { efree(qrys); PHP_TOKYO_TYRANT_EXCEPTION_MSG("The parameter must contain only TokyoTyrantQuery instances"); } } res = tcrdbmetasearch(qrys, num_qrys, type); efree(qrys); array_init(return_value); php_tt_tclist_to_array(intern->conn->rdb, res, return_value TSRMLS_CC); tclistdel(res); return; } /* }}} */ #endif /* {{{ array TokyoTyrantQuery::search(); Executes a search query and returns results */ PHP_METHOD(tokyotyrantquery, search) { php_tokyo_tyrant_query_object *intern; TCLIST *res; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; res = tcrdbqrysearch(intern->qry); array_init(return_value); php_tt_tclist_to_array(intern->conn->rdb, res, return_value TSRMLS_CC); tclistdel(res); return; } /* }}} */ /* {{{ array TokyoTyrantQuery::count(); Executes a search query and return the count of corresponding records. */ PHP_METHOD(tokyotyrantquery, count) { php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; RETURN_LONG(tcrdbqrysearchcount(intern->qry)); } /* }}} */ /* {{{ TokyoTyrantQuery TokyoTyrantQuery::out(); Executes a delete query */ PHP_METHOD(tokyotyrantquery, out) { php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; if (!tcrdbqrysearchout(intern->qry)) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unable to execute out query"); } PHP_TOKYO_CHAIN_METHOD; } /* }}} */ /******* Start query iterator interface ******/ /* {{{ mixed TokyoTyrantQuery::key(); Gets the current key */ PHP_METHOD(tokyotyrantquery, key) { php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; if (intern->pos < tclistnum(intern->res)) { const char *rbuf; int rsiz; rbuf = tclistval(intern->res, intern->pos, &rsiz); if (!rbuf) { RETURN_FALSE; } RETURN_STRINGL((char *)rbuf, rsiz, 1); } else { RETURN_FALSE; } } /* }}} */ /* {{{ mixed TokyoTyrantQuery::next(); Move to next value and return it */ PHP_METHOD(tokyotyrantquery, next) { php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; if (++(intern->pos) < tclistnum(intern->res)) { TCMAP *cols; const char *rbuf, *name; int rsiz; rbuf = tclistval(intern->res, intern->pos, &rsiz); if (!rbuf) { RETURN_FALSE; } cols = tcrdbtblget(intern->conn->rdb, rbuf, rsiz); if (cols) { int name_len; array_init(return_value); tcmapiterinit(cols); while ((name = tcmapiternext(cols, &name_len)) != NULL) { int data_len; const char *data; data = tcmapget(cols, name, name_len, &data_len); add_assoc_stringl(return_value, (char *)name, (char *)data, data_len, 1); } tcmapdel(cols); return; } } RETURN_FALSE; } /* }}} */ /* {{{ mixed TokyoTyrantQuery::rewind(); Start from the beginning */ PHP_METHOD(tokyotyrantquery, rewind) { php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; if (!intern->executed) { if (intern->res) { tclistdel(intern->res); } intern->res = tcrdbqrysearch(intern->qry); } intern->pos = 0; RETURN_TRUE; } /* }}} */ /* {{{ mixed TokyoTyrantQuery::current(); Returns the current value */ PHP_METHOD(tokyotyrantquery, current) { php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; if (intern->pos < tclistnum(intern->res)) { const char *rbuf, *name; int rsiz; TCMAP *cols; rbuf = tclistval(intern->res, intern->pos, &rsiz); if (!rbuf) { RETURN_FALSE; } cols = tcrdbtblget(intern->conn->rdb, rbuf, rsiz); if (cols) { int name_len; array_init(return_value); tcmapiterinit(cols); while ((name = tcmapiternext(cols, &name_len)) != NULL) { int data_len; const char *data; data = tcmapget(cols, name, name_len, &data_len); add_assoc_stringl(return_value, (char *)name, (char *)data, data_len, 1); } tcmapdel(cols); return; } } RETURN_FALSE; } /* }}} */ /* {{{ boolean TokyoTyrantQuery::valid(); Whether the current item is valid */ PHP_METHOD(tokyotyrantquery, valid) { php_tokyo_tyrant_query_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_QUERY_OBJECT; RETURN_BOOL(intern->pos < tclistnum(intern->res)); } /* }}} */ /******* End query iterator interface *********/ /** -------- End Table Query API --------- **/ /** -------- Start tokyo tyrant iterator ------- **/ PHP_METHOD(tokyotyrantiterator, __construct) { php_tokyo_tyrant_iterator_object *intern; zval *objvar; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &objvar) == FAILURE) { return; } if (Z_TYPE_P(objvar) != IS_OBJECT) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("The parameter must be a valid TokyoTyrant or TokyoTyrantTable object"); } intern = PHP_TOKYO_ITERATOR_OBJECT; if (!php_tt_iterator_object_init(intern, objvar TSRMLS_CC)) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Failed to initialize the iterator: %s"); } return; } PHP_METHOD(tokyotyrantiterator, key) { php_tokyo_tyrant_iterator_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_ITERATOR_OBJECT; if (!intern->current) { RETURN_LONG(0); } else { RETURN_STRINGL(intern->current, intern->current_len, 1); } } PHP_METHOD(tokyotyrantiterator, next) { php_tokyo_tyrant_iterator_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_ITERATOR_OBJECT; if (intern->current) { free(intern->current); intern->current = NULL; } intern->current_len = 0; intern->current = tcrdbiternext(intern->conn->rdb, &(intern->current_len)); } PHP_METHOD(tokyotyrantiterator, rewind) { php_tokyo_tyrant_iterator_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_ITERATOR_OBJECT; /* The iterator has been traversed */ if (!tcrdbiterinit(intern->conn->rdb)) { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Failed to rewind the iterator"); } if (intern->current) { free(intern->current); intern->current = NULL; } intern->current_len = 0; intern->current = tcrdbiternext(intern->conn->rdb, &(intern->current_len)); return; } PHP_METHOD(tokyotyrantiterator, current) { php_tokyo_tyrant_iterator_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_ITERATOR_OBJECT; if (intern->iterator_type == PHP_TOKYO_TYRANT_ITERATOR) { char *value, *kbuf; int new_len, value_len; kbuf = php_tt_prefix(intern->current, intern->current_len, &new_len TSRMLS_CC); value = tcrdbget(intern->conn->rdb, kbuf, new_len, &value_len); efree(kbuf); if (!value) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the record: %s"); } RETVAL_STRINGL(value, value_len, 1); free(value); } else if (intern->iterator_type == PHP_TOKYO_TYRANT_TABLE_ITERATOR) { TCMAP *map; char *kbuf; int new_len; kbuf = php_tt_prefix(intern->current, intern->current_len, &new_len TSRMLS_CC); map = tcrdbtblget(intern->conn->rdb, kbuf, new_len); efree(kbuf); if (!map) { PHP_TOKYO_TYRANT_EXCEPTION(intern, "Unable to get the record: %s"); } php_tt_tcmap_to_zval(map, return_value TSRMLS_CC); } else { PHP_TOKYO_TYRANT_EXCEPTION_MSG("Unknown iterator type (this should not happen)"); } return; } PHP_METHOD(tokyotyrantiterator, valid) { php_tokyo_tyrant_iterator_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { return; } intern = PHP_TOKYO_ITERATOR_OBJECT; if (intern->current) { RETURN_TRUE; } RETURN_FALSE; } /** -------- End tokyo tyrant iterator ------- **/ ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_empty_args, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_construct_args, 0, 0, 0) ZEND_ARG_INFO(0, host) ZEND_ARG_INFO(0, port) ZEND_ARG_INFO(0, persistent) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_connect_args, 0, 0, 1) ZEND_ARG_INFO(0, host) ZEND_ARG_INFO(0, port) ZEND_ARG_INFO(0, persistent) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_connecturi_args, 0, 0, 1) ZEND_ARG_INFO(0, uri) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_put_args, 0, 0, 1) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_putshl_args, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, width) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_get_args, 0, 0, 1) ZEND_ARG_INFO(0, keys) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_out_args, 0, 0, 1) ZEND_ARG_INFO(0, keys) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_stat_args, 0, 0, 0) ZEND_ARG_INFO(0, params) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_tune_args, 0, 0, 1) ZEND_ARG_INFO(0, timeout) ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_tableput_args, 0, 0, 1) ZEND_ARG_INFO(0, columns) ZEND_ARG_INFO(0, pk) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_add_args, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_size_args, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_fwmkeys_args, 0, 0, 2) ZEND_ARG_INFO(0, prefix) ZEND_ARG_INFO(0, max_recs) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_ext_args, 0, 0, 4) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, options) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_copy_args, 0, 0, 1) ZEND_ARG_INFO(0, path) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_restore_args, 0, 0, 2) ZEND_ARG_INFO(0, log_dir) ZEND_ARG_INFO(0, timestamp) ZEND_ARG_INFO(0, check_consistency) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_setmaster_args, 0, 0, 3) ZEND_ARG_INFO(0, host) ZEND_ARG_INFO(0, port) ZEND_ARG_INFO(0, timestamp) ZEND_ARG_INFO(0, check_consistency) ZEND_END_ARG_INFO() static function_entry php_tokyo_tyrant_class_methods[] = { PHP_ME(tokyotyrant, __construct, tokyo_tyrant_construct_args, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(tokyotyrant, connect, tokyo_tyrant_connect_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, connecturi, tokyo_tyrant_connecturi_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, vanish, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, stat, tokyo_tyrant_stat_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, tune, tokyo_tyrant_tune_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, fwmkeys, tokyo_tyrant_fwmkeys_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, size, tokyo_tyrant_size_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, num, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, sync, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, ext, tokyo_tyrant_ext_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, copy, tokyo_tyrant_copy_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, restore, tokyo_tyrant_restore_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, setmaster, tokyo_tyrant_setmaster_args, ZEND_ACC_PUBLIC) /* These are the shared methods */ PHP_ME(tokyotyrant, put, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, putkeep, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, putcat, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, get, tokyo_tyrant_get_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, out, tokyo_tyrant_out_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, getiterator, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) /* These throw exception on table api */ PHP_ME(tokyotyrant, add, tokyo_tyrant_add_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, putshl, tokyo_tyrant_putshl_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrant, putnr, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_table_setindex_args, 0, 0, 2) ZEND_ARG_INFO(0, column) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO() static function_entry php_tokyo_tyrant_table_class_methods[] = { /* Inherit and override */ PHP_ME(tokyotyranttable, put, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, putkeep, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, putcat, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, get, tokyo_tyrant_get_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, out, tokyo_tyrant_out_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, setindex, tokyo_tyrant_table_setindex_args, ZEND_ACC_PUBLIC) /* Inherit and throw error if used */ PHP_ME(tokyotyranttable, add, tokyo_tyrant_add_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, putshl, tokyo_tyrant_putshl_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, putnr, tokyo_tyrant_put_args, ZEND_ACC_PUBLIC) /* Table API */ PHP_ME(tokyotyranttable, getquery, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyranttable, genuid, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_query_construct_args, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, TokyoTyrantTable, TokyoTyrantTable, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_query_addcond_args, 0, 0, 3) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, op) ZEND_ARG_INFO(0, expr) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_query_setlimit_args, 0, 0, 0) ZEND_ARG_INFO(0, max) ZEND_ARG_INFO(0, skip) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_query_setorder_args, 0, 0, 2) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_query_metasearch_args, 0, 0, 2) ZEND_ARG_INFO(0, queries) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO() static function_entry php_tokyo_tyrant_query_class_methods[] = { PHP_ME(tokyotyrantquery, __construct, tokyo_tyrant_query_construct_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, addcond, tokyo_tyrant_query_addcond_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, setlimit, tokyo_tyrant_query_setlimit_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, setorder, tokyo_tyrant_query_setorder_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, search, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, count, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, out, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) #if PHP_TOKYO_TYRANT_VERSION >= 1001033 PHP_ME(tokyotyrantquery, hint, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, metasearch, tokyo_tyrant_query_metasearch_args, ZEND_ACC_PUBLIC) #endif PHP_ME(tokyotyrantquery, key, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, next, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, rewind, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, current, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantquery, valid, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; ZEND_BEGIN_ARG_INFO_EX(tokyo_tyrant_iterator_construct_args, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, TokyoTyrant, TokyoTyrant, 0) ZEND_END_ARG_INFO() static function_entry php_tokyo_tyrant_iterator_class_methods[] = { /* Iterator interface */ PHP_ME(tokyotyrantiterator, __construct, tokyo_tyrant_iterator_construct_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantiterator, key, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantiterator, next, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantiterator, rewind, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantiterator, current, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) PHP_ME(tokyotyrantiterator, valid, tokyo_tyrant_empty_args, ZEND_ACC_PUBLIC) { NULL, NULL, NULL } }; zend_function_entry tokyo_tyrant_functions[] = { {NULL, NULL, NULL} }; static void php_tokyo_tyrant_query_object_free_storage(void *object TSRMLS_DC) { php_tokyo_tyrant_query_object *intern = (php_tokyo_tyrant_query_object *)object; if (!intern) { return; } if (intern->parent) { #ifdef Z_REFCOUNT_P Z_SET_REFCOUNT_P(intern->parent, Z_REFCOUNT_P(intern->parent) - 1); if (Z_REFCOUNT_P(intern->parent) <= 0) { #else intern->parent->refcount--; if (intern->parent->refcount == 0) { #endif /* TODO: check if this leaks */ efree(intern->parent); } } if (intern->res) { tclistdel(intern->res); } if (intern->qry) tcrdbqrydel(intern->qry); zend_object_std_dtor(&intern->zo TSRMLS_CC); efree(intern); } static zend_object_value php_tokyo_tyrant_query_object_new(zend_class_entry *class_type TSRMLS_DC) { zval *tmp; zend_object_value retval; php_tokyo_tyrant_query_object *intern; /* Allocate memory for it */ intern = (php_tokyo_tyrant_query_object *) emalloc(sizeof(php_tokyo_tyrant_query_object)); memset(&intern->zo, 0, sizeof(zend_object)); intern->executed = 0; intern->qry = NULL; intern->res = NULL; intern->parent = NULL; zend_object_std_init(&intern->zo, class_type TSRMLS_CC); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) php_tokyo_tyrant_query_object_free_storage, NULL TSRMLS_CC); retval.handlers = (zend_object_handlers *) &tokyo_tyrant_query_object_handlers; return retval; } static void php_tokyo_tyrant_iterator_object_free_storage(void *object TSRMLS_DC) { php_tokyo_tyrant_iterator_object *intern = (php_tokyo_tyrant_iterator_object *)object; if (!intern) { return; } if (intern->current) { free(intern->current); } if (intern->parent) { #ifdef Z_REFCOUNT_P Z_SET_REFCOUNT_P(intern->parent, Z_REFCOUNT_P(intern->parent) - 1); if (Z_REFCOUNT_P(intern->parent) <= 0) { #else intern->parent->refcount--; if (intern->parent->refcount == 0) { #endif /* TODO: check if this leaks */ efree(intern->parent); } } zend_object_std_dtor(&intern->zo TSRMLS_CC); efree(intern); } static zend_object_value php_tokyo_tyrant_iterator_object_new(zend_class_entry *class_type TSRMLS_DC) { zval *tmp; zend_object_value retval; php_tokyo_tyrant_iterator_object *intern; /* Allocate memory for it */ intern = (php_tokyo_tyrant_iterator_object *) emalloc(sizeof(php_tokyo_tyrant_iterator_object)); memset(&intern->zo, 0, sizeof(zend_object)); intern->conn = NULL; intern->parent = NULL; intern->current = NULL; zend_object_std_init(&intern->zo, class_type TSRMLS_CC); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) php_tokyo_tyrant_iterator_object_free_storage, NULL TSRMLS_CC); retval.handlers = (zend_object_handlers *) &tokyo_tyrant_iterator_object_handlers; return retval; } static void php_tokyo_tyrant_object_free_storage(void *object TSRMLS_DC) { php_tokyo_tyrant_object *intern = (php_tokyo_tyrant_object *)object; if (!intern) { return; } php_tt_conn_deinit(intern->conn TSRMLS_CC); zend_object_std_dtor(&intern->zo TSRMLS_CC); efree(intern); } static zend_object_value php_tokyo_tyrant_object_new_ex(zend_class_entry *class_type, php_tokyo_tyrant_object **ptr TSRMLS_DC) { zval *tmp; zend_object_value retval; php_tokyo_tyrant_object *intern; /* Allocate memory for it */ intern = (php_tokyo_tyrant_object *) emalloc(sizeof(php_tokyo_tyrant_object)); memset(&intern->zo, 0, sizeof(zend_object)); /* Init the object. TODO: clone might leak */ php_tt_object_init(intern TSRMLS_CC); if (ptr) { *ptr = intern; } zend_object_std_init(&intern->zo, class_type TSRMLS_CC); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) php_tokyo_tyrant_object_free_storage, NULL TSRMLS_CC); retval.handlers = (zend_object_handlers *) &tokyo_tyrant_object_handlers; return retval; } static zend_object_value php_tokyo_tyrant_object_new(zend_class_entry *class_type TSRMLS_DC) { return php_tokyo_tyrant_object_new_ex(class_type, NULL TSRMLS_CC); } static zend_object_value php_tokyo_tyrant_clone_object(zval *this_ptr TSRMLS_DC) { php_tokyo_tyrant_object *new_obj = NULL; php_tokyo_tyrant_object *old_obj = (php_tokyo_tyrant_object *) zend_object_store_get_object(this_ptr TSRMLS_CC); zend_object_value new_ov = php_tokyo_tyrant_object_new_ex(old_obj->zo.ce, &new_obj TSRMLS_CC); if (old_obj->conn->connected) { php_tt_connect_ex(new_obj->conn, old_obj->conn->rdb->host, old_obj->conn->rdb->port, old_obj->conn->rdb->timeout, old_obj->conn->persistent TSRMLS_CC); } zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); return new_ov; } static PHP_INI_MH(OnUpdateKeyPrefix) { if (new_value_length > 0) { TOKYO_G(key_prefix_len) = new_value_length; } else { TOKYO_G(key_prefix_len) = 0; } return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); } PHP_INI_BEGIN() STD_PHP_INI_ENTRY("tokyo_tyrant.default_timeout", "0.0", PHP_INI_ALL, OnUpdateReal, default_timeout, zend_tokyo_tyrant_globals, tokyo_tyrant_globals) STD_PHP_INI_ENTRY("tokyo_tyrant.session_salt", "", PHP_INI_ALL, OnUpdateString, salt, zend_tokyo_tyrant_globals, tokyo_tyrant_globals) STD_PHP_INI_ENTRY("tokyo_tyrant.key_prefix", "", PHP_INI_ALL, OnUpdateKeyPrefix, key_prefix, zend_tokyo_tyrant_globals, tokyo_tyrant_globals) STD_PHP_INI_ENTRY("tokyo_tyrant.allow_failover", "1", PHP_INI_ALL, OnUpdateBool, allow_failover, zend_tokyo_tyrant_globals, tokyo_tyrant_globals) STD_PHP_INI_ENTRY("tokyo_tyrant.fail_threshold", "5", PHP_INI_ALL, OnUpdateLong, fail_threshold, zend_tokyo_tyrant_globals, tokyo_tyrant_globals) STD_PHP_INI_ENTRY("tokyo_tyrant.health_check_divisor", "1000", PHP_INI_ALL, OnUpdateLong, health_check_divisor, zend_tokyo_tyrant_globals, tokyo_tyrant_globals) STD_PHP_INI_ENTRY("tokyo_tyrant.php_expiration", "0", PHP_INI_ALL, OnUpdateBool, php_expiration, zend_tokyo_tyrant_globals, tokyo_tyrant_globals) PHP_INI_END() static void php_tokyo_tyrant_init_globals(zend_tokyo_tyrant_globals *tokyo_tyrant_globals) { tokyo_tyrant_globals->connections = NULL; tokyo_tyrant_globals->failures = NULL; tokyo_tyrant_globals->default_timeout = 0.0; tokyo_tyrant_globals->salt = NULL; tokyo_tyrant_globals->key_prefix = NULL; tokyo_tyrant_globals->key_prefix_len = 0; tokyo_tyrant_globals->allow_failover = 1; tokyo_tyrant_globals->fail_threshold = 5; tokyo_tyrant_globals->health_check_divisor = 1000; tokyo_tyrant_globals->php_expiration = 0; } PHP_MINIT_FUNCTION(tokyo_tyrant) { zend_class_entry ce; ZEND_INIT_MODULE_GLOBALS(tokyo_tyrant, php_tokyo_tyrant_init_globals, NULL); REGISTER_INI_ENTRIES(); memcpy(&tokyo_tyrant_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); memcpy(&tokyo_tyrant_table_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); memcpy(&tokyo_tyrant_query_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); memcpy(&tokyo_tyrant_iterator_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); INIT_CLASS_ENTRY(ce, "tokyotyrant", php_tokyo_tyrant_class_methods); ce.create_object = php_tokyo_tyrant_object_new; tokyo_tyrant_object_handlers.clone_obj = php_tokyo_tyrant_clone_object; php_tokyo_tyrant_sc_entry = zend_register_internal_class(&ce TSRMLS_CC); INIT_CLASS_ENTRY(ce, "tokyotyranttable", php_tokyo_tyrant_table_class_methods); ce.create_object = php_tokyo_tyrant_object_new; tokyo_tyrant_table_object_handlers.clone_obj = php_tokyo_tyrant_clone_object; php_tokyo_tyrant_table_sc_entry = zend_register_internal_class_ex(&ce, php_tokyo_tyrant_sc_entry, NULL TSRMLS_CC); INIT_CLASS_ENTRY(ce, "tokyotyrantquery", php_tokyo_tyrant_query_class_methods); ce.create_object = php_tokyo_tyrant_query_object_new; tokyo_tyrant_query_object_handlers.clone_obj = NULL; php_tokyo_tyrant_query_sc_entry = zend_register_internal_class(&ce TSRMLS_CC); zend_class_implements(php_tokyo_tyrant_query_sc_entry TSRMLS_CC, 1, zend_ce_iterator); INIT_CLASS_ENTRY(ce, "tokyotyrantiterator", php_tokyo_tyrant_iterator_class_methods); ce.create_object = php_tokyo_tyrant_iterator_object_new; tokyo_tyrant_iterator_object_handlers.clone_obj = NULL; php_tokyo_tyrant_iterator_sc_entry = zend_register_internal_class(&ce TSRMLS_CC); zend_class_implements(php_tokyo_tyrant_iterator_sc_entry TSRMLS_CC, 1, zend_ce_iterator); INIT_CLASS_ENTRY(ce, "tokyotyrantexception", NULL); php_tokyo_tyrant_exception_sc_entry = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); php_tokyo_tyrant_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL; #define TOKYO_REGISTER_CONST_LONG(const_name, value) \ zend_declare_class_constant_long(php_tokyo_tyrant_sc_entry, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC); /* Non Tokyo Tyrant constants */ TOKYO_REGISTER_CONST_LONG("RDBDEF_PORT", PHP_TOKYO_TYRANT_DEFAULT_PORT); TOKYO_REGISTER_CONST_LONG("RDBREC_INT", PHP_TOKYO_TYRANT_RECTYPE_INT); TOKYO_REGISTER_CONST_LONG("RDBREC_DBL", PHP_TOKYO_TYRANT_RECTYPE_DOUBLE); /* And the rest */ TOKYO_REGISTER_CONST_LONG("RDBQC_STREQ", RDBQCSTREQ); /* string is equal to */ TOKYO_REGISTER_CONST_LONG("RDBQC_STRINC", RDBQCSTRINC); /* string is included in */ TOKYO_REGISTER_CONST_LONG("RDBQC_STRBW", RDBQCSTRBW); /* string begins with */ TOKYO_REGISTER_CONST_LONG("RDBQC_STREW", RDBQCSTREW); /* string ends with */ TOKYO_REGISTER_CONST_LONG("RDBQC_STRAND", RDBQCSTRAND); /* string includes all tokens in */ TOKYO_REGISTER_CONST_LONG("RDBQC_STROR", RDBQCSTROR); /* string includes at least one token in */ TOKYO_REGISTER_CONST_LONG("RDBQC_STROREQ", RDBQCSTROREQ); /* string is equal to at least one token in */ TOKYO_REGISTER_CONST_LONG("RDBQC_STRRX", RDBQCSTRRX); /* string matches regular expressions of */ TOKYO_REGISTER_CONST_LONG("RDBQC_NUMEQ", RDBQCNUMEQ); /* number is equal to */ TOKYO_REGISTER_CONST_LONG("RDBQC_NUMGT", RDBQCNUMGT); /* number is greater than */ TOKYO_REGISTER_CONST_LONG("RDBQC_NUMGE", RDBQCNUMGE); /* number is greater than or equal to */ TOKYO_REGISTER_CONST_LONG("RDBQC_NUMLT", RDBQCNUMLT); /* number is less than */ TOKYO_REGISTER_CONST_LONG("RDBQC_NUMLE", RDBQCNUMLE); /* number is less than or equal to */ TOKYO_REGISTER_CONST_LONG("RDBQC_NUMBT", RDBQCNUMBT); /* number is between two tokens of */ TOKYO_REGISTER_CONST_LONG("RDBQC_NUMOREQ", RDBQCNUMOREQ); /* number is equal to at least one token in */ TOKYO_REGISTER_CONST_LONG("RDBQC_NEGATE", RDBQCNEGATE); /* negation flag */ TOKYO_REGISTER_CONST_LONG("RDBQC_NOIDX", RDBQCNOIDX); /* no index flag */ #if PHP_TOKYO_TYRANT_VERSION >= 1001029 TOKYO_REGISTER_CONST_LONG("RDBQCFTS_PH", RDBQCFTSPH); /* full-text search with the phrase of */ TOKYO_REGISTER_CONST_LONG("RDBQCFTS_AND", RDBQCFTSAND); /* full-text search with all tokens in */ TOKYO_REGISTER_CONST_LONG("RDBQCFTS_OR", RDBQCFTSOR); /* full-text search with at least one token in */ TOKYO_REGISTER_CONST_LONG("RDBQCFTS_EX", RDBQCFTSEX); /* full-text search with the compound expression of */ #endif TOKYO_REGISTER_CONST_LONG("RDBXOLCK_REC", RDBXOLCKREC); /* record locking */ TOKYO_REGISTER_CONST_LONG("RDBXOLCK_GLB", RDBXOLCKGLB); /* global locking */ TOKYO_REGISTER_CONST_LONG("RDBQO_STRASC", RDBQOSTRASC); /* string ascending */ TOKYO_REGISTER_CONST_LONG("RDBQO_STRDESC", RDBQOSTRDESC); /* string descending */ TOKYO_REGISTER_CONST_LONG("RDBQO_NUMASC", RDBQONUMASC); /* number ascending */ TOKYO_REGISTER_CONST_LONG("RDBQO_NUMDESC", RDBQONUMDESC); /* number descending */ TOKYO_REGISTER_CONST_LONG("RDBIT_LEXICAL", RDBITLEXICAL); /* lexical string */ TOKYO_REGISTER_CONST_LONG("RDBIT_DECIMAL", RDBITDECIMAL); /* decimal string */ TOKYO_REGISTER_CONST_LONG("RDBIT_OPT", RDBITOPT); /* optimize */ TOKYO_REGISTER_CONST_LONG("RDBIT_VOID", RDBITVOID); /* void */ TOKYO_REGISTER_CONST_LONG("RDBIT_KEEP", RDBITKEEP); /* keep existing index */ #if PHP_TOKYO_TYRANT_VERSION >= 1001029 TOKYO_REGISTER_CONST_LONG("RDBIT_TOKEN", RDBITTOKEN); /* token inverted index */ TOKYO_REGISTER_CONST_LONG("RDBIT_QGRAM", RDBITQGRAM); /* q-gram inverted index */ #endif TOKYO_REGISTER_CONST_LONG("TTE_SUCCESS", TTESUCCESS); /* success */ TOKYO_REGISTER_CONST_LONG("TTE_INVALID", TTEINVALID); /* invalid operation */ TOKYO_REGISTER_CONST_LONG("TTE_NOHOST", TTENOHOST); /* host not found */ TOKYO_REGISTER_CONST_LONG("TTE_REFUSED", TTEREFUSED); /* connection refused */ TOKYO_REGISTER_CONST_LONG("TTE_SEND", TTESEND); /* send error */ TOKYO_REGISTER_CONST_LONG("TTE_RECV", TTERECV); /* recv error */ TOKYO_REGISTER_CONST_LONG("TTE_KEEP", TTEKEEP); /* existing record */ TOKYO_REGISTER_CONST_LONG("TTE_NOREC", TTENOREC); /* no record found */ TOKYO_REGISTER_CONST_LONG("TTE_MISC", TTEMISC); /* miscellaneous error */ #if PHP_TOKYO_TYRANT_VERSION >= 1001033 TOKYO_REGISTER_CONST_LONG("RDBMS_UNION", RDBMSUNION); /* union */ TOKYO_REGISTER_CONST_LONG("RDBMS_ISECT", RDBMSISECT); /* intersection */ TOKYO_REGISTER_CONST_LONG("RDBMS_DIFF", RDBMSDIFF); /* difference */ #endif TOKYO_REGISTER_CONST_LONG("RDBT_RECON", RDBTRECON); /* reconnect */ #undef TOKYO_REGISTER_CONST_LONG #ifdef HAVE_PHP_TOKYO_TYRANT_SESSION php_session_register_module(ps_tokyo_tyrant_ptr); #endif return SUCCESS; } static int _php_tt_connections_hash_dtor(TCRDB **datas TSRMLS_DC) { TCRDB *rdb = *datas; tcrdbdel(rdb); return ZEND_HASH_APPLY_REMOVE; } PHP_MSHUTDOWN_FUNCTION(tokyo_tyrant) { if (TOKYO_G(connections)) { zend_hash_apply(TOKYO_G(connections), (apply_func_t)_php_tt_connections_hash_dtor TSRMLS_CC); zend_hash_destroy(TOKYO_G(connections)); free(TOKYO_G(connections)); TOKYO_G(connections) = NULL; } if (TOKYO_G(failures)) { zend_hash_destroy(TOKYO_G(failures)); free(TOKYO_G(failures)); TOKYO_G(failures) = NULL; } UNREGISTER_INI_ENTRIES(); return SUCCESS; } PHP_MINFO_FUNCTION(tokyo_tyrant) { php_info_print_table_start(); php_info_print_table_header(2, "tokyo_tyrant extension", "enabled"); php_info_print_table_row(2, "tokyo_tyrant extension version", PHP_TOKYO_TYRANT_EXTVER); #ifdef HAVE_PHP_TOKYO_TYRANT_SESSION php_info_print_table_row(2, "tokyo_tyrant session handler", "available"); #else php_info_print_table_row(2, "tokyo_tyrant session handler", "unavailable"); #endif php_info_print_table_end(); DISPLAY_INI_ENTRIES(); } zend_module_entry tokyo_tyrant_module_entry = { STANDARD_MODULE_HEADER, PHP_TOKYO_TYRANT_EXTNAME, tokyo_tyrant_functions, /* Functions */ PHP_MINIT(tokyo_tyrant), /* MINIT */ PHP_MSHUTDOWN(tokyo_tyrant), /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ PHP_MINFO(tokyo_tyrant), /* MINFO */ PHP_TOKYO_TYRANT_EXTVER, /* version */ STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_TOKYO_TYRANT ZEND_GET_MODULE(tokyo_tyrant) #endif /* COMPILE_DL_TOKYO_TYRANT */ tokyo_tyrant-0.6.0/tokyo_tyrant_funcs.c0000644000076500000240000002047011530776271020262 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #include "php_tokyo_tyrant.h" #include "php_tokyo_tyrant_private.h" #include "php_tokyo_tyrant_funcs.h" #include "php_tokyo_tyrant_connection.h" #include "SAPI.h" #include "php_variables.h" /* {{{ void php_tt_object_init(php_tokyo_tyrant_object *intern TSRMLS_DC) */ void php_tt_object_init(php_tokyo_tyrant_object *intern TSRMLS_DC) { intern->conn = php_tt_conn_init(TSRMLS_C); } /* }}} */ /* {{{ zend_bool php_tt_is_connected(php_tokyo_tyrant_object *intern TSRMLS_DC) */ zend_bool php_tt_is_connected(php_tokyo_tyrant_object *intern TSRMLS_DC) { if (!intern->conn) { return 0; } return intern->conn->connected; } /* }}} */ char *php_tt_prefix(char *key, int key_len, int *new_len TSRMLS_DC) { char *buffer; int buffer_len; buffer_len = TOKYO_G(key_prefix_len) + key_len; buffer = emalloc(buffer_len + 1); memset(buffer, 0, buffer_len + 1); /* non binary-safe prefix. */ memcpy(buffer, TOKYO_G(key_prefix), TOKYO_G(key_prefix_len)); memcpy(buffer + TOKYO_G(key_prefix_len), key, key_len); buffer[buffer_len] = '\0'; *new_len = buffer_len; return buffer; } /* {{{ TCMAP *php_tt_zval_to_tcmap(zval *array, zend_bool value_as_key TSRMLS_DC) */ TCMAP *php_tt_zval_to_tcmap(zval *array, zend_bool value_as_key TSRMLS_DC) { HashPosition pos; int buckets, new_len; TCMAP *map; char *kbuf; buckets = zend_hash_num_elements(Z_ARRVAL_P(array)); map = tcmapnew2(buckets); if (!map) { return NULL; } for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); zend_hash_has_more_elements_ex(Z_ARRVAL_P(array), &pos) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)) { zval **ppzval, tmpcopy; if (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void**)&ppzval, &pos) == FAILURE) { continue; } tmpcopy = **ppzval; zval_copy_ctor(&tmpcopy); INIT_PZVAL(&tmpcopy); convert_to_string(&tmpcopy); if (value_as_key) { kbuf = php_tt_prefix(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy), &new_len TSRMLS_CC); tcmapput(map, kbuf, new_len, "", sizeof("")); efree(kbuf); } else { char *arr_key; uint arr_key_len; ulong num_key; int n; zend_bool allocated = 0; n = zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &arr_key, &arr_key_len, &num_key, 0, &pos); if (n == HASH_KEY_IS_LONG) { arr_key_len = spprintf(&arr_key, 78, "%ld", num_key); arr_key_len++; allocated = 1; } kbuf = php_tt_prefix(arr_key, arr_key_len - 1, &new_len TSRMLS_CC); tcmapput(map, kbuf, new_len, Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy)); efree(kbuf); if (allocated) { efree(arr_key); } } zval_dtor(&tmpcopy); } return map; } /* }}} */ /* {{{ void php_tt_tcmap_to_zval(TCMAP *map, zval *array TSRMLS_DC) */ void php_tt_tcmap_to_zval(TCMAP *map, zval *array TSRMLS_DC) { int name_len; const char *name; array_init(array); tcmapiterinit(map); while ((name = tcmapiternext(map, &name_len)) != NULL) { const char *buffer; int buffer_len; const char *kbuf = (char *)name; buffer = tcmapget(map, name, name_len, &buffer_len); if (buffer) { kbuf += TOKYO_G(key_prefix_len); name_len -= TOKYO_G(key_prefix_len); add_assoc_stringl_ex(array, (char *)kbuf, name_len + 1, (char *)buffer, buffer_len, 1); } } } /* }}} */ /* {{{ static zval* php_tt_ttstring_to_zval(const char* value, int value_len TSRMLS_DC) */ static zval* php_tt_ttstring_to_zval(const char* value, int value_len TSRMLS_DC) { zval *retval; int iskey = 1; char* pcur = (char*)value; char* key = pcur; char* prev = pcur; char* end = pcur + value_len; MAKE_STD_ZVAL(retval); array_init(retval); if (!value || value_len < 4) { return retval; } if (!(*value) || *end) { return retval; } for (; pcur <= end; pcur++) { if (*pcur) { continue; } if (iskey) { key = prev; if (!(*key)) { break; } iskey = 0; } else { add_assoc_string(retval, (char *)key, (char *)prev, 1); iskey = 1; } prev = pcur + 1; } return retval; } /* }}} */ /* {{{ void php_tt_tcmapstring_to_zval(TCMAP *map, zval *array TSRMLS_DC) */ void php_tt_tcmapstring_to_zval(TCMAP *map, zval *array TSRMLS_DC) { int name_len; const char *name; array_init(array); tcmapiterinit(map); while ((name = tcmapiternext(map, &name_len)) != NULL) { const char *buffer; int buffer_len; buffer = tcmapget(map, name, name_len, &buffer_len); if (buffer) { name += TOKYO_G(key_prefix_len); name_len -= TOKYO_G(key_prefix_len); add_assoc_zval_ex(array, (char *)name, name_len + 1, php_tt_ttstring_to_zval((const char*) buffer, buffer_len TSRMLS_CC)); } } } /* }}} */ /* {{{ zend_bool php_tt_query_object_init(php_tokyo_tyrant_query_object *query, zval *parent TSRMLS_DC) */ zend_bool php_tt_query_object_init(php_tokyo_tyrant_query_object *query, zval *parent TSRMLS_DC) { php_tokyo_tyrant_object *db = (php_tokyo_tyrant_object *)zend_object_store_get_object(parent TSRMLS_CC); query->qry = tcrdbqrynew(db->conn->rdb); if (!query->qry) { return 0; } query->conn = db->conn; query->parent = parent; query->res = NULL; #ifdef Z_REFCOUNT_P Z_SET_REFCOUNT_P(parent, Z_REFCOUNT_P(parent) + 1); #else parent->refcount++; #endif return 1; } /* }}} */ /* {{{ zend_bool php_tt_iterator_object_init(php_tokyo_tyrant_iterator_object *iterator, zval *parent TSRMLS_DC) */ zend_bool php_tt_iterator_object_init(php_tokyo_tyrant_iterator_object *iterator, zval *parent TSRMLS_DC) { php_tokyo_tyrant_object *db = (php_tokyo_tyrant_object *)zend_object_store_get_object(parent TSRMLS_CC); /* Check table first because it's also instanceof the parent */ if (instanceof_function(Z_OBJCE_P(parent), php_tokyo_tyrant_table_sc_entry TSRMLS_CC)) { iterator->iterator_type = PHP_TOKYO_TYRANT_TABLE_ITERATOR; } else if (instanceof_function(Z_OBJCE_P(parent), php_tokyo_tyrant_sc_entry TSRMLS_CC)) { iterator->iterator_type = PHP_TOKYO_TYRANT_ITERATOR; } else { return 0; } if (!tcrdbiterinit(db->conn->rdb)) { return 0; } iterator->conn = db->conn; iterator->parent = parent; #ifdef Z_REFCOUNT_P Z_SET_REFCOUNT_P(parent, Z_REFCOUNT_P(parent) + 1); #else parent->refcount++; #endif return 1; } /* }}} */ /* void php_tt_tclist_to_array(TCRDB *rdb, TCLIST *res, zval *container TSRMLS_DC) */ void php_tt_tclist_to_array(TCRDB *rdb, TCLIST *res, zval *container TSRMLS_DC) { const char *rbuf, *name; int i, rsiz = 0; TCMAP *cols; for (i = 0; i < tclistnum(res); i++) { rbuf = tclistval(res, i, &rsiz); cols = tcrdbtblget(rdb, rbuf, rsiz); if (cols) { int name_len; zval *row; tcmapiterinit(cols); MAKE_STD_ZVAL(row); array_init(row); while ((name = tcmapiternext(cols, &name_len)) != NULL) { char *data; int data_len; const char *kbuf = name; kbuf += TOKYO_G(key_prefix_len); name_len -= TOKYO_G(key_prefix_len); data = (char *)tcmapget(cols, name, name_len, &data_len); add_assoc_stringl_ex(row, (char *)kbuf, name_len + 1, data, data_len, 1); } tcmapdel(cols); add_assoc_zval_ex(container, (char *)rbuf, rsiz + 1, row); } } } tokyo_tyrant-0.6.0/php_tokyo_tyrant.h0000644000076500000240000000366211530776271017744 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_H_ # define _PHP_TOKYO_TYRANT_H_ #define PHP_TOKYO_TYRANT_EXTNAME "tokyo_tyrant" #define PHP_TOKYO_TYRANT_EXTVER "0.6.0" #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef ZTS # include "TSRM.h" #endif #include "php.h" extern zend_module_entry tokyo_tyrant_module_entry; #define phpext_tokyo_tyrant_ptr &tokyo_tyrant_module_entry #ifdef HAVE_PHP_TOKYO_TYRANT_SESSION #include "ext/session/php_session.h" extern ps_module ps_mod_tokyo_tyrant; #define ps_tokyo_tyrant_ptr &ps_mod_tokyo_tyrant PS_FUNCS(tokyo_tyrant); #endif #endif /* _PHP_TOKYO_TYRANT_H_ */ tokyo_tyrant-0.6.0/php_tokyo_tyrant_connection.h0000644000076500000240000000403211530776271022153 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_CONNECTION_H_ # define _PHP_TOKYO_TYRANT_CONNECTION_H_ #include "php_tokyo_tyrant_private.h" php_tt_conn *php_tt_conn_init(TSRMLS_D); void php_tt_conn_deinit(php_tt_conn *conn TSRMLS_DC); char *php_tt_hash_key(char *host, int port, double timeout, int *key_len TSRMLS_DC); void php_tt_disconnect_ex(php_tt_conn *conn, zend_bool dealloc_rdb TSRMLS_DC); zend_bool php_tt_connect_ex(php_tt_conn *conn, char *host, int port, double timeout, zend_bool persistent TSRMLS_DC); zend_bool php_tt_connect(php_tokyo_tyrant_object *intern, char *host, int port, zval *params TSRMLS_DC); zend_bool php_tt_connect2(php_tokyo_tyrant_object *intern, php_url *url TSRMLS_DC); #endiftokyo_tyrant-0.6.0/php_tokyo_tyrant_failover.h0000644000076500000240000000342711530776271021632 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_FAILOVER_H_ # define _PHP_TOKYO_TYRANT_FAILOVER_H_ #define PHP_TT_INCR 1 #define PHP_TT_DECR 2 #define PHP_TT_GET 3 long php_tt_server_fail(int op, char *host, int port TSRMLS_DC); void php_tt_server_fail_incr(char *host, int port TSRMLS_DC); void php_tt_server_fail_decr(char *host, int port TSRMLS_DC); zend_bool php_tt_server_ok(char *host, int port TSRMLS_DC); void php_tt_health_check(TSRMLS_D); #endiftokyo_tyrant-0.6.0/php_tokyo_tyrant_funcs.h0000644000076500000240000000427311530776271021141 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_FUNCS_H_ # define _PHP_TOKYO_TYRANT_FUNCS_H_ #include "php_tokyo_tyrant.h" #include "php_tokyo_tyrant_private.h" void php_tt_object_init(php_tokyo_tyrant_object *intern TSRMLS_DC); zend_bool php_tt_is_connected(php_tokyo_tyrant_object *intern TSRMLS_DC); TCMAP *php_tt_zval_to_tcmap(zval *array, zend_bool value_as_key TSRMLS_DC); void php_tt_tcmap_to_zval(TCMAP *map, zval *array TSRMLS_DC); void php_tt_tcmapstring_to_zval(TCMAP *map, zval *array TSRMLS_DC); zend_bool php_tt_query_object_init(php_tokyo_tyrant_query_object *query, zval *parent TSRMLS_DC); zend_bool php_tt_iterator_object_init(php_tokyo_tyrant_iterator_object *iterator, zval *parent TSRMLS_DC); void php_tt_tclist_to_array(TCRDB *rdb, TCLIST *res, zval *container TSRMLS_DC); char *php_tt_prefix(char *key, int key_len, int *new_len TSRMLS_DC); #endif tokyo_tyrant-0.6.0/php_tokyo_tyrant_private.h0000644000076500000240000001327111530776271021473 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_PRIVATE_H_ # define _PHP_TOKYO_TYRANT_PRIVATE_H_ #include #include #include #include #include "php_ini.h" #include "ext/standard/url.h" #include "SAPI.h" #include "php_variables.h" typedef struct _php_tt_conn { TCRDB *rdb; /* database instance */ zend_bool connected; /* Are we connected to a db? */ zend_bool persistent; /* Is the instant persistent (?) */ } php_tt_conn; /* {{{ typedef struct _php_tokyo_tyrant_object */ typedef struct _php_tokyo_tyrant_object { zend_object zo; php_tt_conn *conn; /* database connection */ } php_tokyo_tyrant_object; /* }}} */ /* {{{ typedef struct _php_tokyo_tyrant_query_object */ typedef struct _php_tokyo_tyrant_query_object { zend_object zo; php_tt_conn *conn; RDBQRY *qry; zval *parent; int pos; TCLIST *res; zend_bool executed; } php_tokyo_tyrant_query_object; /* }}} */ /* {{{ typedef struct _php_tokyo_tyrant_iterator_object */ typedef struct _php_tokyo_tyrant_iterator_object { zend_object zo; php_tt_conn *conn; /* database connection */ zval *parent; char *current; int current_len; /* iterating kv or table? */ int iterator_type; } php_tokyo_tyrant_iterator_object; /* }}} */ ZEND_BEGIN_MODULE_GLOBALS(tokyo_tyrant) HashTable *connections; HashTable *failures; double default_timeout; char *salt; char *key_prefix; int key_prefix_len; zend_bool allow_failover; long health_check_divisor; long fail_threshold; zend_bool php_expiration; ZEND_END_MODULE_GLOBALS(tokyo_tyrant) ZEND_EXTERN_MODULE_GLOBALS(tokyo_tyrant); #ifdef ZTS # define TOKYO_G(v) TSRMG(tokyo_tyrant_globals_id, zend_tokyo_tyrant_globals *, v) #else # define TOKYO_G(v) (tokyo_tyrant_globals.v) #endif #define PHP_TOKYO_OBJECT (php_tokyo_tyrant_object *)zend_object_store_get_object(getThis() TSRMLS_CC); #define PHP_TOKYO_QUERY_OBJECT (php_tokyo_tyrant_query_object *)zend_object_store_get_object(getThis() TSRMLS_CC); #define PHP_TOKYO_ITERATOR_OBJECT (php_tokyo_tyrant_iterator_object *)zend_object_store_get_object(getThis() TSRMLS_CC); #define PHP_TOKYO_CHAIN_METHOD RETURN_ZVAL(getThis(), 1, 0); #define PHP_TOKYO_TYRANT_DEFAULT_PORT 1978 #define PHP_TOKYO_TYRANT_OP_PUT 1 #define PHP_TOKYO_TYRANT_OP_PUTKEEP 2 #define PHP_TOKYO_TYRANT_OP_PUTCAT 3 #define PHP_TOKYO_TYRANT_OP_OUT 4 #define PHP_TOKYO_TYRANT_OP_TBLPUT 5 #define PHP_TOKYO_TYRANT_OP_TBLPUTKEEP 6 #define PHP_TOKYO_TYRANT_OP_TBLPUTCAT 7 #define PHP_TOKYO_TYRANT_OP_PUTNR 8 #define PHP_TOKYO_TYRANT_OP_TBLOUT 9 #define PHP_TOKYO_TYRANT_RECTYPE_INT 1 #define PHP_TOKYO_TYRANT_RECTYPE_DOUBLE 2 #define PHP_TOKYO_TYRANT_ITERATOR 1 #define PHP_TOKYO_TYRANT_TABLE_ITERATOR 2 /* {{{ #define PHP_TOKYO_TYRANT_EXCEPTION(intern, format) */ #define PHP_TOKYO_TYRANT_EXCEPTION(intern, format) \ { \ int error_code = tcrdbecode(intern->conn->rdb); \ if (error_code == TTENOREC) { \ RETURN_NULL(); \ } \ zend_throw_exception_ex(php_tokyo_tyrant_exception_sc_entry, error_code TSRMLS_CC, format, tcrdberrmsg(error_code)); \ return; \ } /* }}} */ /* {{{ #define PHP_TOKYO_TYRANT_EXCEPTION_FREE(intern, format) */ #define PHP_TOKYO_TYRANT_EXCEPTION_FREE(intern, format) \ { \ int error_code = tcrdbecode(intern->conn->rdb); \ zend_throw_exception_ex(php_tokyo_tyrant_exception_sc_entry, error_code TSRMLS_CC, format, tcrdberrmsg(error_code)); \ efree(format); \ return; \ } /* }}} */ /* {{{ #define PHP_PHP_TOKYO_TYRANT_EXCEPTION_MSG(message) */ #define PHP_TOKYO_TYRANT_EXCEPTION_MSG(message) \ { \ zend_throw_exception(php_tokyo_tyrant_exception_sc_entry, message, TTEMISC TSRMLS_CC); \ return; \ } /* }}} */ /* {{{ #define PHP_TOKYO_CONNECTED_OBJECT(intern) */ #define PHP_TOKYO_CONNECTED_OBJECT(intern) \ { \ intern = (php_tokyo_tyrant_object *)zend_object_store_get_object(getThis() TSRMLS_CC); \ if (!php_tt_is_connected(intern TSRMLS_CC)) \ PHP_TOKYO_TYRANT_EXCEPTION_MSG("Not connected to a database"); \ } /* }}} */ #define DEBUG_M(args...) \ { \ char *buf; \ spprintf(&buf, 1024, args); \ php_log_err(buf); \ efree(buf); \ } \ extern zend_class_entry *php_tokyo_tyrant_sc_entry; extern zend_class_entry *php_tokyo_tyrant_table_sc_entry; extern zend_class_entry *php_tokyo_tyrant_query_sc_entry; extern zend_class_entry *php_tokyo_tyrant_iterator_sc_entry; extern zend_class_entry *php_tokyo_tyrant_exception_sc_entry; #endif /* _PHP_TOKYO_TYRANT_PRIVATE_H_ */tokyo_tyrant-0.6.0/php_tokyo_tyrant_server_pool.h0000644000076500000240000000415011530776271022354 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_SERVER_POOL_H_ # define _PHP_TOKYO_TYRANT_SERVER_POOL_H_ typedef struct _php_tt_server { char *host; int port; } php_tt_server; typedef struct _php_tt_server_pool { php_tt_server **servers; int num_servers; } php_tt_server_pool; php_tt_server_pool *php_tt_pool_init(TSRMLS_D); void php_tt_pool_append(php_tt_server_pool *pool, php_tt_server *server TSRMLS_DC); void php_tt_pool_append2(php_tt_server_pool *pool, char *host, int port TSRMLS_DC); void php_tt_pool_deinit(php_tt_server_pool *pool TSRMLS_DC); php_tt_server_pool *php_tt_pool_init2(const char *save_path TSRMLS_DC); int php_tt_pool_map(php_tt_server_pool *pool, char *key TSRMLS_DC); php_tt_server *php_tt_pool_get_server(php_tt_server_pool *pool, int idx TSRMLS_DC); #endiftokyo_tyrant-0.6.0/php_tokyo_tyrant_session.h0000644000076500000240000000444611530776271021510 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_SESSION_H_ # define _PHP_TOKYO_TYRANT_SESSION_H_ #include "php_tokyo_tyrant.h" #include "php_tokyo_tyrant_private.h" #include "php_tokyo_tyrant_connection.h" #include "php_tokyo_tyrant_server_pool.h" #include "php_tokyo_tyrant_failover.h" #include "php_tokyo_tyrant_funcs.h" PS_CREATE_SID_FUNC(tokyo_tyrant); typedef struct _php_tt_session { php_tt_server_pool *pool; /* Pool of session servers */ php_tt_conn *conn; /* Connection to the session server */ char *pk; /* Primary key of the session data */ int pk_len; /* pk length */ int idx; /* node where the data is stored at */ char *sess_rand; /* The session id part */ int sess_rand_len; /* session id length */ char *checksum; /* Session validation checksum */ int checksum_len; /* Checksum length */ zend_bool remap; /* If 1 create_sid will remap the session to a new server */ } php_tt_session; #endiftokyo_tyrant-0.6.0/php_tokyo_tyrant_session_funcs.h0000644000076500000240000000466211530776271022706 0ustar mkoppanenstaff/* +----------------------------------------------------------------------+ | PHP Version 5 / Tokyo tyrant | +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 Mikko Koppanen | +----------------------------------------------------------------------+ | This source file is dual-licensed. | | It is available under the terms of New BSD License that is bundled | | with this package in the file LICENSE and available under the terms | | of PHP license version 3.01. PHP license is bundled with this | | package in the file LICENSE and can be obtained through the | | world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Mikko Kopppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_TOKYO_TYRANT_SESSION_FUNCS_H_ # define _PHP_TOKYO_TYRANT_SESSION_FUNCS_H_ php_tt_session *php_tt_session_init(TSRMLS_D); void php_tt_session_deinit(php_tt_session *session TSRMLS_DC); char *php_tt_create_sid(char *sess_rand, int idx, char *pk, char *salt TSRMLS_DC); char *php_tt_create_pk(php_tt_conn *conn, int *pk_len TSRMLS_DC); zend_bool php_tt_tokenize(char *session_id, char **sess_rand, char **checksum, int *idx, char **pk_str TSRMLS_DC); zend_bool php_tt_validate(char *sess_rand, char *checksum, int idx, char *pk, char *salt TSRMLS_DC); char *php_tt_get_sess_data(php_tt_conn *conn, char *sess_rand, const char *pk, int pk_len, int *data_len, zend_bool *mismatch TSRMLS_DC); zend_bool php_tt_save_sess_data(php_tt_conn *conn, char *rand_part, char *pk, int pk_len, const char *data, int data_len TSRMLS_DC); zend_bool php_tt_sess_touch(php_tt_conn *conn, char *current_rand, char *sess_rand, char *pk, int pk_len TSRMLS_DC); zend_bool php_tt_sess_destroy(php_tt_conn *conn, char *pk, int pk_len TSRMLS_DC); zend_bool php_tt_gc(php_tt_server_pool *pool TSRMLS_DC); #endif tokyo_tyrant-0.6.0/CREDITS0000644000076500000240000000003311530776271015163 0ustar mkoppanenstafftokyo_tyrant Mikko Koppanentokyo_tyrant-0.6.0/LICENSE0000644000076500000240000001127711530776271015164 0ustar mkoppanenstafftokyo_tyrant can be used under PHP License 3.01 or 3-clause BSD License. -------------------------------------------------------------------- The PHP License, version 3.01 Copyright (c) 1999 - 2009 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name "PHP" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact group@php.net. 4. Products derived from this software may not be called "PHP", nor may "PHP" appear in their name, without prior written permission from group@php.net. You may indicate that your software works in conjunction with PHP by saying "Foo for PHP" instead of calling it "PHP Foo" or "phpfoo" 5. The PHP Group may publish revised and/or new versions of the license from time to time. Each version will be given a distinguishing version number. Once covered code has been published under a particular version of the license, you may always continue to use it under the terms of that version. You may also choose to use such covered code under the terms of any subsequent version of the license published by the PHP Group. No one other than the PHP Group has the right to modify the terms applicable to covered code created under this License. 6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes PHP software, freely available from ". THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------- This software consists of voluntary contributions made by many individuals on behalf of the PHP Group. The PHP Group can be contacted via Email at group@php.net. For more information on the PHP Group and the PHP project, please see . PHP includes the Zend Engine, freely available at . Copyright (c) 2010, Mikko Koppanen All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIKKO KOPPANEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. tokyo_tyrant-0.6.0/ChangeLog0000644000076500000240000000131311530776271015717 0ustar mkoppanenstaff0.6.0 - Fix PECL Bug #18344 0.5.0 - Fix crash when session_regenerate_id(true) is called - Fix SIGFPE when no servers are added to the pool - Make configure pkg-config checks more robust 0.4.0 - Fix restore method to use correct timestamp precision - Dual license under PHP and BSD licenses 0.3.0 - Added multiget for tables. Thanks to Devin - Fixed binary safety on table methods 0.2.0 - Warnings instead of fatal errors in session handler - Added TokyoTyrantIterator - Added getIterator method to TokyoTyrant and TokyoTyrantTable classes 0.1.2 - Make sure that keys and values are binary-safe 0.1.1 - Disabled timeout by default - Added tune method to change the timeout 0.1.0 - Initial release