Skip to content

Commit

Permalink
Merge pull request #7509 from Habbie/4.1.x-mysqlthreadcloser
Browse files Browse the repository at this point in the history
plug mysql_thread_init memory leak, fixes #6231
  • Loading branch information
pieterlexis committed Mar 19, 2019
2 parents 7324586 + b4a7c77 commit 6b23ae3
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
4 changes: 3 additions & 1 deletion modules/gmysqlbackend/gmysqlbackend.cc
Expand Up @@ -59,7 +59,8 @@ void gMySQLBackend::reconnect()
getArg("password"),
getArg("group"),
mustDo("innodb-read-committed"),
getArgAsNum("timeout")));
getArgAsNum("timeout"),
mustDo("thread-cleanup")));
}

class gMySQLFactory : public BackendFactory
Expand All @@ -78,6 +79,7 @@ class gMySQLFactory : public BackendFactory
declare(suffix,"group", "Database backend MySQL 'group' to connect as", "client");
declare(suffix,"innodb-read-committed","Use InnoDB READ-COMMITTED transaction isolation level","yes");
declare(suffix,"timeout", "The timeout in seconds for each attempt to read/write to the server", "10");
declare(suffix,"thread-cleanup","Explicitly call mysql_thread_end() when threads end","no");

declare(suffix,"dnssec","Enable DNSSEC processing","no");

Expand Down
34 changes: 32 additions & 2 deletions modules/gmysqlbackend/smysql.cc
Expand Up @@ -38,6 +38,32 @@
typedef bool my_bool;
#endif

/*
* Older versions of the MySQL and MariaDB client leak memory
* because they expect the application to call mysql_thread_end()
* when a thread ends. This thread_local static object provides
* that closure, but only when the user has asked for it
* by setting gmysql-thread-cleanup.
* For more discussion, see https://github.com/PowerDNS/pdns/issues/6231
*/
class MySQLThreadCloser
{
public:
~MySQLThreadCloser() {
if(d_enabled) {
mysql_thread_end();
}
}
void enable() {
d_enabled = true;
}

private:
bool d_enabled = false;
};

static thread_local MySQLThreadCloser threadcloser;

bool SMySQL::s_dolog;
pthread_mutex_t SMySQL::s_myinitlock = PTHREAD_MUTEX_INITIALIZER;

Expand Down Expand Up @@ -411,6 +437,10 @@ void SMySQL::connect()
int retry=1;

Lock l(&s_myinitlock);
if (d_threadCleanup) {
threadcloser.enable();
}

if (!mysql_init(&d_db))
throw sPerrorException("Unable to initialize mysql driver");

Expand Down Expand Up @@ -459,8 +489,8 @@ void SMySQL::connect()
}

SMySQL::SMySQL(const string &database, const string &host, uint16_t port, const string &msocket, const string &user,
const string &password, const string &group, bool setIsolation, unsigned int timeout):
d_database(database), d_host(host), d_msocket(msocket), d_user(user), d_password(password), d_group(group), d_timeout(timeout), d_port(port), d_setIsolation(setIsolation)
const string &password, const string &group, bool setIsolation, unsigned int timeout, bool threadCleanup):
d_database(database), d_host(host), d_msocket(msocket), d_user(user), d_password(password), d_group(group), d_timeout(timeout), d_port(port), d_setIsolation(setIsolation), d_threadCleanup(threadCleanup)
{
connect();
}
Expand Down
4 changes: 3 additions & 1 deletion modules/gmysqlbackend/smysql.hh
Expand Up @@ -32,7 +32,8 @@ public:
SMySQL(const string &database, const string &host="", uint16_t port=0,
const string &msocket="",const string &user="",
const string &password="", const string &group="",
bool setIsolation=false, unsigned int timeout=10);
bool setIsolation=false, unsigned int timeout=10,
bool threadCleanup=false);

~SMySQL();

Expand Down Expand Up @@ -61,6 +62,7 @@ private:
unsigned int d_timeout;
uint16_t d_port;
bool d_setIsolation;
bool d_threadCleanup;
};

#endif /* SSMYSQL_HH */

0 comments on commit 6b23ae3

Please sign in to comment.