Skip to content

Commit d27a2c6

Browse files
committed
Hold struct reference in separate object
Previously, we had added a pointer to our column_info struct onto our `Result` for lazy loading the data. This resulted in changing the type of `Result` to `T_DATA` which could have negative performance implications. Instead, we can create a separate `Columns` class to store the pointer to our struct. A reference to `columns` now gets eagerly loaded onto the result, but we only populate the actual information for the columns when calling `Result#columns`. This seems like a good trade off for lazy loading (vs. putting the pointer directly on `Result`). Having said that, it's probably worth asking if the lazy loading is worth this extra complexity at all, or if we shoudl simply populate `@columns` with an already loaded array for the `Result` immediately.
1 parent 33dff02 commit d27a2c6

File tree

2 files changed

+54
-30
lines changed

2 files changed

+54
-30
lines changed

contrib/ruby/ext/trilogy-ruby/cext.c

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717

1818
VALUE Trilogy_CastError;
1919
static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
20-
Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError,
21-
Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result, Trilogy_Result_Column, Trilogy_EOFError;
20+
Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError, Trilogy_TimeoutError,
21+
Trilogy_SyscallError, Trilogy_Result, Trilogy_Result_Columns, Trilogy_Result_Column, Trilogy_EOFError;
2222

2323
static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout,
2424
id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count,
25-
id_ivar_affected_rows, id_ivar_fields, id_ivar_last_insert_id, id_ivar_rows, id_ivar_query_time, id_password,
25+
id_ivar_affected_rows, id_ivar_fields, id_ivar_columns, id_ivar_last_insert_id, id_ivar_rows, id_ivar_query_time, id_password,
2626
id_database, id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
2727
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result,
2828
id_from_code, id_from_errno, id_connection_options, id_max_allowed_packet;
@@ -34,7 +34,7 @@ struct trilogy_ctx {
3434
VALUE encoding;
3535
};
3636

37-
struct trilogy_result_ctx {
37+
struct trilogy_result_columns_ctx {
3838
struct column_info *column_info;
3939
uint64_t column_count;
4040
};
@@ -54,19 +54,19 @@ static void free_trilogy(void *ptr)
5454
xfree(ptr);
5555
}
5656

57-
static void free_trilogy_result(void *ptr)
57+
static void free_trilogy_result_columns(void *ptr)
5858
{
59-
struct trilogy_result_ctx *ctx = ptr;
59+
struct trilogy_result_columns_ctx *ctx = ptr;
6060
if (ctx->column_info != NULL) {
6161
xfree(ctx->column_info);
6262
}
6363
xfree(ptr);
6464
}
6565

