Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a370382

Browse files
committed
Persistent connections pool
1 parent 8cd165d commit a370382

3 files changed

Lines changed: 109 additions & 23 deletions

File tree

common.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ zend_string_realloc(zend_string *s, size_t len, int persistent)
6868
return zstr;
6969
}
7070

71+
#define strpprintf zend_strpprintf
72+
73+
static zend_string *
74+
zend_strpprintf(size_t max_len, const char *format, ...)
75+
{
76+
va_list ap;
77+
zend_string *zstr;
78+
79+
va_start(ap, format);
80+
zstr = ecalloc(1, sizeof(*zstr));
81+
ZSTR_LEN(zstr) = vspprintf(&ZSTR_VAL(zstr), max_len, format, ap);
82+
zstr->gc = 0x11;
83+
va_end(ap);
84+
return zstr;
85+
}
86+
7187
#define zend_string_copy(s) zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), 0)
7288

7389
#define zend_string_equal_val(s1, s2) !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1))
@@ -140,6 +156,8 @@ zend_hash_str_find(const HashTable *ht, const char *key, size_t len)
140156
return NULL;
141157
}
142158

159+
#define zend_hash_find_ptr(ht, s) zend_hash_str_find_ptr(ht, ZSTR_VAL(s), ZSTR_LEN(s))
160+
143161
static zend_always_inline void *
144162
zend_hash_str_find_ptr(const HashTable *ht, const char *str, size_t len)
145163
{
@@ -151,10 +169,12 @@ zend_hash_str_find_ptr(const HashTable *ht, const char *str, size_t len)
151169
return NULL;
152170
}
153171

