Skip to content

Commit ec9b61c

Browse files
committed
Result objects now keep a reference to the Client that they came from.
1 parent 02da91a commit ec9b61c

File tree

3 files changed

+26
-19
lines changed

3 files changed

+26
-19
lines changed

ext/mysql2/client.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,15 +182,14 @@ static VALUE nogvl_close(void *ptr) {
182182
return Qnil;
183183
}
184184

185-
static void rb_mysql_client_free(void * ptr) {
185+
static void rb_mysql_client_free(void *ptr) {
186186
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
187187

188-
wrapper->freed = 1;
189-
nogvl_close(wrapper);
190-
188+
wrapper->refcount--;
191189
if (wrapper->refcount == 0) {
190+
nogvl_close(wrapper);
192191
xfree(wrapper->client);
193-
xfree(ptr);
192+
xfree(wrapper);
194193
}
195194
}
196195

@@ -203,8 +202,7 @@ static VALUE allocate(VALUE klass) {
203202
wrapper->reconnect_enabled = 0;
204203
wrapper->connected = 0; /* means that a database connection is open */
205204
wrapper->initialized = 0; /* means that that the wrapper is initialized */
206-
wrapper->refcount = 0;
207-
wrapper->freed = 0;
205+
wrapper->refcount = 1;
208206
wrapper->client = (MYSQL*)xmalloc(sizeof(MYSQL));
209207
return obj;
210208
}
@@ -398,7 +396,7 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
398396
return Qnil;
399397
}
400398

401-
resultObj = rb_mysql_result_to_obj(wrapper, result);
399+
resultObj = rb_mysql_result_to_obj(self, result);
402400
/* pass-through query options for result construction later */
403401
rb_iv_set(resultObj, "@query_options", rb_hash_dup(rb_iv_get(self, "@current_query_options")));
404402

@@ -947,7 +945,7 @@ static VALUE rb_mysql_client_store_result(VALUE self)
947945
return Qnil;
948946
}
949947

950-
resultObj = rb_mysql_result_to_obj(wrapper, result);
948+
resultObj = rb_mysql_result_to_obj(self, result);
951949
/* pass-through query options for result construction later */
952950
rb_iv_set(resultObj, "@query_options", rb_hash_dup(rb_iv_get(self, "@current_query_options")));
953951

ext/mysql2/result.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,33 @@ static void rb_mysql_result_mark(void * wrapper) {
6464
rb_gc_mark(w->fields);
6565
rb_gc_mark(w->rows);
6666
rb_gc_mark(w->encoding);
67+
rb_gc_mark(w->client);
6768
}
6869
}
6970

7071
/* this may be called manually or during GC */
7172
static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
7273
if (wrapper && wrapper->resultFreed != 1) {
74+
/* FIXME: this may call flush_use_result, which can hit the socket */
7375
mysql_free_result(wrapper->result);
7476
wrapper->resultFreed = 1;
77+
}
78+
}
79+
80+
/* this is called during GC */
81+
static void rb_mysql_result_free(void *ptr) {
82+
mysql2_result_wrapper * wrapper = ptr;
83+
rb_mysql_result_free_result(wrapper);
84+
85+
// If the GC gets to client first it will be nil
86+
if (wrapper->client != Qnil) {
7587
wrapper->client_wrapper->refcount--;
76-
if (wrapper->client_wrapper->refcount == 0 && wrapper->client_wrapper->freed) {
88+
if (wrapper->client_wrapper->refcount == 0) {
7789
xfree(wrapper->client_wrapper->client);
7890
xfree(wrapper->client_wrapper);
7991
}
8092
}
81-
}
8293

83-
/* this is called during GC */
84-
static void rb_mysql_result_free(void * wrapper) {
85-
mysql2_result_wrapper * w = wrapper;
86-
/* FIXME: this may call flush_use_result, which can hit the socket */
87-
rb_mysql_result_free_result(w);
8894
xfree(wrapper);
8995
}
9096

@@ -567,7 +573,7 @@ static VALUE rb_mysql_result_count(VALUE self) {
567573
}
568574

569575
/* Mysql2::Result */
570-
VALUE rb_mysql_result_to_obj(mysql_client_wrapper *client_wrapper, MYSQL_RES *r) {
576+
VALUE rb_mysql_result_to_obj(VALUE client, MYSQL_RES *r) {
571577
VALUE obj;
572578
mysql2_result_wrapper * wrapper;
573579
obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
@@ -580,8 +586,10 @@ VALUE rb_mysql_result_to_obj(mysql_client_wrapper *client_wrapper, MYSQL_RES *r)
580586
wrapper->rows = Qnil;
581587
wrapper->encoding = Qnil;
582588
wrapper->streamingComplete = 0;
583-
wrapper->client_wrapper = client_wrapper;
589+
wrapper->client = client;
590+
wrapper->client_wrapper = DATA_PTR(client);
584591
wrapper->client_wrapper->refcount++;
592+
585593
rb_obj_call_init(obj, 0, NULL);
586594
return obj;
587595
}

ext/mysql2/result.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
#define MYSQL2_RESULT_H
33

44
void init_mysql2_result();
5-
VALUE rb_mysql_result_to_obj(mysql_client_wrapper *client_wrapper, MYSQL_RES * r);
5+
VALUE rb_mysql_result_to_obj(VALUE client, MYSQL_RES * r);
66

77
typedef struct {
88
VALUE fields;
99
VALUE rows;
10+
VALUE client;
1011
VALUE encoding;
1112
unsigned int numberOfFields;
1213
unsigned long numberOfRows;

0 commit comments

Comments
 (0)