Step 1. Build the test code
Step 2. Start MySQL/Mariadb server
Step 3. Execute the test binary (in terminal or valgrind), and it would keep printing "Query OK"..
Step 4. Shut down MySQL/Mariadb server. And the client would keep printing "Query error..."
Step 5. Watch the memory usage of the test binary, and it would keep raising.
After debugging for a while, I thought the bug locates in function "mysql_reconnect" in file "libmariadb.c" around line 1992.
The original logic is to let a tmp_client to rebuild a new connection which has to allocate some structures such as hash_table for keeping the mysql_options. But when it fails to reconnect, the destructor "mysql_close" should be called in order to free the allocated memory. And it seems someone has fogot this point.
So after line 1992: my_set_error(mysql,..... )
I added this line as a test patch:
mysql_close(&tmp_mysql);
And it seems to work well without memory leak any more.
But I'm not 100% sure of it and looking forward for your response.
As you said, I've tried the same test code with the c client library from MySQL-5.6.20 and didn't find any leak. The memory usage looks quite normal.
Tianhong
added a comment - Hi Georg,
Thanks for your reply.
As you said, I've tried the same test code with the c client library from MySQL-5.6.20 and didn't find any leak. The memory usage looks quite normal.
Today I reviewed the code and thought that there are also a few bugs in function "mysql_reconnect"
The problems are:
1. original options would get lost if reconnecting fails, because of the bzero() before mysql_real_connect()
2. The free_me flag in original mysql object is set to 0, which would lead to memory leak. You should store the old value and set it back after the cloning from tmp_mysql object.
I wrote the patch with some comment.
Please do a code review if you have time.
static my_bool mysql_reconnect(MYSQL *mysql)
{
MYSQL tmp_mysql;
//--Origial free_me flag in mysql object
my_bool free_me;
LIST *li_stmt= mysql->stmts;
DBUG_ENTER("mysql_reconnect");
if (!mysql->reconnect ||
(mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
{
/* Allov reconnect next time */
mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
/* make sure that we reconnect with the same character set */
if (!tmp_mysql.options.charset_name ||
strcmp(tmp_mysql.options.charset_name, mysql->charset->csname))
tmp_mysql.reconnect= mysql->reconnect;
//--------BUG----------------------------
//-We have to keep the original options--
//-So don't set the options to zero here-
//bzero((char*) &mysql->options,sizeof(mysql->options));
if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
{
my_set_error(mysql, tmp_mysql.net.last_errno,
tmp_mysql.net.sqlstate,
tmp_mysql.net.last_error);
//--If it fails, just destroy the tmp_mysql.
//--But don't delete the options in tmp_mysql
//--, because the options are shared between mysql and tmp_mysql
//--The options need to be reused next time.
//--Set the options in tmp_mysql to NULL, in order to guard
//--the original pointers of options in mysql object.
bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options));
mysql_close(&tmp_mysql);
DBUG_RETURN(1);
}
/* reset the connection in all active statements
todo: check stmt->mysql in mysql_stmt* functions ! */
for (;li_stmt;li_stmt= li_stmt->next)
{
MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
//-------------BUG----------------
//We also have to keep the origial free_me flag
//The flag needs to be set back after cloning.
free_me = mysql->free_me;
mysql->free_me=0;
mysql->stmts= NULL;
//----BUG-------------------------
//--The options should be set to NULL before mysql_close()
//--Otherwise, the options would be deleted in mysql_close()
memset(&mysql->options, 0, sizeof(mysql->options));
mysql_close(mysql);
//memset(&mysql->options, 0, sizeof(mysql->options));
*mysql=tmp_mysql;
//--Now, set the original free_me flag back.
mysql->free_me = free_me;
mysql->reconnect= 1;
net_clear(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0;
DBUG_RETURN(0);
}
Tianhong
added a comment - Hi Georg,
thanks for your work and support.
Today I reviewed the code and thought that there are also a few bugs in function "mysql_reconnect"
The problems are:
1. original options would get lost if reconnecting fails, because of the bzero() before mysql_real_connect()
2. The free_me flag in original mysql object is set to 0, which would lead to memory leak. You should store the old value and set it back after the cloning from tmp_mysql object.
I wrote the patch with some comment.
Please do a code review if you have time.
static my_bool mysql_reconnect(MYSQL *mysql)
{
MYSQL tmp_mysql;
//--Origial free_me flag in mysql object
my_bool free_me;
LIST *li_stmt= mysql->stmts;
DBUG_ENTER("mysql_reconnect");
if (!mysql->reconnect ||
(mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
{
/* Allov reconnect next time */
mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
mysql_init(&tmp_mysql);
tmp_mysql.options=mysql->options;
/* don't reread options from configuration files */
tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL;
/* make sure that we reconnect with the same character set */
if (!tmp_mysql.options.charset_name ||
strcmp(tmp_mysql.options.charset_name, mysql->charset->csname))
{
my_free(tmp_mysql.options.charset_name, MYF(MY_ALLOW_ZERO_PTR));
tmp_mysql.options.charset_name= my_strdup(mysql->charset->csname, MYF(MY_WME));
}
tmp_mysql.reconnect= mysql->reconnect;
//-------- BUG ----------------------------
//- We have to keep the original options --
//- So don't set the options to zero here -
//bzero((char*) &mysql->options,sizeof(mysql->options));
if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
{
my_set_error(mysql, tmp_mysql.net.last_errno,
tmp_mysql.net.sqlstate,
tmp_mysql.net.last_error);
//--If it fails, just destroy the tmp_mysql.
//--But don't delete the options in tmp_mysql
//--, because the options are shared between mysql and tmp_mysql
//--The options need to be reused next time.
//--Set the options in tmp_mysql to NULL, in order to guard
//--the original pointers of options in mysql object.
bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options));
mysql_close(&tmp_mysql);
DBUG_RETURN(1);
}
/* reset the connection in all active statements
todo: check stmt->mysql in mysql_stmt* functions ! */
for (;li_stmt;li_stmt= li_stmt->next)
{
MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
if (stmt->state != MYSQL_STMT_INITTED)
{
stmt->mysql= NULL;
stmt->state= MYSQL_STMT_INITTED;
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
}
else
tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list);
}
//------------- BUG ----------------
//We also have to keep the origial free_me flag
//The flag needs to be set back after cloning.
free_me = mysql->free_me;
mysql->free_me=0;
mysql->stmts= NULL;
//---- BUG -------------------------
//--The options should be set to NULL before mysql_close()
//--Otherwise, the options would be deleted in mysql_close()
memset(&mysql->options, 0, sizeof(mysql->options));
mysql_close(mysql);
//memset(&mysql->options, 0, sizeof(mysql->options));
*mysql=tmp_mysql;
//--Now, set the original free_me flag back.
mysql->free_me = free_me;
mysql->reconnect= 1;
net_clear(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0;
DBUG_RETURN(0);
}
People
Georg Richter
Tianhong
Votes:
0Vote for this issue
Watchers:
2Start watching this issue
Dates
Created:
Updated:
Resolved:
Git Integration
Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.
{"report":{"fcp":883.0999999046326,"ttfb":240,"pageVisibility":"visible","entityId":49444,"key":"jira.project.issue.view-issue","isInitial":true,"threshold":1000,"elementTimings":{},"userDeviceMemory":8,"userDeviceProcessors":64,"apdex":1,"journeyId":"aff4f3c5-eb4f-4d90-9999-c48e7f7b110d","navigationType":0,"readyForUser":967.5999999046326,"redirectCount":0,"resourceLoadedEnd":624.2999999523163,"resourceLoadedStart":247.70000004768372,"resourceTiming":[{"duration":6.799999952316284,"initiatorType":"link","name":"https://jira.mariadb.org/s/2c21342762a6a02add1c328bed317ffd-CDN/lu2bu7/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/css/_super/batch.css","startTime":247.70000004768372,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":247.70000004768372,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":254.5,"responseStart":0,"secureConnectionStart":0},{"duration":8.199999809265137,"initiatorType":"link","name":"https://jira.mariadb.org/s/7ebd35e77e471bc30ff0eba799ebc151-CDN/lu2bu7/820016/12ta74/8679b4946efa1a0bb029a3a22206fb5d/_/download/contextbatch/css/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.css?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&slack-enabled=true","startTime":247.90000009536743,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":247.90000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":256.09999990463257,"responseStart":0,"secureConnectionStart":0},{"duration":208.59999990463257,"initiatorType":"script","name":"https://jira.mariadb.org/s/fbf975c0cce4b1abf04784eeae9ba1f4-CDN/lu2bu7/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/js/_super/batch.js?locale=en","startTime":248,"connectEnd":248,"connectStart":248,"domainLookupEnd":248,"domainLookupStart":248,"fetchStart":248,"redirectEnd":0,"redirectStart":0,"requestStart":259.2999999523163,"responseEnd":456.59999990463257,"responseStart":280.59999990463257,"secureConnectionStart":248},{"duration":376.2000000476837,"initiatorType":"script","name":"https://jira.mariadb.org/s/099b33461394b8015fc36c0a4b96e19f-CDN/lu2bu7/820016/12ta74/8679b4946efa1a0bb029a3a22206fb5d/_/download/contextbatch/js/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&locale=en&slack-enabled=true","startTime":248.09999990463257,"connectEnd":248.09999990463257,"connectStart":248.09999990463257,"domainLookupEnd":248.09999990463257,"domainLookupStart":248.09999990463257,"fetchStart":248.09999990463257,"redirectEnd":0,"redirectStart":0,"requestStart":263.2999999523163,"responseEnd":624.2999999523163,"responseStart":282.40000009536743,"secureConnectionStart":248.09999990463257},{"duration":44.09999990463257,"initiatorType":"script","name":"https://jira.mariadb.org/s/94c15bff32baef80f4096a08aceae8bc-CDN/lu2bu7/820016/12ta74/c92c0caa9a024ae85b0ebdbed7fb4bd7/_/download/contextbatch/js/atl.global,-_super/batch.js?locale=en","startTime":248.20000004768372,"connectEnd":248.20000004768372,"connectStart":248.20000004768372,"domainLookupEnd":248.20000004768372,"domainLookupStart":248.20000004768372,"fetchStart":248.20000004768372,"redirectEnd":0,"redirectStart":0,"requestStart":263.7999999523163,"responseEnd":292.2999999523163,"responseStart":286.09999990463257,"secureConnectionStart":248.20000004768372},{"duration":41,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bu7/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-en/jira.webresources:calendar-en.js","startTime":248.29999995231628,"connectEnd":248.29999995231628,"connectStart":248.29999995231628,"domainLookupEnd":248.29999995231628,"domainLookupStart":248.29999995231628,"fetchStart":248.29999995231628,"redirectEnd":0,"redirectStart":0,"requestStart":264.09999990463257,"responseEnd":289.2999999523163,"responseStart":285.09999990463257,"secureConnectionStart":248.29999995231628},{"duration":47,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bu7/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-localisation-moment/jira.webresources:calendar-localisation-moment.js","startTime":248.40000009536743,"connectEnd":248.40000009536743,"connectStart":248.40000009536743,"domainLookupEnd":248.40000009536743,"domainLookupStart":248.40000009536743,"fetchStart":248.40000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":265.40000009536743,"responseEnd":295.40000009536743,"responseStart":289.5,"secureConnectionStart":248.40000009536743},{"duration":11.400000095367432,"initiatorType":"link","name":"https://jira.mariadb.org/s/b04b06a02d1959df322d9cded3aeecc1-CDN/lu2bu7/820016/12ta74/a2ff6aa845ffc9a1d22fe23d9ee791fc/_/download/contextbatch/css/jira.global.look-and-feel,-_super/batch.css","startTime":248.5,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":248.5,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":259.90000009536743,"responseStart":0,"secureConnectionStart":0},{"duration":76.70000004768372,"initiatorType":"script","name":"https://jira.mariadb.org/rest/api/1.0/shortcuts/820016/47140b6e0a9bc2e4913da06536125810/shortcuts.js?context=issuenavigation&context=issueaction","startTime":248.59999990463257,"connectEnd":248.59999990463257,"connectStart":248.59999990463257,"domainLookupEnd":248.59999990463257,"domainLookupStart":248.59999990463257,"fetchStart":248.59999990463257,"redirectEnd":0,"redirectStart":0,"requestStart":266,"responseEnd":325.2999999523163,"responseStart":323.2999999523163,"secureConnectionStart":248.59999990463257},{"duration":13.799999952316284,"initiatorType":"link","name":"https://jira.mariadb.org/s/3ac36323ba5e4eb0af2aa7ac7211b4bb-CDN/lu2bu7/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/css/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.css?jira.create.linked.issue=true","startTime":248.70000004768372,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":248.70000004768372,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":262.5,"responseStart":0,"secureConnectionStart":0},{"duration":47.299999952316284,"initiatorType":"script","name":"https://jira.mariadb.org/s/3339d87fa2538a859872f2df449bf8d0-CDN/lu2bu7/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/js/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.js?jira.create.linked.issue=true&locale=en","startTime":248.79999995231628,"connectEnd":248.79999995231628,"connectStart":248.79999995231628,"domainLookupEnd":248.79999995231628,"domainLookupStart":248.79999995231628,"fetchStart":248.79999995231628,"redirectEnd":0,"redirectStart":0,"requestStart":266.2000000476837,"responseEnd":296.09999990463257,"responseStart":290.40000009536743,"secureConnectionStart":248.79999995231628},{"duration":307.2000000476837,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bu7/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-js/jira.webresources:bigpipe-js.js","startTime":256.09999990463257,"connectEnd":256.09999990463257,"connectStart":256.09999990463257,"domainLookupEnd":256.09999990463257,"domainLookupStart":256.09999990463257,"fetchStart":256.09999990463257,"redirectEnd":0,"redirectStart":0,"requestStart":294.2999999523163,"responseEnd":563.2999999523163,"responseStart":556.4000000953674,"secureConnectionStart":256.09999990463257},{"duration":307.2999999523163,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bu7/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-init/jira.webresources:bigpipe-init.js","startTime":256.2999999523163,"connectEnd":256.2999999523163,"connectStart":256.2999999523163,"domainLookupEnd":256.2999999523163,"domainLookupStart":256.2999999523163,"fetchStart":256.2999999523163,"redirectEnd":0,"redirectStart":0,"requestStart":294.40000009536743,"responseEnd":563.5999999046326,"responseStart":557.0999999046326,"secureConnectionStart":256.2999999523163},{"duration":133,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":599.9000000953674,"connectEnd":599.9000000953674,"connectStart":599.9000000953674,"domainLookupEnd":599.9000000953674,"domainLookupStart":599.9000000953674,"fetchStart":599.9000000953674,"redirectEnd":0,"redirectStart":0,"requestStart":703.7999999523163,"responseEnd":732.9000000953674,"responseStart":732.2000000476837,"secureConnectionStart":599.9000000953674},{"duration":82.89999985694885,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":840.7000000476837,"connectEnd":840.7000000476837,"connectStart":840.7000000476837,"domainLookupEnd":840.7000000476837,"domainLookupStart":840.7000000476837,"fetchStart":840.7000000476837,"redirectEnd":0,"redirectStart":0,"requestStart":896.4000000953674,"responseEnd":923.5999999046326,"responseStart":922.7000000476837,"secureConnectionStart":840.7000000476837},{"duration":135.60000014305115,"initiatorType":"script","name":"https://www.google-analytics.com/analytics.js","startTime":876.5999999046326,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":876.5999999046326,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":1012.2000000476837,"responseStart":0,"secureConnectionStart":0}],"fetchStart":0,"domainLookupStart":0,"domainLookupEnd":0,"connectStart":0,"connectEnd":0,"requestStart":29,"responseStart":240,"responseEnd":258,"domLoading":244,"domInteractive":1069,"domContentLoadedEventStart":1069,"domContentLoadedEventEnd":1118,"domComplete":1220,"loadEventStart":1220,"loadEventEnd":1220,"userAgent":"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)","marks":[{"name":"bigPipe.sidebar-id.start","time":1045.5999999046326},{"name":"bigPipe.sidebar-id.end","time":1046.2999999523163},{"name":"bigPipe.activity-panel-pipe-id.start","time":1046.4000000953674},{"name":"bigPipe.activity-panel-pipe-id.end","time":1048.0999999046326},{"name":"activityTabFullyLoaded","time":1136.9000000953674}],"measures":[],"correlationId":"eb536af6655568","effectiveType":"4g","downlink":10,"rtt":0,"serverDuration":83,"dbReadsTimeInMs":9,"dbConnsTimeInMs":15,"applicationHash":"9d11dbea5f4be3d4cc21f03a88dd11d8c8687422","experiments":[]}}
Thanks for your bug report. Verified - the leak also exists in servers (GPL licensed) client library.