├── CREDITS ├── config.w32 ├── README ├── beanstalk_standard_hash.c ├── config.m4 ├── php_beanstalk.h ├── beanstalk_pool.h ├── beanstalk_consistent_hash.c ├── beanstalk_pool.c └── beanstalk.c /CREDITS: -------------------------------------------------------------------------------- 1 | beanstalk -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | // If your extension references something external, use ARG_WITH 5 | // ARG_WITH("beanstalk", "for beanstalk support", "no"); 6 | 7 | // Otherwise, use ARG_ENABLE 8 | // ARG_ENABLE("beanstalk", "enable beanstalk support", "no"); 9 | 10 | if (PHP_BEANSTALK != "no") { 11 | EXTENSION("beanstalk", "beanstalk.c"); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 1.Install libbeanstalkclient 2 | $mkdir php-beanstalk 3 | $cd php-beanstalk/ 4 | $wget https://github.com/bergundy/libbeanstalkclient/tarball/master --no-check-certificate 5 | $mv master bergundy-libbeanstalkclient-b6ec294.tar.gz 6 | $tar -xzvf bergundy-libbeanstalkclient-b6ec294.tar.gz 7 | $mv bergundy-libbeanstalkclient-b6ec294 libbeanstalkclient 8 | $cd libbeanstalkclient/ 9 | $mkdir m4 10 | $sudo ./autogen.sh 11 | $sudo vim /etc/ld.so.conf 12 | /usr/lib 13 | $sudo ldconfig 14 | 15 | 2.Install php-beanstalk 16 | $wget https://github.com/nil-zhang/php-beanstalk/tarball/master --no-check-certificate 17 | $mv master php-beanstalk.tar.gz 18 | $tar -xzvf php-beanstalk.tar.gz 19 | $cd php-beanstalk 20 | $phpize 21 | $./configure 22 | $make 23 | $sudo make install 24 | $sudo vim /etc/php.d/beanstalk.ini 25 | extension = "beanstalk.so" 26 | $php -m 27 | 28 | 3.Using example 29 | -----example.php---------- 30 | addserver("ip1", 11300); 35 | $bsc->addserver("ip2", 11300); 36 | 37 | $tubes = $bsc->list_tubes(); 38 | print_r($tubes); 39 | 40 | for($i = 0; $i < 10; $i++) 41 | { 42 | $key = "key".$i; 43 | $value = "value".$i; 44 | 45 | $bsc->use($key); 46 | $bsc->put($key, $value); 47 | echo "$key\t$value\n"; 48 | 49 | $bsc->watch($key); 50 | $job = $bsc->reserve($key); 51 | print_r($job); 52 | 53 | if($bsc->bury($job['id'], $key)) 54 | echo "bury ok\n"; 55 | else 56 | echo "bury failed\n"; 57 | 58 | $bsc->kick(100, $key); 59 | if($bsc->delete($job['id'], $key)) 60 | echo "delete ok\n"; 61 | else 62 | echo "delete failed \n"; 63 | 64 | $bsc->ignore($key); 65 | echo "\n"; 66 | } 67 | 68 | echo "done\n"; 69 | 70 | ?> 71 | 72 | -------------------------------------------------------------------------------- /beanstalk_standard_hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.0 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_0.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Antony Dovgal | 16 | | Mikael Johansson | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | /* $Id: beanstalk_standard_hash.c 310129 2011-04-11 04:44:27Z hradtke $ */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include "php.h" 27 | #include "beanstalk_pool.h" 28 | 29 | //ZEND_EXTERN_MODULE_GLOBALS(beanstalk) 30 | 31 | typedef struct bsc_standard_state { 32 | int num_servers; 33 | bsc **buckets; 34 | int num_buckets; 35 | bsc_hash_function_t *hash; 36 | } bsc_standard_state_t; 37 | 38 | void *bsc_standard_create_state(bsc_hash_function_t *hash) /* {{{ */ 39 | { 40 | bsc_standard_state_t *state = emalloc(sizeof(bsc_standard_state_t)); 41 | memset(state, 0, sizeof(bsc_standard_state_t)); 42 | state->hash = hash; 43 | return state; 44 | } 45 | /* }}} */ 46 | 47 | void bsc_standard_free_state(void *s) /* {{{ */ 48 | { 49 | bsc_standard_state_t *state = s; 50 | if (state != NULL) { 51 | if (state->buckets != NULL) { 52 | efree(state->buckets); 53 | } 54 | efree(state); 55 | } 56 | } 57 | /* }}} */ 58 | 59 | bsc *bsc_standard_find_server(void *s, const char *key, unsigned int key_len TSRMLS_DC) /* {{{ */ 60 | { 61 | bsc_standard_state_t *state = s; 62 | 63 | if (state->num_servers > 1) { 64 | /* "new-style" hash */ 65 | unsigned int hash = (bsc_hash(state->hash, key, key_len) >> 16) & 0x7fff; 66 | return state->buckets[(hash ? hash : 1) % state->num_buckets]; 67 | } 68 | 69 | return state->buckets[0]; 70 | } 71 | /* }}} */ 72 | 73 | void bsc_standard_add_server(void *s, bsc *svr, unsigned int weight) /* {{{ */ 74 | { 75 | bsc_standard_state_t *state = s; 76 | int i; 77 | 78 | /* add weight number of buckets for this server */ 79 | state->buckets = erealloc(state->buckets, sizeof(*state->buckets) * (state->num_buckets + weight)); 80 | 81 | for (i=0; ibuckets[state->num_buckets + i] = svr; 83 | } 84 | 85 | state->num_buckets += weight; 86 | state->num_servers++; 87 | } 88 | /* }}} */ 89 | 90 | bsc_hash_strategy_t bsc_standard_hash = { 91 | bsc_standard_create_state, 92 | bsc_standard_free_state, 93 | bsc_standard_find_server, 94 | bsc_standard_add_server 95 | }; 96 | 97 | /* 98 | * Local variables: 99 | * tab-width: 4 100 | * c-basic-offset: 4 101 | * End: 102 | * vim600: noet sw=4 ts=4 fdm=marker 103 | * vim<600: noet sw=4 ts=4 104 | */ 105 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension beanstalk 3 | 4 | dnl Comments in this file start with the string 'dnl'. 5 | dnl Remove where necessary. This file will not work 6 | dnl without editing. 7 | 8 | dnl If your extension references something external, use with: 9 | 10 | dnl PHP_ARG_WITH(beanstalk, for beanstalk support, 11 | dnl Make sure that the comment is aligned: 12 | dnl [ --with-beanstalk Include beanstalk support]) 13 | 14 | dnl Otherwise use enable: 15 | 16 | PHP_ARG_ENABLE(beanstalk, whether to enable beanstalk support, 17 | [ --enable-beanstalk Enable beanstalk support]) 18 | 19 | PHP_ARG_WITH(libbeanstalkclient-dir, for libbeanstalkclient, 20 | [ --with-libbeanstalkclient-dir[=DIR] Set the path to libbeanstalkclient install prefix.], yes) 21 | 22 | if test -z "$PHP_DEBUG"; then 23 | AC_ARG_ENABLE(debug, 24 | [ --enable-debug compile with debugging symbols],[ 25 | PHP_DEBUG=$enableval 26 | ],[ PHP_DEBUG=no 27 | ]) 28 | fi 29 | 30 | if test "$PHP_BEANSTALK" != "no"; then 31 | 32 | if test "$PHP_LIBBEANSTALKCLIENT_DIR" != "no" && test "$PHP_LIBBEANSTALKCLIENT_DIR" != "yes"; then 33 | if test -r "$PHP_LIBBEANSTALKCLIENT_DIR/include/beanstalkclient.h"; then 34 | PHP_LIBBEANSTALKCLIENT_DIR="$PHP_LIBBEANSTALKCLIENT_DIR" 35 | else 36 | AC_MSG_ERROR([Can't find libbeanstalkclient headers under "$PHP_LIBBEANSTALKCLIENT_DIR"]) 37 | fi 38 | else 39 | PHP_LIBBEANSTALKCLIENT_DIR="no" 40 | for i in /usr /usr/local; do 41 | if test -r "$i/include/beanstalkclient.h"; then 42 | PHP_LIBBEANSTALKCLIENT_DIR=$i 43 | break 44 | fi 45 | done 46 | fi 47 | 48 | AC_MSG_CHECKING([for libbeanstalkclient location]) 49 | if test "$PHP_LIBBEANSTALKCLIENT_DIR" = "no"; then 50 | AC_MSG_ERROR([beanstalk support requires libbeanstalkclient. Use --with-libbeanstalkclient-dir= to specify the prefix where libbeanstalkclient headers and library are located]) 51 | else 52 | AC_MSG_RESULT([$PHP_LIBBEANSTALKCLIENT_DIR]) 53 | PHP_LIBBEANSTALKCLIENT_INCDIR="$PHP_LIBBEANSTALKCLIENT_DIR/include" 54 | PHP_ADD_INCLUDE($PHP_LIBBEANSTALKCLIENT_INCDIR) 55 | PHP_ADD_LIBRARY_WITH_PATH(beanstalkclient, $PHP_LIBBEANSTALKCLIENT_DIR/$PHP_LIBDIR, BEANSTALK_SHARED_LIBADD) 56 | 57 | PHP_SUBST(BEANSTALK_SHARED_LIBADD) 58 | 59 | PHP_BEANSTALK_FILES="beanstalk.c beanstalk_pool.c beanstalk_consistent_hash.c beanstalk_standard_hash.c" 60 | 61 | PHP_NEW_EXTENSION(beanstalk, $PHP_BEANSTALK_FILES, $ext_shared) 62 | 63 | ifdef([PHP_ADD_EXTENSION_DEP], 64 | [ 65 | PHP_ADD_EXTENSION_DEP(beanstalk, spl, true) 66 | ]) 67 | 68 | fi 69 | fi 70 | 71 | dnl Write more examples of tests here... 72 | 73 | dnl # --with-beanstalk -> check with-path 74 | dnl SEARCH_PATH="/usr/local /usr" # you might want to change this 75 | dnl SEARCH_FOR="/include/beanstalk.h" # you most likely want to change this 76 | dnl if test -r $PHP_BEANSTALK/$SEARCH_FOR; then # path given as parameter 77 | dnl BEANSTALK_DIR=$PHP_BEANSTALK 78 | dnl else # search default path list 79 | dnl AC_MSG_CHECKING([for beanstalk files in default path]) 80 | dnl for i in $SEARCH_PATH ; do 81 | dnl if test -r $i/$SEARCH_FOR; then 82 | dnl BEANSTALK_DIR=$i 83 | dnl AC_MSG_RESULT(found in $i) 84 | dnl fi 85 | dnl done 86 | dnl fi 87 | dnl 88 | dnl if test -z "$BEANSTALK_DIR"; then 89 | dnl AC_MSG_RESULT([not found]) 90 | dnl AC_MSG_ERROR([Please reinstall the beanstalk distribution]) 91 | dnl fi 92 | 93 | dnl # --with-beanstalk -> add include path 94 | dnl PHP_ADD_INCLUDE($BEANSTALK_DIR/include) 95 | 96 | dnl # --with-beanstalk -> check for lib and symbol presence 97 | dnl LIBNAME=beanstalk # you may want to change this 98 | dnl LIBSYMBOL=beanstalk # you most likely want to change this 99 | 100 | dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, 101 | dnl [ 102 | dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $BEANSTALK_DIR/lib, BEANSTALK_SHARED_LIBADD) 103 | dnl AC_DEFINE(HAVE_BEANSTALKLIB,1,[ ]) 104 | dnl ],[ 105 | dnl AC_MSG_ERROR([wrong beanstalk lib version or lib not found]) 106 | dnl ],[ 107 | dnl -L$BEANSTALK_DIR/lib -lm -ldl 108 | dnl ]) 109 | dnl 110 | dnl PHP_SUBST(BEANSTALK_SHARED_LIBADD) 111 | 112 | -------------------------------------------------------------------------------- /php_beanstalk.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id: header,v 1.16.2.1.2.1 2007/01/01 19:32:09 iliaa Exp $ */ 20 | 21 | #ifndef PHP_BEANSTALK_H 22 | #define PHP_BEANSTALK_H 23 | 24 | extern zend_module_entry beanstalk_module_entry; 25 | #define phpext_beanstalk_ptr &beanstalk_module_entry 26 | 27 | #ifdef PHP_WIN32 28 | #define PHP_BEANSTALK_API __declspec(dllexport) 29 | #else 30 | #define PHP_BEANSTALK_API 31 | #endif 32 | 33 | #ifdef ZTS 34 | #include "TSRM.h" 35 | #endif 36 | 37 | #include "beanstalk_pool.h" 38 | 39 | PHP_MINIT_FUNCTION(beanstalk); 40 | PHP_MSHUTDOWN_FUNCTION(beanstalk); 41 | //PHP_RINIT_FUNCTION(beanstalk); 42 | //PHP_RSHUTDOWN_FUNCTION(beanstalk); 43 | PHP_MINFO_FUNCTION(beanstalk); 44 | 45 | PHP_NAMED_FUNCTION(zif_beanstalk_pool_addserver); 46 | PHP_NAMED_FUNCTION(zif_beanstalk_pool_findserver); 47 | 48 | PHP_FUNCTION(beanstalk_add_server); 49 | PHP_FUNCTION(beanstalk_use); 50 | PHP_FUNCTION(beanstalk_put); 51 | PHP_FUNCTION(beanstalk_reserve); 52 | PHP_FUNCTION(beanstalk_delete); 53 | PHP_FUNCTION(beanstalk_release); 54 | PHP_FUNCTION(beanstalk_bury); 55 | PHP_FUNCTION(beanstalk_touch); 56 | PHP_FUNCTION(beanstalk_watch); 57 | PHP_FUNCTION(beanstalk_ignore); 58 | PHP_FUNCTION(beanstalk_peek); 59 | PHP_FUNCTION(beanstalk_kick); 60 | PHP_FUNCTION(beanstalk_list_tubes); 61 | PHP_FUNCTION(beanstalk_quit); 62 | 63 | #define PHP_BEANSTALK_VERSION "0.0.1" 64 | 65 | #define BSC_DEFAULT_TIMEOUT 0 /* seconds */ 66 | #define BSC_DEFAULT_RETRY 15 /* retry failed server after x seconds */ 67 | 68 | #define BSC_DEFAULT_PRORITY 1024 69 | #define BSC_DEFAULT_DELAY 0 70 | #define BSC_DEFAULT_TTR 60 71 | #define DEFAULT_PORT 60 72 | 73 | #if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3) 74 | # define IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp) TSRMLS_CC) 75 | #else 76 | # define IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp)) 77 | #endif 78 | 79 | /* 80 | Declare any global variables you may need between the BEGIN 81 | and END macros here: 82 | ZEND_BEGIN_MODULE_GLOBALS(beanstalk) 83 | long default_port; 84 | long hash_strategy; 85 | long hash_function; 86 | ZEND_END_MODULE_GLOBALS(beanstalk) 87 | */ 88 | 89 | /* In every utility function you add that needs to use variables 90 | in php_beanstalk_globals, call TSRMLS_FETCH(); after declaring other 91 | variables used by that function, or better yet, pass in TSRMLS_CC 92 | after the last function argument and declare your utility function 93 | with TSRMLS_DC after the last declared argument. Always refer to 94 | the globals in your function as BEANSTALK_G(variable). You are 95 | encouraged to rename these macros something shorter, see 96 | examples in any other php module directory. 97 | */ 98 | 99 | /* 100 | */ 101 | #ifdef ZTS 102 | #define BEANSTALK_G(v) TSRMG(beanstalk_globals_id, zend_beanstalk_globals *, v) 103 | #else 104 | #define BEANSTALK_G(v) (beanstalk_globals.v) 105 | #endif 106 | 107 | #endif /* PHP_BEANSTALK_H */ 108 | 109 | 110 | /* 111 | * Local variables: 112 | * tab-width: 4 113 | * c-basic-offset: 4 114 | * End: 115 | * vim600: noet sw=4 ts=4 fdm=marker 116 | * vim<600: noet sw=4 ts=4 117 | */ 118 | 119 | 120 | -------------------------------------------------------------------------------- /beanstalk_pool.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.0 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_0.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Antony Dovgal | 16 | | Mikael Johansson | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | /* $Id: beanstalk_pool.h 310129 2011-04-11 04:44:27Z hradtke $ */ 21 | 22 | #ifndef BEANSTALK_POOL_H 23 | #define BEANSTALK_POOL_H 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include "config.h" 27 | #endif 28 | 29 | #ifdef HAVE_SYS_TYPES_H 30 | #include 31 | #endif 32 | 33 | #include 34 | #include 35 | 36 | #include "php.h" 37 | #include "ext/standard/php_smart_str_public.h" 38 | #include "beanstalkclient.h" 39 | 40 | #ifndef ZSTR 41 | #define ZSTR 42 | #define ZSTR_VAL(v) v 43 | #define zstr char * 44 | #else 45 | #define ZSTR_VAL(v) (v).s 46 | #endif 47 | 48 | /* 49 | * Mac OS X has no MSG_NOSIGNAL but >= 10.2 comes with SO_NOSIGPIPE which is a setsockopt() option 50 | * and not a send() parameter as MSG_NOSIGNAL. OpenBSD has none of the options so we need to ignore 51 | * SIGPIPE events 52 | */ 53 | #ifndef MSG_NOSIGNAL 54 | #define MSG_NOSIGNAL 0 55 | #endif /*MSG_NOSIGNAL*/ 56 | 57 | #define BSC_MAX_KEY_LEN 250 58 | #define BSC_PORT_LEN 10 59 | 60 | #define BSC_OK 0 61 | 62 | #define BSC_STANDARD_HASH 1 63 | #define BSC_CONSISTENT_HASH 2 64 | #define BSC_HASH_CRC32 1 /* CRC32 hash function */ 65 | #define BSC_HASH_FNV1A 2 /* FNV-1a hash function */ 66 | 67 | #define BSC_CONSISTENT_POINTS 160 /* points per server */ 68 | #define BSC_CONSISTENT_BUCKETS 1024 /* number of precomputed buckets, should be power of 2 */ 69 | 70 | typedef struct bsc_pool bsc_pool_t; 71 | 72 | /* hashing strategy */ 73 | typedef unsigned int (*bsc_hash_function_init)(); 74 | typedef unsigned int (*bsc_hash_function_combine)(unsigned int seed, const void *key, unsigned int key_len); 75 | typedef unsigned int (*bsc_hash_function_finish)(unsigned int seed); 76 | 77 | typedef struct bsc_hash_function { 78 | bsc_hash_function_init init; 79 | bsc_hash_function_combine combine; 80 | bsc_hash_function_finish finish; 81 | } bsc_hash_function_t; 82 | 83 | extern bsc_hash_function_t bsc_hash_crc32; 84 | extern bsc_hash_function_t bsc_hash_fnv1a; 85 | 86 | #define bsc_hash(hash, key, key_len) ((hash)->finish((hash)->combine((hash)->init(), (key), (key_len)))) 87 | 88 | typedef void * (*bsc_hash_create_state)(bsc_hash_function_t *); 89 | typedef void (*bsc_hash_free_state)(void *state); 90 | typedef bsc * (*bsc_hash_find_server)(void *state, const char *key, unsigned int key_len TSRMLS_DC); 91 | typedef void (*bsc_hash_add_server)(void *state, bsc *mmc, unsigned int weight); 92 | 93 | typedef struct bsc_hash_strategy { 94 | bsc_hash_create_state create_state; 95 | bsc_hash_free_state free_state; 96 | bsc_hash_find_server find_server; 97 | bsc_hash_add_server add_server; 98 | } bsc_hash_strategy_t; 99 | 100 | extern bsc_hash_strategy_t bsc_standard_hash; 101 | extern bsc_hash_strategy_t bsc_consistent_hash; 102 | 103 | /* 32 bit magic FNV-1a prime and init */ 104 | #define FNV_32_PRIME 0x01000193 105 | #define FNV_32_INIT 0x811c9dc5 106 | 107 | /* failure callback prototype */ 108 | typedef void (*bsc_failure_callback)(bsc_pool_t *pool, bsc *svr, void *param TSRMLS_DC); 109 | 110 | /* server pool */ 111 | struct bsc_pool { 112 | bsc **servers; 113 | int num_servers; 114 | bsc_hash_strategy_t *hash; /* hash strategy */ 115 | void *hash_state; /* strategy specific state */ 116 | struct timeval timeout; /* smallest timeout for any of the servers */ 117 | bsc_failure_callback failure_callback; /* receives notification when a server fails */ 118 | void *failure_callback_param; 119 | }; 120 | 121 | /* pool functions */ 122 | bsc_pool_t *bsc_pool_new(TSRMLS_D); 123 | void bsc_pool_free(bsc_pool_t * TSRMLS_DC); 124 | void bsc_pool_add(bsc_pool_t *, bsc *, unsigned int); 125 | bsc *bsc_server_new(const char *host, int host_len, unsigned short tcp_port, double timeout, int retry_interval TSRMLS_DC); 126 | void bsc_server_free(bsc * TSRMLS_DC); 127 | void bsc_pool_close(bsc_pool_t * TSRMLS_DC); 128 | bsc *bsc_pool_find(bsc_pool_t *, const char *, unsigned int TSRMLS_DC); 129 | 130 | /* globals */ 131 | /* 132 | ZEND_BEGIN_MODULE_GLOBALS(beanstalk) 133 | long default_port; 134 | long hash_strategy; 135 | long hash_function; 136 | ZEND_END_MODULE_GLOBALS(beanstalk) 137 | */ 138 | /* 139 | #ifdef ZTS 140 | #define BEANSTALK_G(v) TSRMG(beanstalk_globals_id, zend_beanstalk_globals *, v) 141 | #else 142 | #define BEANSTALK_G(v) (beanstalk_globals.v) 143 | #endif 144 | */ 145 | 146 | #endif /* BEANSTALK_POOL_H */ 147 | 148 | 149 | /* 150 | * Local variables: 151 | * tab-width: 4 152 | * c-basic-offset: 4 153 | * End: 154 | * vim600: noet sw=4 ts=4 fdm=marker 155 | * vim<600: noet sw=4 ts=4 156 | */ 157 | -------------------------------------------------------------------------------- /beanstalk_consistent_hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.0 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_0.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Antony Dovgal | 16 | | Mikael Johansson | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | /* $Id: beanstalk_consistent_hash.c 310129 2011-04-11 04:44:27Z hradtke $ */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include 27 | 28 | #include "php.h" 29 | #include "beanstalk_pool.h" 30 | 31 | //ZEND_EXTERN_MODULE_GLOBALS(beanstalk) 32 | 33 | typedef struct bsc_consistent_point { 34 | bsc *server; 35 | unsigned int point; 36 | } bsc_consistent_point_t; 37 | 38 | typedef struct bsc_consistent_state { 39 | int num_servers; 40 | bsc_consistent_point_t *points; 41 | int num_points; 42 | bsc *buckets[BSC_CONSISTENT_BUCKETS]; 43 | int buckets_populated; 44 | bsc_hash_function_t *hash; 45 | } bsc_consistent_state_t; 46 | 47 | void *bsc_consistent_create_state(bsc_hash_function_t *hash) /* {{{ */ 48 | { 49 | bsc_consistent_state_t *state = emalloc(sizeof(bsc_consistent_state_t)); 50 | memset(state, 0, sizeof(bsc_consistent_state_t)); 51 | state->hash = hash; 52 | return state; 53 | } 54 | /* }}} */ 55 | 56 | void bsc_consistent_free_state(void *s) /* {{{ */ 57 | { 58 | bsc_consistent_state_t *state = s; 59 | if (state != NULL) { 60 | if (state->points != NULL) { 61 | efree(state->points); 62 | } 63 | efree(state); 64 | } 65 | } 66 | /* }}} */ 67 | 68 | static int bsc_consistent_compare(const void *a, const void *b) /* {{{ */ 69 | { 70 | if (((bsc_consistent_point_t *)a)->point < ((bsc_consistent_point_t *)b)->point) { 71 | return -1; 72 | } 73 | if (((bsc_consistent_point_t *)a)->point > ((bsc_consistent_point_t *)b)->point) { 74 | return 1; 75 | } 76 | return 0; 77 | } 78 | /* }}} */ 79 | 80 | static bsc *bsc_consistent_find(bsc_consistent_state_t *state, unsigned int point) /* {{{ */ 81 | { 82 | int lo = 0, hi = state->num_points - 1, mid; 83 | 84 | while (1) { 85 | /* point is outside interval or lo >= hi, wrap-around */ 86 | if (point <= state->points[lo].point || point > state->points[hi].point) { 87 | return state->points[lo].server; 88 | } 89 | 90 | /* test middle point */ 91 | mid = lo + (hi - lo) / 2; 92 | 93 | /* perfect match */ 94 | if (point <= state->points[mid].point && point > (mid ? state->points[mid-1].point : 0)) { 95 | return state->points[mid].server; 96 | } 97 | 98 | /* too low, go up */ 99 | if (state->points[mid].point < point) { 100 | lo = mid + 1; 101 | } 102 | else { 103 | hi = mid - 1; 104 | } 105 | } 106 | } 107 | /* }}} */ 108 | 109 | static void bsc_consistent_populate_buckets(bsc_consistent_state_t *state) /* {{{ */ 110 | { 111 | unsigned int i, step = 0xffffffff / BSC_CONSISTENT_BUCKETS; 112 | 113 | qsort((void *)state->points, state->num_points, sizeof(bsc_consistent_point_t), bsc_consistent_compare); 114 | for (i=0; ibuckets[i] = bsc_consistent_find(state, step * i); 116 | } 117 | 118 | state->buckets_populated = 1; 119 | } 120 | /* }}} */ 121 | 122 | bsc *bsc_consistent_find_server(void *s, const char *key, unsigned int key_len TSRMLS_DC) /* {{{ */ 123 | { 124 | bsc_consistent_state_t *state = s; 125 | 126 | if (state->num_servers > 1) { 127 | unsigned int hash; 128 | 129 | if (!state->buckets_populated) { 130 | bsc_consistent_populate_buckets(state); 131 | } 132 | 133 | hash = bsc_hash(state->hash, key, key_len); 134 | return state->buckets[hash % BSC_CONSISTENT_BUCKETS]; 135 | } 136 | 137 | return state->points[0].server; 138 | } 139 | /* }}} */ 140 | 141 | void bsc_consistent_add_server(void *s, bsc *svr, unsigned int weight) /* {{{ */ 142 | { 143 | bsc_consistent_state_t *state = s; 144 | int i, key_len, points = weight * BSC_CONSISTENT_POINTS; 145 | unsigned int seed = state->hash->init(), hash; 146 | 147 | /* buffer for "host:port-i\0" */ 148 | char *key = emalloc(strlen(svr->host) + MAX_LENGTH_OF_LONG * 2 + 3); 149 | key_len = sprintf(key, "%s:%d-", svr->host, svr->port); 150 | seed = state->hash->combine(seed, key, key_len); 151 | 152 | /* add weight * BSC_CONSISTENT_POINTS number of points for this server */ 153 | state->points = erealloc(state->points, sizeof(*state->points) * (state->num_points + points)); 154 | 155 | for (i=0; ihash->finish(state->hash->combine(seed, key, key_len)); 158 | state->points[state->num_points + i].server = svr; 159 | state->points[state->num_points + i].point = hash; 160 | } 161 | 162 | state->num_points += points; 163 | state->num_servers++; 164 | state->buckets_populated = 0; 165 | 166 | efree(key); 167 | } 168 | /* }}} */ 169 | 170 | bsc_hash_strategy_t bsc_consistent_hash = { 171 | bsc_consistent_create_state, 172 | bsc_consistent_free_state, 173 | bsc_consistent_find_server, 174 | bsc_consistent_add_server 175 | }; 176 | 177 | /* 178 | * Local variables: 179 | * tab-width: 4 180 | * c-basic-offset: 4 181 | * End: 182 | * vim600: noet sw=4 ts=4 fdm=marker 183 | * vim<600: noet sw=4 ts=4 184 | */ 185 | -------------------------------------------------------------------------------- /beanstalk_pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.0 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_0.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Antony Dovgal | 16 | | Mikael Johansson | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | /* $Id: beanstalk_pool.c 310129 2011-04-11 04:44:27Z hradtke $ */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include "php.h" 27 | #include "ext/standard/crc32.h" 28 | #include "ext/standard/php_var.h" 29 | #include "ext/standard/php_string.h" 30 | #include "ext/standard/php_smart_str.h" 31 | #include "beanstalk_pool.h" 32 | 33 | //ZEND_EXTERN_MODULE_GLOBALS(beanstalk) 34 | 35 | static unsigned int bsc_hash_crc32_init() { return ~0; } 36 | static unsigned int bsc_hash_crc32_finish(unsigned int seed) { return ~seed; } 37 | 38 | static unsigned int bsc_hash_crc32_combine(unsigned int seed, const void *key, unsigned int key_len) /* 39 | CRC32 hash {{{ */ 40 | { 41 | const char *p = (const char *)key, *end = p + key_len; 42 | while (p < end) { 43 | CRC32(seed, *(p++)); 44 | } 45 | 46 | return seed; 47 | } 48 | /* }}} */ 49 | 50 | bsc_hash_function_t bsc_hash_crc32 = { 51 | bsc_hash_crc32_init, 52 | bsc_hash_crc32_combine, 53 | bsc_hash_crc32_finish 54 | }; 55 | 56 | static unsigned int bsc_hash_fnv1a_combine(unsigned int seed, const void *key, unsigned int key_len) /* 57 | FNV-1a hash {{{ */ 58 | { 59 | const char *p = (const char *)key, *end = p + key_len; 60 | while (p < end) { 61 | seed ^= (unsigned int)*(p++); 62 | seed *= FNV_32_PRIME; 63 | } 64 | 65 | return seed; 66 | } 67 | /* }}} */ 68 | 69 | static unsigned int bsc_hash_fnv1a_init() { return FNV_32_INIT; } 70 | static unsigned int bsc_hash_fnv1a_finish(unsigned int seed) { return seed; } 71 | 72 | bsc_hash_function_t bsc_hash_fnv1a = { 73 | bsc_hash_fnv1a_init, 74 | bsc_hash_fnv1a_combine, 75 | bsc_hash_fnv1a_finish 76 | }; 77 | 78 | /* 79 | double timeval_to_double(struct timeval tv) { 80 | return (double)tv.tv_sec + ((double)tv.tv_usec) / 1000000; 81 | } 82 | 83 | struct timeval double_to_timeval(double sec) { 84 | struct timeval tv; 85 | tv.tv_sec = (long)sec; 86 | tv.tv_usec = (sec - tv.tv_sec) * 1000000; 87 | return tv; 88 | } 89 | */ 90 | 91 | void bsc_error_callback(bsc *svr, bsc_error_t error) 92 | { 93 | char errorstr[BSC_ERRSTR_LEN]; 94 | 95 | switch (error) { 96 | case BSC_ERROR_INTERNAL: 97 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: recieved BSC_ERROR_INTERNAL, quitting"); 98 | break; 99 | case BSC_ERROR_MEMORY: 100 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: recieved BSC_ERROR_MEMORY, quitting"); 101 | break; 102 | case BSC_ERROR_SOCKET: 103 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "error: recieved BSC_ERROR_SOCKET, quitting ..."); 104 | break; 105 | default: 106 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", error); 107 | } 108 | } 109 | 110 | bsc *bsc_server_new( 111 | const char *host, int host_len, unsigned short tcp_port, 112 | double timeout, int retry_interval TSRMLS_DC) /* {{{ */ 113 | { 114 | bsc * svr; 115 | char errorstr[BSC_ERRSTR_LEN]; 116 | char port[BSC_PORT_LEN]; 117 | sprintf(port, "%d", tcp_port); 118 | svr = bsc_new_w_defaults(host, port, BSC_DEFAULT_TUBE, bsc_error_callback, errorstr); 119 | return svr; 120 | } 121 | /* }}} */ 122 | 123 | void bsc_server_free(bsc *svr TSRMLS_DC) /* {{{ */ 124 | { 125 | bsc_free(svr); 126 | } 127 | /* }}} */ 128 | 129 | static void bsc_pool_init_hash(bsc_pool_t *pool TSRMLS_DC) /* {{{ */ 130 | { 131 | bsc_hash_function_t *hash; 132 | 133 | switch (BSC_STANDARD_HASH) { 134 | case BSC_CONSISTENT_HASH: 135 | pool->hash = &bsc_consistent_hash; 136 | break; 137 | default: 138 | pool->hash = &bsc_standard_hash; 139 | } 140 | 141 | switch (BSC_HASH_CRC32) { 142 | case BSC_HASH_FNV1A: 143 | hash = &bsc_hash_fnv1a; 144 | break; 145 | default: 146 | hash = &bsc_hash_crc32; 147 | } 148 | 149 | pool->hash_state = pool->hash->create_state(hash); 150 | } 151 | /* }}} */ 152 | 153 | bsc_pool_t *bsc_pool_new(TSRMLS_D) /* {{{ */ 154 | { 155 | bsc_pool_t *pool = emalloc(sizeof(bsc_pool_t)); 156 | memset(pool, 0, sizeof(*pool)); 157 | 158 | bsc_pool_init_hash(pool TSRMLS_CC); 159 | 160 | return pool; 161 | } 162 | /* }}} */ 163 | 164 | void bsc_pool_free(bsc_pool_t *pool TSRMLS_DC) /* {{{ */ 165 | { 166 | int i; 167 | 168 | for (i=0; inum_servers; i++) { 169 | if (pool->servers[i] != NULL) { 170 | bsc_server_free(pool->servers[i]); 171 | pool->servers[i] = NULL; 172 | } 173 | } 174 | 175 | if (pool->num_servers) { 176 | efree(pool->servers); 177 | } 178 | 179 | pool->hash->free_state(pool->hash_state); 180 | 181 | efree(pool); 182 | } 183 | /* }}} */ 184 | 185 | void bsc_pool_add(bsc_pool_t *pool, bsc *svr, unsigned int weight) /* 186 | adds a server to the pool and hash strategy {{{ */ 187 | { 188 | pool->hash->add_server(pool->hash_state, svr, weight); 189 | pool->servers = erealloc(pool->servers, sizeof(*pool->servers) * (pool->num_servers + 1)); 190 | pool->servers[pool->num_servers] = svr; 191 | 192 | /* store the smallest timeout for any server */ 193 | /* 194 | if (!pool->num_servers || timeval_to_double(bsc->timeout) < timeval_to_double(pool->timeout)) { 195 | pool->timeout = bsc->timeout; 196 | } 197 | */ 198 | 199 | pool->num_servers++; 200 | } 201 | /* }}} */ 202 | 203 | void bsc_pool_close(bsc_pool_t *pool TSRMLS_DC) /* 204 | disconnects and removes all servers in the pool {{{ */ 205 | { 206 | if (pool->num_servers) { 207 | int i; 208 | 209 | for (i=0; inum_servers; i++) { 210 | bsc_server_free(pool->servers[i] TSRMLS_CC); 211 | } 212 | 213 | efree(pool->servers); 214 | pool->servers = NULL; 215 | pool->num_servers = 0; 216 | 217 | /* reallocate the hash strategy state */ 218 | pool->hash->free_state(pool->hash_state); 219 | bsc_pool_init_hash(pool TSRMLS_CC); 220 | } 221 | } 222 | /* }}} */ 223 | 224 | bsc *bsc_pool_find(bsc_pool_t *pool, const char *key, unsigned int key_len TSRMLS_DC) /* 225 | maps a key to a non-failed server {{{ */ 226 | { 227 | bsc *svr = pool->hash->find_server(pool->hash_state, key, key_len TSRMLS_CC); 228 | 229 | return svr; 230 | } 231 | /* }}} */ 232 | 233 | /* 234 | * Local variables: 235 | * tab-width: 4 236 | * c-basic-offset: 4 237 | * End: 238 | * vim600: noet sw=4 ts=4 fdm=marker 239 | * vim<600: noet sw=4 ts=4 240 | */ 241 | -------------------------------------------------------------------------------- /beanstalk.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id: header,v 1.16.2.1.2.1 2007/01/01 19:32:09 iliaa Exp $ */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include "php.h" 26 | #include "php_ini.h" 27 | #include "ext/standard/info.h" 28 | #include "ext/standard/php_string.h" 29 | #include "php_beanstalk.h" 30 | 31 | #ifndef ZEND_ENGINE_2 32 | #define OnUpdateLong OnUpdateInt 33 | #endif 34 | 35 | /* If you declare any globals in php_beanstalk.h uncomment this: 36 | ZEND_DECLARE_MODULE_GLOBALS(beanstalk) 37 | */ 38 | 39 | /* True global resources - no need for thread safety here */ 40 | //static int le_beanstalk; 41 | static int le_beanstalk_pool; 42 | static zend_class_entry *beanstalk_pool_ce; 43 | static zend_class_entry *beanstalk_ce; 44 | 45 | /* {{{ beanstalk_functions[] 46 | * 47 | * Every user visible function must have an entry in beanstalk_functions[]. 48 | */ 49 | zend_function_entry beanstalk_functions[] = { 50 | PHP_FE(beanstalk_add_server, NULL) 51 | PHP_FE(beanstalk_use, NULL) 52 | PHP_FE(beanstalk_put, NULL) 53 | PHP_FE(beanstalk_watch, NULL) 54 | PHP_FE(beanstalk_reserve, NULL) 55 | PHP_FE(beanstalk_bury, NULL) 56 | PHP_FE(beanstalk_ignore, NULL) 57 | PHP_FE(beanstalk_delete, NULL) 58 | PHP_FE(beanstalk_kick, NULL) 59 | PHP_FE(beanstalk_list_tubes, NULL) 60 | /*PHP_FE(beanstalk_release, NULL) 61 | PHP_FE(beanstalk_touch, NULL) 62 | PHP_FE(beanstalk_peek, NULL) 63 | PHP_FE(beanstalk_quit, NULL)*/ 64 | {NULL, NULL, NULL} /* Must be the last line in beanstalk_functions[] */ 65 | }; 66 | 67 | zend_function_entry php_beanstalk_pool_class_functions[] = { 68 | PHP_NAMED_FE(addserver, zif_beanstalk_pool_addserver, NULL) 69 | //PHP_NAMED_FE(findserver, zif_beanstalk_pool_findserver, NULL) 70 | PHP_FALIAS(use, beanstalk_use, NULL) 71 | PHP_FALIAS(put, beanstalk_put, NULL) 72 | PHP_FALIAS(watch, beanstalk_watch, NULL) 73 | PHP_FALIAS(reserve, beanstalk_reserve, NULL) 74 | PHP_FALIAS(bury, beanstalk_bury, NULL) 75 | PHP_FALIAS(ignore, beanstalk_ignore, NULL) 76 | PHP_FALIAS(delete, beanstalk_delete, NULL) 77 | PHP_FALIAS(kick, beanstalk_kick, NULL) 78 | PHP_FALIAS(list_tubes, beanstalk_list_tubes, NULL) 79 | /*PHP_FALIAS(release, beanstalk_release, NULL) 80 | PHP_FALIAS(touch, beanstalk_touch, NULL) 81 | PHP_FALIAS(peek, beanstalk_peek, NULL) 82 | PHP_FALIAS(quit, beanstalk_quit, NULL)*/ 83 | {NULL, NULL, NULL} 84 | }; 85 | 86 | zend_function_entry php_beanstalk_class_functions[] = { 87 | PHP_FALIAS(addserver, beanstalk_add_server, NULL) 88 | {NULL, NULL, NULL} 89 | }; 90 | /* }}} */ 91 | 92 | /* {{{ beanstalk_module_entry 93 | */ 94 | zend_module_entry beanstalk_module_entry = { 95 | #if ZEND_MODULE_API_NO >= 20010901 96 | STANDARD_MODULE_HEADER, 97 | #endif 98 | "beanstalk", 99 | beanstalk_functions, 100 | PHP_MINIT(beanstalk), 101 | PHP_MSHUTDOWN(beanstalk), 102 | NULL, /* Replace with NULL if there's nothing to do at request start */ 103 | NULL, /* Replace with NULL if there's nothing to do at request end */ 104 | PHP_MINFO(beanstalk), 105 | #if ZEND_MODULE_API_NO >= 20010901 106 | PHP_BEANSTALK_VERSION, /* Replace with version number for your extension */ 107 | #endif 108 | STANDARD_MODULE_PROPERTIES 109 | }; 110 | /* }}} */ 111 | 112 | #ifdef COMPILE_DL_BEANSTALK 113 | ZEND_GET_MODULE(beanstalk) 114 | #endif 115 | 116 | /* 117 | static PHP_INI_MH(OnUpdateHashStrategy) 118 | { 119 | if (!strcasecmp(new_value, "standard")) { 120 | BEANSTALK_G(hash_strategy) = BSC_STANDARD_HASH; 121 | } 122 | else if (!strcasecmp(new_value, "consistent")) { 123 | BEANSTALK_G(hash_strategy) = BSC_CONSISTENT_HASH; 124 | } 125 | else { 126 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "beanstalk.hash_strategy must be in set {standard, consistent} ('%s' given)", new_value); 127 | return FAILURE; 128 | } 129 | 130 | return SUCCESS; 131 | } 132 | 133 | static PHP_INI_MH(OnUpdateHashFunction) 134 | { 135 | if (!strcasecmp(new_value, "crc32")) { 136 | BEANSTALK_G(hash_function) = BSC_HASH_CRC32; 137 | } 138 | else if (!strcasecmp(new_value, "fnv")) { 139 | BEANSTALK_G(hash_function) = BSC_HASH_FNV1A; 140 | } 141 | else { 142 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "beanstalk.hash_function must be in set {crc32, fnv} ('%s' given)", new_value); 143 | return FAILURE; 144 | } 145 | 146 | return SUCCESS; 147 | } 148 | */ 149 | 150 | /* {{{ PHP_INI 151 | /* Remove comments and fill if you need to have entries in php.ini 152 | PHP_INI_BEGIN() 153 | STD_PHP_INI_ENTRY("beanstalk.default_port", DEFAULT_PORT, PHP_INI_ALL, OnUpdateLong, default_port, zend_beanstalk_globals, beanstalk_globals) 154 | STD_PHP_INI_ENTRY("beanstalk.hash_strategy", "consistent", PHP_INI_ALL, OnUpdateHashStrategy, hash_strategy, zend_beanstalk_globals, beanstalk_globals) 155 | STD_PHP_INI_ENTRY("beanstalk.hash_function", "crc32", PHP_INI_ALL, OnUpdateHashFunction, hash_function, zend_beanstalk_globals, beanstalk_globals) 156 | PHP_INI_END() 157 | */ 158 | /* }}} */ 159 | 160 | /* {{{ internal function protos */ 161 | static void _bsc_pool_list_dtor(zend_rsrc_list_entry * TSRMLS_DC); 162 | static void php_bsc_set_failure_callback(bsc_pool_t *, zval *, zval * TSRMLS_DC); 163 | static void php_bsc_failure_callback(bsc_pool_t *, bsc *, void * TSRMLS_DC); 164 | /* }}} */ 165 | 166 | /* {{{ php_beanstalk_init_globals 167 | */ 168 | /* Uncomment this function if you have INI entries 169 | static void php_beanstalk_init_globals(zend_beanstalk_globals *beanstalk_globals) 170 | { 171 | // BEANSTALK_G(hash_strategy) = BSC_STANDARD_HASH; 172 | // BEANSTALK_G(hash_function) = BSC_HASH_CRC32; 173 | } 174 | */ 175 | /* }}} */ 176 | 177 | /* {{{ PHP_MINIT_FUNCTION 178 | */ 179 | PHP_MINIT_FUNCTION(beanstalk) 180 | { 181 | /* If you have INI entries, uncomment these lines 182 | REGISTER_INI_ENTRIES(); 183 | */ 184 | zend_class_entry ce; 185 | 186 | INIT_CLASS_ENTRY(ce, "BeanstalkPool", php_beanstalk_pool_class_functions); 187 | beanstalk_pool_ce = zend_register_internal_class(&ce TSRMLS_CC); 188 | 189 | INIT_CLASS_ENTRY(ce, "Beanstalk", php_beanstalk_class_functions); 190 | beanstalk_ce = zend_register_internal_class_ex(&ce, beanstalk_pool_ce, NULL TSRMLS_CC); 191 | 192 | le_beanstalk_pool = zend_register_list_destructors_ex(_bsc_pool_list_dtor, NULL, "beanstalk connection", module_number); 193 | 194 | #ifdef ZTS 195 | ts_allocate_id(&beanstalk_globals_id, sizeof(zend_beanstalk_globals), (ts_allocate_ctor) php_beanstalk_init_globals, NULL); 196 | #else 197 | //php_beanstalk_init_globals(&beanstalk_globals TSRMLS_CC); 198 | #endif 199 | 200 | return SUCCESS; 201 | } 202 | /* }}} */ 203 | 204 | /* {{{ PHP_MSHUTDOWN_FUNCTION 205 | */ 206 | PHP_MSHUTDOWN_FUNCTION(beanstalk) 207 | { 208 | /* uncomment this line if you have INI entries 209 | UNREGISTER_INI_ENTRIES(); 210 | */ 211 | return SUCCESS; 212 | } 213 | /* }}} */ 214 | 215 | /* Remove if there's nothing to do at request start */ 216 | /* {{{ PHP_RINIT_FUNCTION 217 | PHP_RINIT_FUNCTION(beanstalk) 218 | { 219 | return SUCCESS; 220 | } 221 | */ 222 | /* }}} */ 223 | 224 | /* Remove if there's nothing to do at request end */ 225 | /* {{{ PHP_RSHUTDOWN_FUNCTION 226 | PHP_RSHUTDOWN_FUNCTION(beanstalk) 227 | { 228 | return SUCCESS; 229 | } 230 | */ 231 | /* }}} */ 232 | 233 | /* {{{ PHP_MINFO_FUNCTION 234 | */ 235 | PHP_MINFO_FUNCTION(beanstalk) 236 | { 237 | php_info_print_table_start(); 238 | php_info_print_table_header(2, "beanstalk support", "enabled"); 239 | php_info_print_table_row(2, "Version", PHP_BEANSTALK_VERSION); 240 | php_info_print_table_row(2, "Revision", "$Revision: 310129 $"); 241 | php_info_print_table_end(); 242 | 243 | /* Remove comments if you have entries in php.ini 244 | */ 245 | DISPLAY_INI_ENTRIES(); 246 | } 247 | /* }}} */ 248 | 249 | 250 | /* ------------------ 251 | internal functions 252 | ------------------ */ 253 | 254 | static void _bsc_pool_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ 255 | { 256 | bsc_pool_t *pool = (bsc_pool_t *)rsrc->ptr; 257 | 258 | if (pool->failure_callback_param) { 259 | zval_ptr_dtor((zval **)&pool->failure_callback_param); 260 | pool->failure_callback_param = NULL; 261 | } 262 | 263 | bsc_pool_free(pool TSRMLS_CC); 264 | } 265 | 266 | static int bsc_get_pool(zval *id, bsc_pool_t **pool TSRMLS_DC) /* {{{ */ 267 | { 268 | zval **connection; 269 | int resource_type; 270 | 271 | if (Z_TYPE_P(id) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(id), "connection", sizeof("connection"), (void**)&connection) == FAILURE) { 272 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "No servers added to beanstalk connection"); 273 | return 0; 274 | } 275 | 276 | *pool = (bsc_pool_t *) zend_list_find(Z_LVAL_PP(connection), &resource_type); 277 | if (!*pool || resource_type != le_beanstalk_pool) { 278 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid BeanstalkPool->connection member variable"); 279 | return 0; 280 | } 281 | 282 | return Z_LVAL_PP(connection); 283 | } 284 | /* }}} */ 285 | 286 | static bsc *php_bsc_pool_addserver( 287 | zval *bsc_object, const char *host, int host_len, long tcp_port, long weight, 288 | double timeout, long retry_interval, zend_bool status, bsc_pool_t **pool_result TSRMLS_DC) /* {{{ */ 289 | { 290 | zval **connection; 291 | bsc_pool_t *pool; 292 | bsc *svr; 293 | int list_id, resource_type; 294 | 295 | if (weight < 1) { 296 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "weight must be a positive integer"); 297 | return NULL; 298 | } 299 | 300 | /* initialize pool if need be */ 301 | if (zend_hash_find(Z_OBJPROP_P(bsc_object), "connection", sizeof("connection"), (void **)&connection) == FAILURE) { 302 | pool = bsc_pool_new(TSRMLS_C); 303 | pool->failure_callback = &php_bsc_failure_callback; 304 | list_id = zend_list_insert(pool, le_beanstalk_pool); 305 | add_property_resource(bsc_object, "connection", list_id); 306 | } 307 | else { 308 | pool = (bsc_pool_t *)zend_list_find(Z_LVAL_PP(connection), &resource_type); 309 | if (!pool || resource_type != le_beanstalk_pool) { 310 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown connection identifier"); 311 | return NULL; 312 | } 313 | } 314 | 315 | /* lazy initialization of server struct */ 316 | //svr = bsc_find_persistent(host, host_len, tcp_port, timeout, retry_interval TSRMLS_CC); 317 | svr = bsc_server_new(host, host_len, tcp_port, timeout, retry_interval TSRMLS_CC); 318 | if(svr) 319 | { 320 | bsc_pool_add(pool, svr, weight); 321 | } 322 | 323 | if (pool_result != NULL) { 324 | *pool_result = pool; 325 | } 326 | 327 | return svr; 328 | } 329 | /* }}} */ 330 | 331 | static void php_bsc_failure_callback(bsc_pool_t *pool, bsc *svr, void *param TSRMLS_DC) /* {{{ */ 332 | { 333 | zval **callback; 334 | 335 | /* check for userspace callback*/ 336 | if (param != NULL && zend_hash_find(Z_OBJPROP_P((zval *)param), "_failureCallback", sizeof("_failureCallback"), (void **)&callback) == SUCCESS && Z_TYPE_PP(callback) != IS_NULL) { 337 | if (IS_CALLABLE(*callback, 0, NULL)) { 338 | zval *retval = NULL; 339 | zval *host, *tcp_port, *error, *errnum; 340 | zval **params[2]; 341 | 342 | params[0] = &host; 343 | params[1] = &tcp_port; 344 | 345 | MAKE_STD_ZVAL(host); 346 | MAKE_STD_ZVAL(tcp_port); 347 | 348 | ZVAL_STRING(host, svr->host, 1); 349 | ZVAL_STRING(tcp_port, svr->host, 1); 350 | 351 | call_user_function_ex(EG(function_table), NULL, *callback, &retval, 5, params, 0, NULL TSRMLS_CC); 352 | 353 | zval_ptr_dtor(&host); 354 | zval_ptr_dtor(&tcp_port); 355 | 356 | if (retval != NULL) { 357 | zval_ptr_dtor(&retval); 358 | } 359 | } 360 | else { 361 | php_bsc_set_failure_callback(pool, (zval *)param, NULL TSRMLS_CC); 362 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback"); 363 | } 364 | } 365 | else { 366 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Server %s (tcp ) failed.", svr->host, svr->port); 367 | } 368 | } 369 | /* }}} */ 370 | 371 | static void php_bsc_set_failure_callback(bsc_pool_t *pool, zval *bsc_object, zval *callback TSRMLS_DC) /* {{{ 372 | */ 373 | { 374 | // Decrease refcount of old bsc_object 375 | if (pool->failure_callback_param) { 376 | zval_ptr_dtor((zval **)&pool->failure_callback_param); 377 | } 378 | 379 | if (callback != NULL) { 380 | zval *callback_tmp; 381 | ALLOC_ZVAL(callback_tmp); 382 | 383 | *callback_tmp = *callback; 384 | zval_copy_ctor(callback_tmp); 385 | INIT_PZVAL(callback_tmp); 386 | 387 | add_property_zval(bsc_object, "_failureCallback", callback_tmp); 388 | pool->failure_callback_param = bsc_object; 389 | zval_add_ref(&bsc_object); 390 | 391 | INIT_PZVAL(callback_tmp); 392 | } 393 | else { 394 | add_property_null(bsc_object, "_failureCallback"); 395 | pool->failure_callback_param = NULL; 396 | } 397 | } 398 | /* }}} */ 399 | 400 | /* ---------------- 401 | module functions 402 | ---------------- */ 403 | 404 | /* {{{ proto bool BeanstalkPool::addServer(string host [, int tcp_port [, [, int weight [, double timeout [, int retry_interval [, bool status] ] ]) 405 | Adds a server to the pool */ 406 | PHP_NAMED_FUNCTION(zif_beanstalk_pool_addserver) 407 | { 408 | zval *bsc_object = getThis(); 409 | bsc *svr; 410 | 411 | char *host; 412 | int host_len; 413 | long tcp_port = DEFAULT_PORT, weight = 1, retry_interval = BSC_DEFAULT_RETRY; 414 | double timeout = BSC_DEFAULT_TIMEOUT; 415 | zend_bool status = 1; 416 | 417 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lldlb", 418 | &host, &host_len, &tcp_port, &weight, &timeout, &retry_interval, &status) == FAILURE) { 419 | return; 420 | } 421 | 422 | svr = php_bsc_pool_addserver(bsc_object, host, host_len, tcp_port, weight, timeout, retry_interval, status, NULL TSRMLS_CC); 423 | if (svr == NULL) { 424 | RETURN_FALSE; 425 | } 426 | 427 | RETURN_TRUE; 428 | } 429 | /* }}} */ 430 | 431 | /* {{{ proto bool beanstalk_add_server(string host [, int port [, int weight [, double timeout [, int retry_interval [, bool status [, callback failure_callback ] ] ] ] ] ]) 432 | Adds a server to the pool.*/ 433 | PHP_FUNCTION(beanstalk_add_server) 434 | { 435 | zval *bsc_object = getThis(), *failure_callback = NULL; 436 | bsc_pool_t *pool; 437 | bsc *svr; 438 | 439 | char *host; 440 | int host_len; 441 | int tcp_port = DEFAULT_PORT; 442 | int weight = 1; 443 | int retry_interval = BSC_DEFAULT_RETRY; 444 | double timeout = BSC_DEFAULT_TIMEOUT; 445 | zend_bool status = 1; 446 | 447 | if (bsc_object) { 448 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lldlbz", 449 | &host, &host_len, &tcp_port, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) { 450 | return; 451 | } 452 | } 453 | else { 454 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lldlbz", &bsc_object, beanstalk_ce, 455 | &host, &host_len, &tcp_port, &weight, &timeout, &retry_interval, &status, &failure_callback) == FAILURE) { 456 | return; 457 | } 458 | } 459 | 460 | if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { 461 | if (!IS_CALLABLE(failure_callback, 0, NULL)) { 462 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid failure callback"); 463 | RETURN_FALSE; 464 | } 465 | } 466 | 467 | svr = php_bsc_pool_addserver(bsc_object, host, host_len, tcp_port, weight, timeout, retry_interval, status, &pool TSRMLS_CC); 468 | if (svr == NULL) { 469 | RETURN_FALSE; 470 | } 471 | 472 | if (failure_callback != NULL && Z_TYPE_P(failure_callback) != IS_NULL) { 473 | php_bsc_set_failure_callback(pool, bsc_object, failure_callback TSRMLS_CC); 474 | } 475 | 476 | RETURN_TRUE; 477 | } 478 | /* }}} */ 479 | 480 | fd_set readset, writeset; 481 | static bsc_error_t bsc_error; 482 | int cmd_poll(bsc *svr, fd_set *readset, fd_set *writeset) 483 | { 484 | FD_SET(svr->fd, readset); 485 | FD_SET(svr->fd, writeset); 486 | if (AQ_EMPTY(svr->outq)) { 487 | if ( select(svr->fd+1, readset, NULL, NULL, NULL) < 0) { 488 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: select()"); 489 | return false; 490 | } 491 | if (FD_ISSET(svr->fd, readset)) 492 | bsc_read(svr); 493 | } 494 | else { 495 | if ( select(svr->fd+1, readset, writeset, NULL, NULL) < 0) { 496 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: select()"); 497 | return false; 498 | } 499 | if (FD_ISSET(svr->fd, readset)) 500 | bsc_read(svr); 501 | if (FD_ISSET(svr->fd, writeset)) 502 | bsc_write(svr); 503 | } 504 | } 505 | 506 | static int use_flag = false; 507 | static struct bsc_use_info *g_use_info = NULL; 508 | void use_callback(bsc *svr, struct bsc_use_info *info) 509 | { 510 | g_use_info = info; 511 | use_flag = true; 512 | } 513 | 514 | bool cmd_use(bsc *svr, char *tube, int tube_len) 515 | { 516 | 517 | bsc_error = bsc_use(svr, use_callback, NULL, tube); 518 | 519 | if (bsc_error != BSC_ERROR_NONE) { 520 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 521 | return false; 522 | } 523 | 524 | FD_ZERO(&readset); 525 | FD_ZERO(&writeset); 526 | 527 | while (!use_flag) 528 | { 529 | cmd_poll(svr, &readset, &writeset); 530 | } 531 | 532 | return true; 533 | } 534 | 535 | /* {{{ proto bool beanstalk_use(object beanstalk, string tube) 536 | */ 537 | PHP_FUNCTION(beanstalk_use) 538 | { 539 | bsc_pool_t *pool; 540 | bsc * svr; 541 | char *tube; 542 | int tube_len; 543 | zval *bsc_object = getThis(); 544 | 545 | if (bsc_object == NULL) { 546 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os", &bsc_object, beanstalk_pool_ce, &tube, &tube_len) == FAILURE) { 547 | return; 548 | } 549 | } 550 | else { 551 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tube, &tube_len) == FAILURE) { 552 | return; 553 | } 554 | } 555 | 556 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 557 | RETURN_FALSE; 558 | } 559 | 560 | RETVAL_NULL(); 561 | 562 | svr = bsc_pool_find(pool, tube, tube_len); 563 | if(!svr){ 564 | RETURN_FALSE; 565 | } 566 | 567 | if(cmd_use(svr, tube, tube_len) && g_use_info){ 568 | if(BSC_USE_RES_USING == g_use_info->response.code){ 569 | g_use_info = NULL; 570 | use_flag = false; 571 | RETURN_TRUE; 572 | } 573 | } 574 | 575 | RETURN_FALSE; 576 | } 577 | 578 | static int put_flag = false; 579 | static struct bsc_put_info *g_put_info = NULL; 580 | void put_callback(bsc *svr, struct bsc_put_info *info) 581 | { 582 | g_put_info = info; 583 | put_flag = true; 584 | } 585 | 586 | bool cmd_put(bsc *svr, char *value, int value_len) 587 | { 588 | bsc_error = bsc_put(svr, put_callback, NULL, BSC_DEFAULT_PRORITY, 589 | BSC_DEFAULT_DELAY, BSC_DEFAULT_TTR, value_len, value, false); 590 | 591 | if (bsc_error != BSC_ERROR_NONE) { 592 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 593 | return false; 594 | } 595 | 596 | FD_ZERO(&readset); 597 | FD_ZERO(&writeset); 598 | 599 | while (!put_flag) 600 | { 601 | cmd_poll(svr, &readset, &writeset); 602 | } 603 | 604 | return true; 605 | } 606 | 607 | /* {{{ proto bool beanstalk_put(object beanstalk, string tube [, mixed var [, int flag [, int exptime ] ] ]) 608 | Sets the value of an item. Item may exist or not */ 609 | PHP_FUNCTION(beanstalk_put) 610 | { 611 | bsc_pool_t *pool; 612 | bsc * svr; 613 | char *tube, *value; 614 | int tube_len, value_len; 615 | zval *bsc_object = getThis(); 616 | long flags = 0, exptime = 0; 617 | 618 | if (bsc_object == NULL) { 619 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oss|ll", &bsc_object, beanstalk_pool_ce, &tube, &tube_len, &value, &value_len, &flags, &exptime) == FAILURE) { 620 | return; 621 | } 622 | } 623 | else { 624 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &tube, &tube_len, &value, &value_len, &flags, &exptime) == FAILURE) { 625 | return; 626 | } 627 | } 628 | 629 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 630 | RETURN_FALSE; 631 | } 632 | 633 | RETVAL_NULL(); 634 | 635 | svr = bsc_pool_find(pool, tube, tube_len); 636 | if(!svr) { 637 | RETURN_FALSE; 638 | } 639 | 640 | if(cmd_put(svr, value, value_len) && g_put_info) { 641 | if(BSC_PUT_RES_INSERTED == g_put_info->response.code) { 642 | g_put_info = NULL; 643 | put_flag = false; 644 | RETURN_TRUE; 645 | } 646 | } 647 | 648 | RETURN_FALSE; 649 | } 650 | /* }}} */ 651 | 652 | 653 | static int wtch_flag = false; 654 | static struct bsc_watch_info *g_wtch_info = NULL; 655 | void wtch_callback(bsc *svr, struct bsc_watch_info *info) 656 | { 657 | g_wtch_info = info; 658 | wtch_flag = true; 659 | } 660 | 661 | bool cmd_watch(bsc *svr, char *tube, int tube_len) 662 | { 663 | bsc_error = bsc_watch(svr, wtch_callback, NULL, tube); 664 | 665 | if (bsc_error != BSC_ERROR_NONE) { 666 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 667 | return false; 668 | } 669 | 670 | FD_ZERO(&readset); 671 | FD_ZERO(&writeset); 672 | 673 | while (!wtch_flag) 674 | { 675 | cmd_poll(svr, &readset, &writeset); 676 | } 677 | 678 | return true; 679 | } 680 | 681 | /* {{{ proto bool beanstalk_watch(object beanstalk, string tube) 682 | */ 683 | PHP_FUNCTION(beanstalk_watch) 684 | { 685 | bsc_pool_t *pool; 686 | bsc * svr; 687 | char *tube; 688 | int tube_len; 689 | zval *bsc_object = getThis(); 690 | 691 | if (bsc_object == NULL) { 692 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os", &bsc_object, beanstalk_pool_ce, &tube, &tube_len) == FAILURE) { 693 | return; 694 | } 695 | } 696 | else { 697 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tube, &tube_len) == FAILURE) { 698 | return; 699 | } 700 | } 701 | 702 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 703 | RETURN_FALSE; 704 | } 705 | 706 | RETVAL_NULL(); 707 | 708 | svr = bsc_pool_find(pool, tube, tube_len); 709 | if(!svr) 710 | { 711 | RETURN_FALSE; 712 | } 713 | 714 | if(cmd_watch(svr, tube, tube_len) && g_wtch_info) { 715 | if(BSC_RES_WATCHING == g_wtch_info->response.code) 716 | { 717 | g_wtch_info = NULL; 718 | wtch_flag = false; 719 | RETURN_TRUE; 720 | } 721 | } 722 | 723 | RETURN_FALSE; 724 | } 725 | 726 | static int ign_flag = false; 727 | static struct bsc_ignore_info *g_ign_info = NULL; 728 | void ign_callback(bsc *svr, struct bsc_ignore_info *info) 729 | { 730 | g_ign_info = info; 731 | ign_flag = true; 732 | } 733 | 734 | bool cmd_ignore(bsc *svr, char *tube, int tube_len) 735 | { 736 | bsc_error = bsc_ignore(svr, ign_callback, NULL, tube); 737 | 738 | if (bsc_error != BSC_ERROR_NONE) { 739 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 740 | return false; 741 | } 742 | 743 | FD_ZERO(&readset); 744 | FD_ZERO(&writeset); 745 | 746 | while (!ign_flag) 747 | { 748 | cmd_poll(svr, &readset, &writeset); 749 | } 750 | 751 | return true; 752 | } 753 | 754 | /* {{{ proto bool beanstalk_ignore(object beanstalk, string tube) 755 | */ 756 | PHP_FUNCTION(beanstalk_ignore) 757 | { 758 | bsc_pool_t *pool; 759 | bsc * svr; 760 | char *tube; 761 | int tube_len; 762 | zval *bsc_object = getThis(); 763 | 764 | if (bsc_object == NULL) { 765 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os", &bsc_object, beanstalk_pool_ce, &tube, &tube_len) == FAILURE) { 766 | return; 767 | } 768 | } 769 | else { 770 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tube, &tube_len) == FAILURE) { 771 | return; 772 | } 773 | } 774 | 775 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 776 | RETURN_FALSE; 777 | } 778 | 779 | RETVAL_NULL(); 780 | 781 | svr = bsc_pool_find(pool, tube, tube_len); 782 | if(!svr) 783 | { 784 | RETURN_FALSE; 785 | } 786 | 787 | if(cmd_ignore(svr, tube, tube_len) && g_ign_info) 788 | { 789 | if(BSC_RES_WATCHING == g_ign_info->response.code) 790 | { 791 | g_ign_info = NULL; 792 | ign_flag = false; 793 | RETURN_TRUE; 794 | } 795 | } 796 | 797 | RETURN_FALSE; 798 | } 799 | 800 | static int rsv_flag = false; 801 | static struct bsc_reserve_info *g_rsv_info = NULL; 802 | void rsv_callback(bsc *svr, struct bsc_reserve_info *info) 803 | { 804 | g_rsv_info = info; 805 | rsv_flag = true; 806 | } 807 | 808 | bool cmd_reserve(bsc *svr, int timeout) 809 | { 810 | bsc_error = bsc_reserve(svr, rsv_callback, NULL, timeout); 811 | if (bsc_error != BSC_ERROR_NONE) { 812 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 813 | return false; 814 | } 815 | 816 | FD_ZERO(&readset); 817 | FD_ZERO(&writeset); 818 | 819 | while (!rsv_flag) { 820 | cmd_poll(svr, &readset, &writeset); 821 | } 822 | 823 | return true; 824 | } 825 | 826 | /* {{{ proto bool beanstalk_reserve(object beanstalk, char *tube, int tube_len, int timeout ]) 827 | Returns value of existing item or false */ 828 | PHP_FUNCTION(beanstalk_reserve) 829 | { 830 | bsc_pool_t *pool; 831 | bsc * svr; 832 | char *tube, *value; 833 | int tube_len, value_len; 834 | int timeout; 835 | zval *bsc_object = getThis(); 836 | long flags = 0, exptime = 0; 837 | 838 | if (bsc_object == NULL) { 839 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &bsc_object, beanstalk_pool_ce, &tube, &tube_len, &timeout) == FAILURE) { 840 | return; 841 | } 842 | } 843 | else { 844 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &tube, &tube_len, &timeout) == FAILURE) { 845 | return; 846 | } 847 | } 848 | 849 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 850 | RETURN_FALSE; 851 | } 852 | 853 | RETVAL_NULL(); 854 | 855 | svr = bsc_pool_find(pool, tube, tube_len); 856 | if(!svr) 857 | { 858 | RETURN_FALSE; 859 | } 860 | 861 | array_init(return_value); 862 | 863 | if(cmd_reserve(svr, timeout) && g_rsv_info) 864 | { 865 | if(BSC_RESERVE_RES_RESERVED == g_rsv_info->response.code) 866 | { 867 | add_assoc_long(return_value, "id", g_rsv_info->response.id); 868 | add_assoc_stringl(return_value, "data", g_rsv_info->response.data, g_rsv_info->response.bytes, 1); 869 | } 870 | } 871 | g_rsv_info = NULL; 872 | rsv_flag = false; 873 | } 874 | 875 | static int bury_flag = false; 876 | static struct bsc_bury_info *g_bury_info = NULL; 877 | void bury_callback(bsc *svr, struct bsc_bury_info *info) 878 | { 879 | g_bury_info = info; 880 | bury_flag = true; 881 | } 882 | 883 | bool cmd_bury(bsc *svr, int job_id) 884 | { 885 | bsc_error = bsc_bury(svr, bury_callback, NULL, job_id, BSC_DEFAULT_PRORITY); 886 | 887 | if (bsc_error != BSC_ERROR_NONE) { 888 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 889 | return false; 890 | } 891 | 892 | FD_ZERO(&readset); 893 | FD_ZERO(&writeset); 894 | 895 | while (!bury_flag) 896 | { 897 | cmd_poll(svr, &readset, &writeset); 898 | } 899 | 900 | return true; 901 | } 902 | 903 | /* {{{ proto bool beanstalk_bury(object beanstalk, string tube, int job_id) 904 | */ 905 | PHP_FUNCTION(beanstalk_bury) 906 | { 907 | bsc_pool_t *pool; 908 | bsc * svr; 909 | char *tube; 910 | int tube_len; 911 | int job_id; 912 | zval *bsc_object = getThis(); 913 | 914 | if (bsc_object == NULL) { 915 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ols", &bsc_object, beanstalk_pool_ce, &job_id, &tube, &tube_len) == FAILURE) { 916 | return; 917 | } 918 | } 919 | else { 920 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &job_id, &tube, &tube_len) == FAILURE) { 921 | return; 922 | } 923 | } 924 | 925 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 926 | RETURN_FALSE; 927 | } 928 | 929 | RETVAL_NULL(); 930 | 931 | svr = bsc_pool_find(pool, tube, tube_len); 932 | if(!svr) 933 | { 934 | RETURN_FALSE; 935 | } 936 | 937 | if(cmd_bury(svr, job_id) && g_bury_info) { 938 | if(BSC_RES_BURIED == g_bury_info->response.code){ 939 | g_bury_info = NULL; 940 | bury_flag = false; 941 | RETURN_TRUE; 942 | } 943 | } 944 | 945 | RETURN_FALSE; 946 | } 947 | 948 | static int kick_flag = false; 949 | static struct bsc_kick_info *g_kick_info = NULL; 950 | void kick_callback(bsc *svr, struct bsc_kick_info *info) 951 | { 952 | g_kick_info = info; 953 | kick_flag = true; 954 | } 955 | 956 | bool cmd_kick(bsc *svr, int bound) 957 | { 958 | bsc_error = bsc_kick(svr, kick_callback, NULL, bound); 959 | 960 | if (bsc_error != BSC_ERROR_NONE) { 961 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 962 | return false; 963 | } 964 | 965 | FD_ZERO(&readset); 966 | FD_ZERO(&writeset); 967 | 968 | while (!kick_flag) 969 | { 970 | cmd_poll(svr, &readset, &writeset); 971 | } 972 | 973 | return true; 974 | } 975 | 976 | /* {{{ proto bool beanstalk_kick(object beanstalk, string tube, int bound) 977 | */ 978 | PHP_FUNCTION(beanstalk_kick) 979 | { 980 | bsc_pool_t *pool; 981 | bsc * svr; 982 | char *tube; 983 | int tube_len; 984 | int bound; 985 | zval *bsc_object = getThis(); 986 | 987 | if (bsc_object == NULL) { 988 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ols", &bsc_object, beanstalk_pool_ce, &bound, &tube, &tube_len) == FAILURE) { 989 | return; 990 | } 991 | } 992 | else { 993 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &bound, &tube, &tube_len) == FAILURE) { 994 | return; 995 | } 996 | } 997 | 998 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 999 | RETURN_FALSE; 1000 | } 1001 | 1002 | RETVAL_NULL(); 1003 | 1004 | svr = bsc_pool_find(pool, tube, tube_len); 1005 | if(!svr) 1006 | { 1007 | RETURN_FALSE; 1008 | } 1009 | 1010 | if(cmd_kick(svr, bound) && g_kick_info) { 1011 | if(BSC_KICK_RES_KICKED == g_kick_info->response.code){ 1012 | g_kick_info = NULL; 1013 | kick_flag = false; 1014 | RETURN_TRUE; 1015 | } 1016 | } 1017 | 1018 | RETURN_FALSE; 1019 | } 1020 | 1021 | static int dlt_flag = false; 1022 | static struct bsc_delete_info *g_dlt_info = NULL; 1023 | void dlt_callback(bsc *svr, struct bsc_delete_info *info) 1024 | { 1025 | g_dlt_info = info; 1026 | dlt_flag = true; 1027 | } 1028 | 1029 | bool cmd_delete(bsc *svr, int job_id) 1030 | { 1031 | bsc_error = bsc_delete(svr, dlt_callback, NULL, job_id); 1032 | 1033 | if (bsc_error != BSC_ERROR_NONE) { 1034 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 1035 | return false; 1036 | } 1037 | 1038 | FD_ZERO(&readset); 1039 | FD_ZERO(&writeset); 1040 | 1041 | while (!dlt_flag) 1042 | { 1043 | cmd_poll(svr, &readset, &writeset); 1044 | } 1045 | 1046 | return true; 1047 | } 1048 | 1049 | /* {{{ proto bool beanstalk_delete(object beanstalk, string tube, int job_id) 1050 | */ 1051 | PHP_FUNCTION(beanstalk_delete) 1052 | { 1053 | bsc_pool_t *pool; 1054 | bsc * svr; 1055 | char *tube; 1056 | int tube_len; 1057 | int job_id; 1058 | zval *bsc_object = getThis(); 1059 | 1060 | if (bsc_object == NULL) { 1061 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ols", &bsc_object, beanstalk_pool_ce, &job_id, &tube, &tube_len) == FAILURE) { 1062 | return; 1063 | } 1064 | } 1065 | else { 1066 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &job_id, &tube, &tube_len) == FAILURE) { 1067 | return; 1068 | } 1069 | } 1070 | 1071 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 1072 | RETURN_FALSE; 1073 | } 1074 | 1075 | RETVAL_NULL(); 1076 | 1077 | svr = bsc_pool_find(pool, tube, tube_len); 1078 | if(!svr) 1079 | { 1080 | RETURN_FALSE; 1081 | } 1082 | 1083 | if(cmd_delete(svr, job_id) && g_dlt_info){ 1084 | if(BSC_DELETE_RES_DELETED == g_dlt_info->response.code){ 1085 | g_dlt_info = NULL; 1086 | dlt_flag = false; 1087 | RETURN_TRUE; 1088 | } 1089 | } 1090 | 1091 | RETURN_FALSE; 1092 | } 1093 | 1094 | static int lst_flag = false; 1095 | static struct bsc_list_tubes_info *g_lst_info = NULL; 1096 | static char *lst_callback(bsc *svr, struct bsc_list_tubes_info *info) 1097 | { 1098 | g_lst_info = info; 1099 | lst_flag = true; 1100 | } 1101 | 1102 | bool cmd_list_tubes(bsc *svr) 1103 | { 1104 | bsc_error = bsc_list_tubes(svr, lst_callback, NULL); 1105 | 1106 | if (bsc_error != BSC_ERROR_NONE) { 1107 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error: got unknown error (%d)\n", bsc_error); 1108 | return false; 1109 | } 1110 | 1111 | FD_ZERO(&readset); 1112 | FD_ZERO(&writeset); 1113 | 1114 | while (!lst_flag) 1115 | { 1116 | cmd_poll(svr, &readset, &writeset); 1117 | } 1118 | 1119 | return true; 1120 | } 1121 | 1122 | /* {{{ proto bool beanstalk_list_tubes(object beanstalk) 1123 | */ 1124 | PHP_FUNCTION(beanstalk_list_tubes) 1125 | { 1126 | bsc_pool_t *pool; 1127 | bsc * svr; 1128 | char *tube; 1129 | int tube_len; 1130 | int i; 1131 | int j = 0; 1132 | char key[BSC_MAX_TUBE_NAME + 56]; 1133 | zval *bsc_object = getThis(); 1134 | 1135 | if (bsc_object == NULL) { 1136 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &bsc_object, beanstalk_pool_ce) == FAILURE) { 1137 | return; 1138 | } 1139 | } 1140 | 1141 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC) || !pool->num_servers) { 1142 | RETURN_FALSE; 1143 | } 1144 | 1145 | RETVAL_NULL(); 1146 | 1147 | array_init(return_value); 1148 | 1149 | for (i = 0; i < pool->num_servers; i++) 1150 | { 1151 | if(cmd_list_tubes(pool->servers[i]) && g_lst_info){ 1152 | while(g_lst_info->response.tubes[j][0] != '\0') 1153 | { 1154 | sprintf(key, "srv%d_%d", i, j); 1155 | add_assoc_string(return_value, key, g_lst_info->response.tubes[j], 1); 1156 | j++; 1157 | } 1158 | j = 0; 1159 | } 1160 | g_lst_info = NULL; 1161 | lst_flag = false; 1162 | } 1163 | } 1164 | 1165 | /* {{{ proto bool beanstalk_quit( object beanstalk ) 1166 | Closes connection to beanstalkd */ 1167 | PHP_FUNCTION(beanstalk_quit) 1168 | { 1169 | bsc_pool_t *pool; 1170 | zval *bsc_object = getThis(); 1171 | 1172 | if (bsc_object == NULL) { 1173 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &bsc_object, beanstalk_pool_ce) == FAILURE) { 1174 | return; 1175 | } 1176 | } 1177 | 1178 | if (!bsc_get_pool(bsc_object, &pool TSRMLS_CC)) { 1179 | RETURN_FALSE; 1180 | } 1181 | 1182 | bsc_pool_close(pool TSRMLS_CC); 1183 | RETURN_TRUE; 1184 | } 1185 | /* }}} */ 1186 | 1187 | /* 1188 | * Local variables: 1189 | * tab-width: 4 1190 | * c-basic-offset: 4 1191 | * End: 1192 | * vim600: noet sw=4 ts=4 fdm=marker 1193 | * vim<600: noet sw=4 ts=4 1194 | */ 1195 | 1196 | --------------------------------------------------------------------------------