Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the bug #606 for version 0.3.x ( base on the pr https://github.com/brianmario/mysql2/pull/663 ) #1202

Open
wants to merge 2 commits into
base: 0.3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 27 additions & 18 deletions ext/mysql2/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,6 @@ static void *nogvl_close(void *ptr) {
if (wrapper->connected) {
wrapper->active_thread = Qnil;
wrapper->connected = 0;
#ifndef _WIN32
/* Invalidate the socket before calling mysql_close(). This prevents
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
* the socket. The difference is that invalidate_fd will drop this
* process's reference to the socket only, while a QUIT or shutdown()
* would render the underlying connection unusable, interrupting other
* processes which share this object across a fork().
*/
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, leaking some memory\n");
close(wrapper->client->net.fd);
return NULL;
}
#endif

mysql_close(wrapper->client); /* only used to free memory at this point */
}
Expand All @@ -256,6 +242,24 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
{
wrapper->refcount--;
if (wrapper->refcount == 0) {

#ifndef _WIN32
if (wrapper->connected) {
/* Invalidate the socket before calling mysql_close(). This prevents
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
* the socket. The difference is that invalidate_fd will drop this
* process's reference to the socket only, while a QUIT or shutdown()
* would render the underlying connection unusable, interrupting other
* processes which share this object across a fork().
*/
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, leaking some memory\n");
close(wrapper->client->net.fd);
return NULL;
}
}
#endif

nogvl_close(wrapper);
xfree(wrapper->client);
xfree(wrapper);
Expand Down Expand Up @@ -389,10 +393,15 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
}

/*
* Immediately disconnect from the server, normally the garbage collector
* will disconnect automatically when a connection is no longer needed.
* Explicitly closing this will free up server resources sooner than waiting
* for the garbage collector.
* Terminate the connection; call this when the connection is no longer needed.
* The garbage collector can close the connection, but doing so emits an
* "Aborted connection" error on the server and increments the Aborted_clients
* status variable.
*
* @see http://dev.mysql.com/doc/en/communication-errors.html
* @see https://github.com/brianmario/mysql2/pull/663
* @return [void]
*
*/
static VALUE rb_mysql_client_close(VALUE self) {
GET_CLIENT(self);
Expand Down
8 changes: 8 additions & 0 deletions spec/mysql2/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ def connect *args
ssl_client.close
end

it "should terminate connections when calling close" do
expect {
Mysql2::Client.new(DatabaseCredentials['root']).close
}.to_not change {
@client.query("SHOW STATUS LIKE 'Aborted_clients'").first['Value'].to_i
}
end

it "should not leave dangling connections after garbage collection" do
GC.start
sleep 0.300 # Let GC do its work
Expand Down