6161extern zend_class_entry * redis_ce ;
6262extern 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 */
6567static 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,
17431745PHP_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 );
0 commit comments