From 9f8b746e776031e6eef6dea84c8dafbb8c24c725 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 5 Nov 2020 12:45:08 +0300 Subject: Ruby: reusing static constant references to string objects. This shall save a couple of CPU cycles in request processing. --- src/ruby/nxt_ruby.c | 158 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 43 deletions(-) (limited to 'src/ruby') diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c index 743bf646..7b383557 100644 --- a/src/ruby/nxt_ruby.c +++ b/src/ruby/nxt_ruby.c @@ -14,14 +14,6 @@ #define NXT_RUBY_RACK_API_VERSION_MAJOR 1 #define NXT_RUBY_RACK_API_VERSION_MINOR 3 -#define NXT_RUBY_STRINGIZE_HELPER(x) #x -#define NXT_RUBY_STRINGIZE(x) NXT_RUBY_STRINGIZE_HELPER(x) - -#define NXT_RUBY_LIB_VERSION \ - NXT_RUBY_STRINGIZE(RUBY_API_VERSION_MAJOR) \ - "." NXT_RUBY_STRINGIZE(RUBY_API_VERSION_MINOR) \ - "." NXT_RUBY_STRINGIZE(RUBY_API_VERSION_TEENY) - typedef struct { nxt_task_t *task; @@ -45,10 +37,8 @@ static void nxt_ruby_request_handler(nxt_unit_request_info_t *req); static VALUE nxt_ruby_rack_app_run(VALUE arg); static int nxt_ruby_read_request(VALUE hash_env); -nxt_inline void nxt_ruby_add_sptr(VALUE hash_env, - const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len); -nxt_inline void nxt_ruby_add_str(VALUE hash_env, - const char *name, uint32_t name_len, const char *str, uint32_t len); +nxt_inline void nxt_ruby_add_sptr(VALUE hash_env, VALUE name, + nxt_unit_sptr_t *sptr, uint32_t len); static nxt_int_t nxt_ruby_rack_result_status(VALUE result); static int nxt_ruby_rack_result_headers(VALUE result, nxt_int_t status); static int nxt_ruby_hash_info(VALUE r_key, VALUE r_value, VALUE arg); @@ -86,6 +76,93 @@ NXT_EXPORT nxt_app_module_t nxt_app_module = { nxt_ruby_start, }; +typedef struct { + nxt_str_t string; + VALUE *v; +} nxt_ruby_string_t; + +static VALUE nxt_rb_80_str; +static VALUE nxt_rb_content_length_str; +static VALUE nxt_rb_content_type_str; +static VALUE nxt_rb_http_str; +static VALUE nxt_rb_https_str; +static VALUE nxt_rb_path_info_str; +static VALUE nxt_rb_query_string_str; +static VALUE nxt_rb_rack_url_scheme_str; +static VALUE nxt_rb_remote_addr_str; +static VALUE nxt_rb_request_method_str; +static VALUE nxt_rb_request_uri_str; +static VALUE nxt_rb_server_addr_str; +static VALUE nxt_rb_server_name_str; +static VALUE nxt_rb_server_port_str; +static VALUE nxt_rb_server_protocol_str; + +static nxt_ruby_string_t nxt_rb_strings[] = { + { nxt_string("80"), &nxt_rb_80_str }, + { nxt_string("CONTENT_LENGTH"), &nxt_rb_content_length_str }, + { nxt_string("CONTENT_TYPE"), &nxt_rb_content_type_str }, + { nxt_string("http"), &nxt_rb_http_str }, + { nxt_string("https"), &nxt_rb_https_str }, + { nxt_string("PATH_INFO"), &nxt_rb_path_info_str }, + { nxt_string("QUERY_STRING"), &nxt_rb_query_string_str }, + { nxt_string("rack.url_scheme"), &nxt_rb_rack_url_scheme_str }, + { nxt_string("REMOTE_ADDR"), &nxt_rb_remote_addr_str }, + { nxt_string("REQUEST_METHOD"), &nxt_rb_request_method_str }, + { nxt_string("REQUEST_URI"), &nxt_rb_request_uri_str }, + { nxt_string("SERVER_ADDR"), &nxt_rb_server_addr_str }, + { nxt_string("SERVER_NAME"), &nxt_rb_server_name_str }, + { nxt_string("SERVER_PORT"), &nxt_rb_server_port_str }, + { nxt_string("SERVER_PROTOCOL"), &nxt_rb_server_protocol_str }, + { nxt_null_string, NULL }, +}; + + +static int +nxt_ruby_init_strings(void) +{ + VALUE v; + nxt_ruby_string_t *pstr; + + pstr = nxt_rb_strings; + + while (pstr->string.start != NULL) { + v = rb_str_new_static((char *) pstr->string.start, pstr->string.length); + + if (nxt_slow_path(v == Qnil)) { + nxt_unit_alert(NULL, "Ruby: failed to create const string '%.*s'", + (int) pstr->string.length, + (char *) pstr->string.start); + + return NXT_UNIT_ERROR; + } + + *pstr->v = v; + + rb_gc_register_address(pstr->v); + + pstr++; + } + + return NXT_UNIT_OK; +} + + +static void +nxt_ruby_done_strings(void) +{ + nxt_ruby_string_t *pstr; + + pstr = nxt_rb_strings; + + while (pstr->string.start != NULL) { + rb_gc_unregister_address(pstr->v); + + *pstr->v = Qnil; + + pstr++; + } +} + static nxt_int_t nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) @@ -109,6 +186,8 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) rack_init.task = task; rack_init.script = &conf->u.ruby.script; + nxt_ruby_init_strings(); + res = rb_protect(nxt_ruby_init_basic, (VALUE) (uintptr_t) &rack_init, &state); if (nxt_slow_path(res == Qnil || state != 0)) { @@ -440,78 +519,69 @@ fail: static int nxt_ruby_read_request(VALUE hash_env) { + VALUE name; uint32_t i; nxt_unit_field_t *f; nxt_unit_request_t *r; r = nxt_ruby_run_ctx.req->request; -#define NL(S) (S), sizeof(S)-1 - - nxt_ruby_add_sptr(hash_env, NL("REQUEST_METHOD"), &r->method, + nxt_ruby_add_sptr(hash_env, nxt_rb_request_method_str, &r->method, r->method_length); - nxt_ruby_add_sptr(hash_env, NL("REQUEST_URI"), &r->target, + nxt_ruby_add_sptr(hash_env, nxt_rb_request_uri_str, &r->target, r->target_length); - nxt_ruby_add_sptr(hash_env, NL("PATH_INFO"), &r->path, r->path_length); - nxt_ruby_add_sptr(hash_env, NL("QUERY_STRING"), &r->query, + nxt_ruby_add_sptr(hash_env, nxt_rb_path_info_str, &r->path, r->path_length); + nxt_ruby_add_sptr(hash_env, nxt_rb_query_string_str, &r->query, r->query_length); - nxt_ruby_add_sptr(hash_env, NL("SERVER_PROTOCOL"), &r->version, + nxt_ruby_add_sptr(hash_env, nxt_rb_server_protocol_str, &r->version, r->version_length); - nxt_ruby_add_sptr(hash_env, NL("REMOTE_ADDR"), &r->remote, + nxt_ruby_add_sptr(hash_env, nxt_rb_remote_addr_str, &r->remote, r->remote_length); - nxt_ruby_add_sptr(hash_env, NL("SERVER_ADDR"), &r->local, r->local_length); - - nxt_ruby_add_sptr(hash_env, NL("SERVER_NAME"), &r->server_name, + nxt_ruby_add_sptr(hash_env, nxt_rb_server_addr_str, &r->local, + r->local_length); + nxt_ruby_add_sptr(hash_env, nxt_rb_server_name_str, &r->server_name, r->server_name_length); - nxt_ruby_add_str(hash_env, NL("SERVER_PORT"), "80", 2); - rb_hash_aset(hash_env, rb_str_new2("rack.url_scheme"), - r->tls ? rb_str_new2("https") : rb_str_new2("http")); + rb_hash_aset(hash_env, nxt_rb_server_port_str, nxt_rb_80_str); + + rb_hash_aset(hash_env, nxt_rb_rack_url_scheme_str, + r->tls ? nxt_rb_https_str : nxt_rb_http_str); for (i = 0; i < r->fields_count; i++) { f = r->fields + i; - nxt_ruby_add_sptr(hash_env, nxt_unit_sptr_get(&f->name), f->name_length, - &f->value, f->value_length); + name = rb_str_new(nxt_unit_sptr_get(&f->name), f->name_length); + + nxt_ruby_add_sptr(hash_env, name, &f->value, f->value_length); } if (r->content_length_field != NXT_UNIT_NONE_FIELD) { f = r->fields + r->content_length_field; - nxt_ruby_add_sptr(hash_env, NL("CONTENT_LENGTH"), + nxt_ruby_add_sptr(hash_env, nxt_rb_content_length_str, &f->value, f->value_length); } if (r->content_type_field != NXT_UNIT_NONE_FIELD) { f = r->fields + r->content_type_field; - nxt_ruby_add_sptr(hash_env, NL("CONTENT_TYPE"), + nxt_ruby_add_sptr(hash_env, nxt_rb_content_type_str, &f->value, f->value_length); } -#undef NL - return NXT_UNIT_OK; } nxt_inline void -nxt_ruby_add_sptr(VALUE hash_env, - const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len) +nxt_ruby_add_sptr(VALUE hash_env, VALUE name, + nxt_unit_sptr_t *sptr, uint32_t len) { char *str; str = nxt_unit_sptr_get(sptr); - rb_hash_aset(hash_env, rb_str_new(name, name_len), rb_str_new(str, len)); -} - - -nxt_inline void -nxt_ruby_add_str(VALUE hash_env, - const char *name, uint32_t name_len, const char *str, uint32_t len) -{ - rb_hash_aset(hash_env, rb_str_new(name, name_len), rb_str_new(str, len)); + rb_hash_aset(hash_env, name, rb_str_new(str, len)); } @@ -901,5 +971,7 @@ nxt_ruby_atexit(void) rb_gc_unregister_address(&nxt_ruby_call); rb_gc_unregister_address(&nxt_ruby_env); + nxt_ruby_done_strings(); + ruby_cleanup(0); } -- cgit