66-
static size_t trilogy_result_memsize(const void *ptr)
66+
static size_t trilogy_result_columns_memsize(const void *ptr)
6767
{
68-
const struct trilogy_result_ctx *ctx = ptr;
69-
size_t memsize = sizeof(struct trilogy_result_ctx);
68+
const struct trilogy_result_columns_ctx *ctx = ptr;
69+
size_t memsize = sizeof(struct trilogy_result_columns_ctx);
7070
if (ctx->column_info != NULL) {
7171
memsize += sizeof(struct column_info) * ctx->column_count;
7272
}
@@ -93,11 +93,11 @@ static const rb_data_type_t trilogy_data_type = {
9393
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
9494
};
9595

96-
static const rb_data_type_t trilogy_result_data_type = {
97-
.wrap_struct_name = "trilogy_result",
96+
static const rb_data_type_t trilogy_result_columns_data_type = {
97+
.wrap_struct_name = "trilogy_result_columns",
9898
.function = {
99-
.dfree = free_trilogy_result,
100-
.dsize = trilogy_result_memsize,
99+
.dfree = free_trilogy_result_columns,
100+
.dsize = trilogy_result_columns_memsize,
101101
},
102102
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
103103
};
@@ -216,19 +216,19 @@ static VALUE allocate_trilogy(VALUE klass)
216216
return obj;
217217
}
218218

219-
static VALUE allocate_trilogy_result(VALUE klass)
219+
static VALUE allocate_trilogy_result_columns(VALUE klass)
220220
{
221-
struct trilogy_result_ctx *ctx;
221+
struct trilogy_result_columns_ctx *ctx;
222222

223-
VALUE obj = TypedData_Make_Struct(klass, struct trilogy_result_ctx, &trilogy_result_data_type, ctx);
223+
VALUE obj = TypedData_Make_Struct(klass, struct trilogy_result_columns_ctx, &trilogy_result_columns_data_type, ctx);
224224

225225
return obj;
226226
}
227227

228-
static struct trilogy_result_ctx *get_trilogy_result_ctx(VALUE obj)
228+
static struct trilogy_result_columns_ctx *get_trilogy_result_columns_ctx(VALUE obj)
229229
{
230-
struct trilogy_result_ctx *ctx;
231-
TypedData_Get_Struct(obj, struct trilogy_result_ctx, &trilogy_result_data_type, ctx);
230+
struct trilogy_result_columns_ctx *ctx;
231+
TypedData_Get_Struct(obj, struct trilogy_result_columns_ctx, &trilogy_result_columns_data_type, ctx);
232232
return ctx;
233233
}
234234

@@ -799,6 +799,9 @@ static VALUE read_query_response(VALUE vargs)
799799
VALUE column_names = rb_ary_new2(column_count);
800800
rb_ivar_set(result, id_ivar_fields, column_names);
801801

802+
VALUE columns = rb_obj_alloc(Trilogy_Result_Columns);
803+
rb_ivar_set(result, id_ivar_columns, columns);
804+
802805
VALUE rows = rb_ary_new();
803806
rb_ivar_set(result, id_ivar_rows, rows);
804807

@@ -814,7 +817,7 @@ static VALUE read_query_response(VALUE vargs)
814817
rb_ivar_set(result, id_ivar_last_insert_id, Qnil);
815818
rb_ivar_set(result, id_ivar_affected_rows, Qnil);
816819
}
817-
struct trilogy_result_ctx *trilogy_result_ctx = get_trilogy_result_ctx(result);
820+
struct trilogy_result_columns_ctx *trilogy_result_ctx = get_trilogy_result_columns_ctx(columns);
818821
trilogy_result_ctx->column_info = ALLOC_N(struct column_info, column_count);
819822
trilogy_result_ctx->column_count = column_count;
820823
for (uint64_t i = 0; i < column_count; i++) {
@@ -1169,15 +1172,15 @@ static char *downcase(const char *str)
11691172

11701173
static VALUE rb_trilogy_result_columns(VALUE self)
11711174
{
1172-
struct trilogy_result_ctx *trilogy_result_ctx = get_trilogy_result_ctx(self);
1175+
struct trilogy_result_columns_ctx *trilogy_result_columns_ctx = get_trilogy_result_columns_ctx(self);
11731176
VALUE cols = rb_ary_new();
1174-
for (uint64_t i = 0; i < trilogy_result_ctx->column_count; i++) {
1177+
for (uint64_t i = 0; i < trilogy_result_columns_ctx->column_count; i++) {
11751178
VALUE obj = rb_funcall(
1176-
Trilogy_Result_Column, rb_intern("new"), 6, trilogy_result_ctx->column_info[i].name,
1177-
rb_id2sym(rb_intern(downcase(trilogy_type_names[trilogy_result_ctx->column_info[i].type]))),
1178-
rb_int_new(trilogy_result_ctx->column_info[i].len), rb_int_new(trilogy_result_ctx->column_info[i].flags),
1179-
rb_id2sym(rb_intern(downcase(trilogy_charset_names[trilogy_result_ctx->column_info[i].charset]))),
1180-
rb_int_new(trilogy_result_ctx->column_info[i].decimals));
1179+
Trilogy_Result_Column, rb_intern("new"), 6, trilogy_result_columns_ctx->column_info[i].name,
1180+
rb_id2sym(rb_intern(downcase(trilogy_type_names[trilogy_result_columns_ctx->column_info[i].type]))),
1181+
rb_int_new(trilogy_result_columns_ctx->column_info[i].len), rb_int_new(trilogy_result_columns_ctx->column_info[i].flags),
1182+
rb_id2sym(rb_intern(downcase(trilogy_charset_names[trilogy_result_columns_ctx->column_info[i].charset]))),
1183+
rb_int_new(trilogy_result_columns_ctx->column_info[i].decimals));
11811184
rb_ary_push(cols, obj);
11821185
}
11831186
return cols;
@@ -1260,9 +1263,14 @@ RUBY_FUNC_EXPORTED void Init_cext()
12601263
rb_global_variable(&Trilogy_ConnectionClosedError);
12611264

12621265
Trilogy_Result = rb_const_get(Trilogy, rb_intern("Result"));
1263-
rb_define_alloc_func(Trilogy_Result, allocate_trilogy_result);
12641266
rb_global_variable(&Trilogy_Result);
1265-
rb_define_private_method(Trilogy_Result, "_columns", rb_trilogy_result_columns, 0);
1267+
1268+
Trilogy_Result_Columns = rb_const_get(Trilogy_Result, rb_intern("Columns"));
1269+
rb_define_alloc_func(Trilogy_Result_Columns, allocate_trilogy_result_columns);
1270+
1271+
rb_define_private_method(Trilogy_Result_Columns, "_all", rb_trilogy_result_columns, 0);
1272+
1273+
rb_global_variable(&Trilogy_Result_Columns);
12661274

12671275
Trilogy_Result_Column = rb_const_get(Trilogy_Result, rb_intern("Column"));
12681276
rb_global_variable(&Trilogy_Result_Column);
@@ -1308,6 +1316,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
13081316
id_from_errno = rb_intern("from_errno");
13091317
id_ivar_affected_rows = rb_intern("@affected_rows");
13101318
id_ivar_fields = rb_intern("@fields");
1319+
id_ivar_columns = rb_intern("@columns");
13111320
id_ivar_last_insert_id = rb_intern("@last_insert_id");
13121321
id_ivar_rows = rb_intern("@rows");
13131322
id_ivar_query_time = rb_intern("@query_time");

contrib/ruby/lib/trilogy/result.rb

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,26 @@ def each(&bk)
2929
end
3030

3131
def columns
32-
@columns ||= _columns
32+
@columns.all
3333
end
3434

3535
include Enumerable
3636

37+
38+
class Columns
39+
def all
40+
@all ||= _all
41+
end
42+
43+
def count
44+
all.count
45+
end
46+
47+
def each(&bk)
48+
all.each(&bk)
49+
end
50+
end
51+
3752
class Column
3853
attr_reader :name, :type, :length, :flags, :charset, :decimals
3954

0 commit comments

Comments
 (0)