172+
#define zend_hash_str_update_ptr(ht, str, len, pData) zend_hash_str_update_mem(ht, str, len, pData, sizeof(void *))
173+
154174
static zend_always_inline void *
155-
zend_hash_str_update_ptr(HashTable *ht, const char *str, size_t len, void *pData)
175+
zend_hash_str_update_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
156176
{
157-
if (zend_hash_update(ht, str, len + 1, (void *)&pData, sizeof(void *), NULL) == SUCCESS) {
177+
if (zend_hash_update(ht, str, len + 1, (void *)&pData, size, NULL) == SUCCESS) {
158178
return pData;
159179
}
160180
return NULL;

library.c

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
extern zend_class_entry *redis_ce;
6262
extern zend_class_entry *redis_exception_ce;
6363

64+
extern int le_redis_pconnect;
65+
6466
/* Helper to reselect the proper DB number when we reconnect */
6567
static int reselect_db(RedisSock *redis_sock TSRMLS_DC) {
6668
char *cmd, *response;
@@ -1743,10 +1745,10 @@ redis_sock_create(char *host, int host_len, unsigned short port,
17431745
PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC)
17441746
{
17451747
struct timeval tv, read_tv, *tv_ptr = NULL;
1746-
char host[1024], *persistent_id = NULL;
1748+
zend_string *persistent_id = NULL;
1749+
char host[1024];
17471750
const char *fmtstr = "%s:%d";
17481751
int host_len, usocket = 0, err = 0;
1749-
php_netstream_data_t *sock;
17501752
int tcp_flag = 1;
17511753
#if (PHP_MAJOR_VERSION < 7)
17521754
char *estr = NULL;
@@ -1758,15 +1760,6 @@ PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC)
17581760
redis_sock_disconnect(redis_sock, 0 TSRMLS_CC);
17591761
}
17601762

1761-
tv.tv_sec = (time_t)redis_sock->timeout;
1762-
tv.tv_usec = (int)((redis_sock->timeout - tv.tv_sec) * 1000000);
1763-
if(tv.tv_sec != 0 || tv.tv_usec != 0) {
1764-
tv_ptr = &tv;
1765-
}
1766-
1767-
read_tv.tv_sec = (time_t)redis_sock->read_timeout;
1768-
read_tv.tv_usec = (int)((redis_sock->read_timeout-read_tv.tv_sec)*1000000);
1769-
17701763
if (ZSTR_VAL(redis_sock->host)[0] == '/' && redis_sock->port < 1) {
17711764
host_len = snprintf(host, sizeof(host), "unix://%s", ZSTR_VAL(redis_sock->host));
17721765
usocket = 1;
@@ -1785,21 +1778,46 @@ PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC)
17851778
}
17861779

17871780
if (redis_sock->persistent) {
1788-
if (redis_sock->persistent_id) {
1789-
spprintf(&persistent_id, 0, "phpredis:%s:%s", host,
1790-
ZSTR_VAL(redis_sock->persistent_id));
1781+
if (INI_INT("redis.pconnect.pooling_enabled")) {
1782+
persistent_id = strpprintf(0, "phpredis_%s:%d", ZSTR_VAL(redis_sock->host), redis_sock->port);
1783+
zend_resource *le = zend_hash_find_ptr(&EG(persistent_list), persistent_id);
1784+
if (le && zend_llist_count(le->ptr) > 0) {
1785+
redis_sock->stream = *(php_stream **)zend_llist_get_last(le->ptr);
1786+
zend_llist_remove_tail(le->ptr);
1787+
/* Check socket liveness using 0 second timeout */
1788+
if (php_stream_set_option(redis_sock->stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL) == PHP_STREAM_OPTION_RETURN_OK) {
1789+
redis_sock->status = REDIS_SOCK_STATUS_CONNECTED;
1790+
zend_string_release(persistent_id);
1791+
return SUCCESS;
1792+
}
1793+
php_stream_pclose(redis_sock->stream);
1794+
}
1795+
zend_string_release(persistent_id);
1796+
1797+
gettimeofday(&tv, NULL);
1798+
persistent_id = strpprintf(0, "phpredis_%d%d", tv.tv_sec, tv.tv_usec);
17911799
} else {
1792-
spprintf(&persistent_id, 0, "phpredis:%s:%f", host,
1793-
redis_sock->timeout);
1800+
if (redis_sock->persistent_id) {
1801+
persistent_id = strpprintf(0, "phpredis:%s:%s", host, ZSTR_VAL(redis_sock->persistent_id));
1802+
} else {
1803+
persistent_id = strpprintf(0, "phpredis:%s:%f", host, redis_sock->timeout);
1804+
}
17941805
}
17951806
}
17961807

1808+
tv.tv_sec = (time_t)redis_sock->timeout;
1809+
tv.tv_usec = (int)((redis_sock->timeout - tv.tv_sec) * 1000000);
1810+
if (tv.tv_sec != 0 || tv.tv_usec != 0) {
1811+
tv_ptr = &tv;
1812+
}
1813+
17971814
redis_sock->stream = php_stream_xport_create(host, host_len,
17981815
0, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
1799-
persistent_id, tv_ptr, NULL, &estr, &err);
1816+
persistent_id ? ZSTR_VAL(persistent_id) : NULL,
1817+
tv_ptr, NULL, &estr, &err);
18001818

18011819
if (persistent_id) {
1802-
efree(persistent_id);
1820+
zend_string_release(persistent_id);
18031821
}
18041822

18051823
if (!redis_sock->stream) {
@@ -1812,12 +1830,12 @@ PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC)
18121830
zend_string_release(estr);
18131831
#endif
18141832
}
1815-
return -1;
1833+
return FAILURE;
18161834
}
18171835

18181836
/* Attempt to set TCP_NODELAY/TCP_KEEPALIVE if we're not using a unix socket. */
1819-
sock = (php_netstream_data_t*)redis_sock->stream->abstract;
18201837
if (!usocket) {
1838+
php_netstream_data_t *sock = (php_netstream_data_t*)redis_sock->stream->abstract;
18211839
err = setsockopt(sock->socket, IPPROTO_TCP, TCP_NODELAY, (char*) &tcp_flag, sizeof(tcp_flag));
18221840
PHPREDIS_NOTUSED(err);
18231841
err = setsockopt(sock->socket, SOL_SOCKET, SO_KEEPALIVE, (char*) &redis_sock->tcp_keepalive, sizeof(redis_sock->tcp_keepalive));
@@ -1826,6 +1844,9 @@ PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC)
18261844

18271845
php_stream_auto_cleanup(redis_sock->stream);
18281846

1847+
read_tv.tv_sec = (time_t)redis_sock->read_timeout;
1848+
read_tv.tv_usec = (int)((redis_sock->read_timeout - read_tv.tv_sec) * 1000000);
1849+
18291850
if (read_tv.tv_sec != 0 || read_tv.tv_usec != 0) {
18301851
php_stream_set_option(redis_sock->stream,PHP_STREAM_OPTION_READ_TIMEOUT,
18311852
0, &read_tv);
@@ -1835,7 +1856,7 @@ PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC)
18351856

