Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:4477 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 39044 invoked by uid 1010); 14 Sep 2003 16:49:43 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 39020 invoked by uid 1007); 14 Sep 2003 16:49:43 -0000 Message-ID: <20030914164943.39019.qmail@pb1.pair.com> To: internals@lists.php.net Date: Sun, 14 Sep 2003 19:49:43 +0300 Lines: 243 User-Agent: KNode/0.7.6 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart1447792.FHmVHyALIp" Content-Transfer-Encoding: 7Bit X-Posted-By: 212.47.207.38 Subject: PATCH: new_link parameter to mysql_pconnect() From: lenar@city.ee (Lenar =?ISO-8859-1?Q?L=F5hmus?=) --nextPart1447792.FHmVHyALIp Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8Bit Hi, I'v implemented new_link paramater (as in mysql_connect) for mysql_pconnect(). Since client_flags were added to those functions in 4.3.x the parameter is 4th in mysql_connect() and 5th in mysql_pconnect(). When new_link is true when connecting to mysql database with mysql_pconnect() two things happen: 1) you always get unique connection to database (no matter what hostname, username or password you supplied. When connecting the code will check if there is an idle connection to server and when found that connection will be reused. When no connection found, new connection will be created and registered for future use within same child(/thread?). 2) when new_link is true, mysql_pconnect won't waste your connections to mysql servers like it has been doing up to day. This is achieved by using mysql_change_user() API call which is available starting from MySQL 3.23.3. This patch should be great news for people with many virtual servers and different mysql usernames/password for each user using their service. --- With this patch and new_link 'true' connection usage to one server will be maximum of [Apache MaxClients conf option]*[different mysql hostname/port combinations] That means when MaxClients=50 and max_persistent=1 you will get no more that 50 real connection hovering around to same mysql server. --- Without this patch it is (or new_link 'false'): [Apache MaxClients conf option]*[different mysql hostname/port/username password combinations] This means that when MaxClients=50 and max_persistent=1 and have 50 clients using mysql_pconnect() you could have maximum of 2500!!! connections to one server. In reality it is not as bad but not good either. -- So I think this should patch would be nice to have included in future PHP releases. I'm not sure I made good/correct/effective use of PHP/Zend internal functions. I hope so. If not please point out what's wrong and I'll try to fix. Oh, this patch is against PHP4.3.3. Go to ext/mysql dir and 'patch -p1'. Lenar --nextPart1447792.FHmVHyALIp Content-Type: text/x-diff; name="mysql_pconnect_newlink.patch" Content-Transfer-Encoding: 8Bit Content-Disposition: attachment; filename="mysql_pconnect_newlink.patch" Common subdirectories: old/libmysql and new/libmysql diff -ub old/php_mysql.c new/php_mysql.c --- old/php_mysql.c 2003-08-08 16:36:44.000000000 +0300 +++ new/php_mysql.c 2003-09-14 19:40:40.000000000 +0300 @@ -90,6 +90,10 @@ #define MYSQL_HAS_YEAR #endif +#if MYSQL_VERSION_ID >= 32303 +#define MYSQL_HAS_CHANGE_USER +#endif + #define MYSQL_ASSOC 1<<0 #define MYSQL_NUM 1<<1 #define MYSQL_BOTH (MYSQL_ASSOC|MYSQL_NUM) @@ -420,6 +424,10 @@ */ PHP_RINIT_FUNCTION(mysql) { +#ifdef MYSQL_HAS_CHANGE_USER + ALLOC_HASHTABLE(MySG(inuse_list)); + zend_hash_init(MySG(inuse_list), 1, NULL, NULL, 0); +#endif MySG(default_link)=-1; MySG(num_links) = MySG(num_persistent); /* Reset connect error/errno on every request */ @@ -442,10 +450,13 @@ php_error_docref("function.mysql-free-result" TSRMLS_CC, E_WARNING, tmp); } } - if (MySG(connect_error)!=NULL) { efree(MySG(connect_error)); } +#ifdef MYSQL_HAS_CHANGE_USER + zend_hash_destroy(MySG(inuse_list)); + FREE_HASHTABLE(MySG(inuse_list)); +#endif return SUCCESS; } /* }}} */ @@ -501,6 +512,7 @@ zval **z_host=NULL, **z_user=NULL, **z_passwd=NULL, **z_new_link=NULL, **z_client_flags=NULL; zend_bool free_host=0, new_link=0; long connect_timeout; + list_entry *inuse_le=NULL; connect_timeout = MySG(connect_timeout); @@ -513,9 +525,6 @@ } host_and_port=passwd=NULL; user=php_get_current_user(); - hashed_details_length = strlen(user)+5+3; - hashed_details = (char *) emalloc(hashed_details_length+1); - sprintf(hashed_details, "mysql__%s_", user); client_flags = CLIENT_INTERACTIVE; } else { host_and_port = MySG(default_host); @@ -575,9 +584,16 @@ } break; case 5: { + if (persistent) { + if (zend_get_parameters_ex(5, &z_host, &z_user, &z_passwd, &z_client_flags, &z_new_link) == FAILURE) { + MYSQL_DO_CONNECT_RETURN_FALSE(); + } + } + else { if (zend_get_parameters_ex(5, &z_host, &z_user, &z_passwd, &z_new_link, &z_client_flags) == FAILURE) { MYSQL_DO_CONNECT_RETURN_FALSE(); } + } convert_to_string_ex(z_user); convert_to_string_ex(z_passwd); convert_to_boolean_ex(z_new_link); @@ -610,11 +626,36 @@ } } } + } + if (!MySG(allow_persistent)) { + persistent=0; + } + +#ifdef MYSQL_HAS_CHANGE_USER + if (!(new_link && persistent)) { +#endif + if (PG(sql_safe_mode)) { + hashed_details_length = strlen(user)+5+3; + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details, "mysql__%s_", user); + } else { hashed_details_length = sizeof("mysql___")-1 + strlen(SAFE_STRING(host_and_port))+strlen(SAFE_STRING(user))+strlen(SAFE_STRING(passwd)); hashed_details = (char *) emalloc(hashed_details_length+1); sprintf(hashed_details, "mysql_%s_%s_%s", SAFE_STRING(host_and_port), SAFE_STRING(user), SAFE_STRING(passwd)); } +#ifdef MYSQL_HAS_CHANGE_USER + } else { + long count = 0; + + if(zend_hash_find(MySG(inuse_list), SAFE_STRING(host_and_port), strlen(SAFE_STRING(host_and_port))+1, (void **) &inuse_le)==SUCCESS) { + count = (long) inuse_le->ptr; + } + hashed_details_length = sizeof("mysqlp__")-1 + strlen(SAFE_STRING(host_and_port)) + 10; + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details, "mysqlp_%s_%ld", SAFE_STRING(host_and_port), count); + } +#endif /* We cannot use mysql_port anymore in windows, need to use * mysql_real_connect() to set the port. @@ -641,9 +682,6 @@ mysql_port = port; #endif - if (!MySG(allow_persistent)) { - persistent=0; - } if (persistent) { list_entry *le; @@ -694,10 +732,27 @@ efree(hashed_details); MYSQL_DO_CONNECT_RETURN_FALSE(); } +#ifdef MYSQL_CHANGE_USER + if(new_link) { + if(inuse_le) { /* increase in use count for this host_and_port */ + ((long)inuse_le->ptr)++; + } else { + list_entry new_inuse_le; + + ((long) new_inuse_le.ptr) = 1; /* in use count */ + if (zend_hash_update(MySG(inuse_list), SAFE_STRING(host_and_port), strlen(SAFE_STRING(host_and_port))+1, (void *) &new_inuse_le, sizeof(list_entry), NULL)==FAILURE) { + free(mysql); + efree(hashed_details); + MYSQL_DO_CONNECT_RETURN_FALSE(); + } + } + } +#endif MySG(num_persistent)++; MySG(num_links)++; } else { /* The link is in our list of persistent connections */ if (Z_TYPE_P(le) != le_plink) { + efree(hashed_details); MYSQL_DO_CONNECT_RETURN_FALSE(); } /* ensure that the link did not die */ @@ -724,6 +779,19 @@ MYSQL_DO_CONNECT_RETURN_FALSE(); } } +#ifdef MYSQL_HAS_CHANGE_USER + else { + if(new_link && mysql_change_user(le->ptr, user, passwd, NULL)) { + if (MySG(connect_error)!=NULL) efree(MySG(connect_error)); + MySG(connect_error)=estrdup(mysql_error(&((php_mysql_conn *)le->ptr)->conn)); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", MySG(connect_error)); + MySG(connect_errno)=mysql_errno(&((php_mysql_conn *)le->ptr)->conn); + efree(hashed_details); + MYSQL_DO_CONNECT_RETURN_FALSE(); + } + } +#endif + #if MYSQL_VERSION_ID < 32231 signal(SIGPIPE, handler); #endif diff -ub old/php_mysql.h new/php_mysql.h --- old/php_mysql.h 2002-12-31 18:35:00.000000000 +0200 +++ new/php_mysql.h 2003-09-14 19:11:49.000000000 +0300 @@ -105,6 +105,7 @@ long connect_timeout; long result_allocated; long trace_mode; + HashTable *inuse_list; ZEND_END_MODULE_GLOBALS(mysql) #ifdef ZTS --nextPart1447792.FHmVHyALIp--