Skip to content

Commit 1b894c9

Browse files
Merge pull request #1 from manhnguyenvan/terminate-on-close
Fix close connection to mysql
2 parents 329b63b + 33543de commit 1b894c9

File tree

2 files changed

+35
-18
lines changed

2 files changed

+35
-18
lines changed

ext/mysql2/client.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -226,20 +226,6 @@ static void *nogvl_close(void *ptr) {
226226
if (wrapper->connected) {
227227
wrapper->active_thread = Qnil;
228228
wrapper->connected = 0;
229-
#ifndef _WIN32
230-
/* Invalidate the socket before calling mysql_close(). This prevents
231-
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
232-
* the socket. The difference is that invalidate_fd will drop this
233-
* process's reference to the socket only, while a QUIT or shutdown()
234-
* would render the underlying connection unusable, interrupting other
235-
* processes which share this object across a fork().
236-
*/
237-
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
238-
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, leaking some memory\n");
239-
close(wrapper->client->net.fd);
240-
return NULL;
241-
}
242-
#endif
243229

244230
mysql_close(wrapper->client); /* only used to free memory at this point */
245231
}
@@ -256,6 +242,24 @@ void decr_mysql2_client(mysql_client_wrapper *wrapper)
256242
{
257243
wrapper->refcount--;
258244
if (wrapper->refcount == 0) {
245+
246+
#ifndef _WIN32
247+
if (wrapper->connected) {
248+
/* Invalidate the socket before calling mysql_close(). This prevents
249+
* mysql_close() from sending a mysql-QUIT or from calling shutdown() on
250+
* the socket. The difference is that invalidate_fd will drop this
251+
* process's reference to the socket only, while a QUIT or shutdown()
252+
* would render the underlying connection unusable, interrupting other
253+
* processes which share this object across a fork().
254+
*/
255+
if (invalidate_fd(wrapper->client->net.fd) == Qfalse) {
256+
fprintf(stderr, "[WARN] mysql2 failed to invalidate FD safely, leaking some memory\n");
257+
close(wrapper->client->net.fd);
258+
return NULL;
259+
}
260+
}
261+
#endif
262+
259263
nogvl_close(wrapper);
260264
xfree(wrapper->client);
261265
xfree(wrapper);
@@ -389,10 +393,15 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
389393
}
390394

391395
/*
392-
* Immediately disconnect from the server, normally the garbage collector
393-
* will disconnect automatically when a connection is no longer needed.
394-
* Explicitly closing this will free up server resources sooner than waiting
395-
* for the garbage collector.
396+
* Terminate the connection; call this when the connection is no longer needed.
397+
* The garbage collector can close the connection, but doing so emits an
398+
* "Aborted connection" error on the server and increments the Aborted_clients
399+
* status variable.
400+
*
401+
* @see http://dev.mysql.com/doc/en/communication-errors.html
402+
* @see https://github.com/brianmario/mysql2/pull/663
403+
* @return [void]
404+
*
396405
*/
397406
static VALUE rb_mysql_client_close(VALUE self) {
398407
GET_CLIENT(self);

spec/mysql2/client_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ def connect *args
153153
ssl_client.close
154154
end
155155

156+
it "should terminate connections when calling close" do
157+
expect {
158+
Mysql2::Client.new(DatabaseCredentials['root']).close
159+
}.to_not change {
160+
@client.query("SHOW STATUS LIKE 'Aborted_clients'").first['Value'].to_i
161+
}
162+
end
163+
156164
it "should not leave dangling connections after garbage collection" do
157165
GC.start
158166
sleep 0.300 # Let GC do its work

0 commit comments

Comments
 (0)