18361857
redis_sock->status = REDIS_SOCK_STATUS_CONNECTED;
18371858

1838-
return 0;
1859+
return SUCCESS;
18391860
}
18401861

18411862
/**
@@ -1869,6 +1890,23 @@ redis_sock_disconnect(RedisSock *redis_sock, int force TSRMLS_DC)
18691890
if (redis_sock->persistent) {
18701891
if (force) {
18711892
php_stream_pclose(redis_sock->stream);
1893+
} else if (INI_INT("redis.pconnect.pooling_enabled")) {
1894+
zend_string *persistent_id = strpprintf(0, "phpredis_%s:%d", ZSTR_VAL(redis_sock->host), redis_sock->port);
1895+
zend_resource *le = zend_hash_find_ptr(&EG(persistent_list), persistent_id);
1896+
if (!le) {
1897+
#if (PHP_MAJOR_VERSION < 7)
1898+
le = ecalloc(1, sizeof(*le));
1899+
#else
1900+
zend_resource res;
1901+
le = &res;
1902+
#endif
1903+
le->type = le_redis_pconnect;
1904+
le->ptr = pecalloc(1, sizeof(zend_llist), 1);
1905+
zend_llist_init(le->ptr, sizeof(void *), NULL, 1);
1906+
zend_hash_str_update_mem(&EG(persistent_list), ZSTR_VAL(persistent_id), ZSTR_LEN(persistent_id), le, sizeof(*le));
1907+
}
1908+
zend_llist_prepend_element(le->ptr, &redis_sock->stream);
1909+
zend_string_release(persistent_id);
18721910
}
18731911
} else {
18741912
php_stream_close(redis_sock->stream);

redis.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ zend_class_entry *redis_exception_ce;
5353
extern zend_function_entry redis_array_functions[];
5454
extern zend_function_entry redis_cluster_functions[];
5555

56+
int le_redis_pconnect;
57+
5658
PHP_INI_BEGIN()
5759
/* redis arrays */
5860
PHP_INI_ENTRY("redis.arrays.algorithm", "", PHP_INI_ALL, NULL)
@@ -77,6 +79,9 @@ PHP_INI_BEGIN()
7779
PHP_INI_ENTRY("redis.clusters.seeds", "", PHP_INI_ALL, NULL)
7880
PHP_INI_ENTRY("redis.clusters.timeout", "0", PHP_INI_ALL, NULL)
7981

82+
/* redis pconnect */
83+
PHP_INI_ENTRY("redis.pconnect.pooling_enabled", "0", PHP_INI_ALL, NULL)
84+
8085
/* redis session */
8186
PHP_INI_ENTRY("redis.session.locking_enabled", "0", PHP_INI_ALL, NULL)
8287
PHP_INI_ENTRY("redis.session.lock_expire", "0", PHP_INI_ALL, NULL)
@@ -742,6 +747,25 @@ static void add_class_constants(zend_class_entry *ce, int is_cluster TSRMLS_DC)
742747
zend_declare_class_constant_stringl(ce, "BEFORE", 6, "before", 6 TSRMLS_CC);
743748
}
744749

750+
static void
751+
redis_pconnect_dtor(void *ptr TSRMLS_DC)
752+
{
753+
php_stream_pclose(*(php_stream **)ptr);
754+
}
755+
756+
static ZEND_RSRC_DTOR_FUNC(redis_connections_pool_dtor)
757+
{
758+
#if (PHP_MAJOR_VERSION < 7)
759+
zend_resource *res = rsrc;
760+
#endif
761+
762+
if (res->ptr) {
763+
zend_llist_apply(res->ptr, redis_pconnect_dtor TSRMLS_CC);
764+
zend_llist_destroy(res->ptr);
765+
pefree(res->ptr, 1);
766+
}
767+
}
768+
745769
/**
746770
* PHP_MINIT_FUNCTION
747771
*/
@@ -823,6 +847,10 @@ PHP_MINIT_FUNCTION(redis)
823847
php_session_register_module(&ps_mod_redis_cluster);
824848
#endif
825849

850+
/* Register resource destructors */
851+
le_redis_pconnect = zend_register_list_destructors_ex(NULL, redis_connections_pool_dtor,
852+
"phpredis persistent connections pool", module_number);
853+
826854
return SUCCESS;
827855
}
828856

0 commit comments

Comments
 (0)