Skip to content

Commit fbc0f94

Browse files
committed
Handle sync connection closing during async query, fixes #157
1 parent a15ec1c commit fbc0f94

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

src/mysql_bindings_connection.cc

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ bool MysqlConnection::RealConnect(const char* hostname,
183183
}
184184

185185
void MysqlConnection::Close() {
186+
DEBUG_PRINTF("Close: pthread_mutex_lock\n");
187+
pthread_mutex_lock(&this->query_lock);
188+
DEBUG_PRINTF("Close: pthread_mutex_lock'ed\n");
186189
if (this->_conn) {
190+
187191
mysql_close(this->_conn);
188192
this->_conn = NULL;
189193
this->connected = false;
@@ -192,6 +196,8 @@ void MysqlConnection::Close() {
192196
this->connect_errno = 0;
193197
this->connect_error = NULL;
194198
}
199+
DEBUG_PRINTF("Close: pthread_mutex_unlock\n");
200+
pthread_mutex_unlock(&this->query_lock);
195201
}
196202

197203
MysqlConnection::MysqlConnection(): ObjectWrap() {
@@ -990,8 +996,15 @@ void MysqlConnection::EIO_After_Query(uv_work_t *req) {
990996
// for both MysqlResult creation and callback call
991997
int argc = 1; // node.js convention, there is always at least one argument for callback
992998
Local<Value> argv[3];
993-
994-
if (!query_req->ok) {
999+
DEBUG_PRINTF("EIO_After_Query: in\n");
1000+
if (!query_req->conn->_conn || !query_req->conn->connected || query_req->connection_closed) {
1001+
DEBUG_PRINTF("EIO_After_Query: !query_req->conn->_conn || !query_req->conn->connected || query_req->connection_closed\n");
1002+
// Check connection
1003+
// If closeSync() is called after query(),
1004+
// than connection is destroyed here
1005+
// https://github.com/Sannis/node-mysql-libmysqlclient/issues/157
1006+
argv[0] = V8EXC("Connection is closed by closeSync() during query");
1007+
} else if (!query_req->ok) {
9951008
unsigned int error_string_length = strlen(query_req->error) + 20;
9961009
char* error_string = new char[error_string_length];
9971010
snprintf(error_string, error_string_length, "Query error #%d: %s",
@@ -1021,6 +1034,7 @@ void MysqlConnection::EIO_After_Query(uv_work_t *req) {
10211034
}
10221035

10231036
if (query_req->callback->IsFunction()) {
1037+
DEBUG_PRINTF("EIO_After_Query: node::MakeCallback\n");
10241038
node::MakeCallback(
10251039
Context::GetCurrent()->Global(),
10261040
Persistent<Function>::Cast(query_req->callback),
@@ -1030,7 +1044,13 @@ void MysqlConnection::EIO_After_Query(uv_work_t *req) {
10301044
query_req->callback.Dispose();
10311045
}
10321046

1033-
query_req->conn->Unref();
1047+
// See comment above
1048+
DEBUG_PRINTF("EIO_After_Query: Unref?\n");
1049+
if (!query_req->conn->_conn || !query_req->conn->connected) {
1050+
DEBUG_PRINTF("EIO_After_Query: Unref\n");
1051+
query_req->conn->Unref();
1052+
DEBUG_PRINTF("EIO_After_Query: Unref'ed\n");
1053+
}
10341054

10351055
delete[] query_req->query;
10361056
delete query_req;
@@ -1043,14 +1063,27 @@ void MysqlConnection::EIO_Query(uv_work_t *req) {
10431063

10441064
MysqlConnection *conn = query_req->conn;
10451065

1046-
if (!conn->_conn) {
1066+
DEBUG_PRINTF("EIO_Query: pthread_mutex_lock\n");
1067+
pthread_mutex_lock(&conn->query_lock);
1068+
DEBUG_PRINTF("EIO_Query: pthread_mutex_lock'ed\n");
1069+
1070+
// Check connection
1071+
// If closeSync() is called after query(),
1072+
// than connection is destroyed here
1073+
// https://github.com/Sannis/node-mysql-libmysqlclient/issues/157
1074+
if (!conn->_conn || !conn->connected) {
10471075
query_req->ok = false;
1048-
// TODO: Handle this
1076+
query_req->connection_closed = true;
1077+
1078+
DEBUG_PRINTF("EIO_Query: !conn->_conn || !conn->connected\n");
1079+
DEBUG_PRINTF("EIO_Query: pthread_mutex_unlock\n");
1080+
pthread_mutex_unlock(&conn->query_lock);
1081+
return;
10491082
}
1083+
query_req->connection_closed = false;
10501084

10511085
MYSQLCONN_DISABLE_MQ;
10521086

1053-
pthread_mutex_lock(&conn->query_lock);
10541087
int r = mysql_real_query(conn->_conn, query_req->query, query_req->query_len);
10551088
int errno = mysql_errno(conn->_conn);
10561089
if (r != 0 || errno != 0) {
@@ -1085,6 +1118,7 @@ void MysqlConnection::EIO_Query(uv_work_t *req) {
10851118
}
10861119
}
10871120
}
1121+
DEBUG_PRINTF("EIO_Query: pthread_mutex_unlock\n");
10881122
pthread_mutex_unlock(&conn->query_lock);
10891123
}
10901124

src/mysql_bindings_connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class MysqlConnection : public node::ObjectWrap {
177177

178178
struct query_request {
179179
bool ok;
180+
bool connection_closed;
180181
bool have_result_set;
181182

182183
Persistent<Value> callback;

tests/issues/test-issue-157.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
Copyright by Oleg Efimov and node-mysql-libmysqlclient contributors
3+
See contributors list in README
4+
5+
See license text in LICENSE file
6+
*/
7+
8+
// Load configuration
9+
var cfg = require("../config");
10+
11+
exports.issue157 = function (test) {
12+
test.expect(3);
13+
14+
var conn = cfg.mysql_libmysqlclient.createConnectionSync(cfg.host, cfg.user, cfg.password, cfg.database);
15+
16+
conn.query('SELECT SLEEP(100);', function (err) {
17+
test.ok(err instanceof Error);
18+
test.ok(err.message.indexOf("Connection is closed by closeSync()") === 0);
19+
20+
test.done();
21+
});
22+
23+
conn.closeSync();
24+
25+
test.ok(true);
26+
};

0 commit comments

Comments
 (0)