From 0038f6b6d779234f1c04e77223385ba6ed7d2664 Mon Sep 17 00:00:00 2001 From: Bo Date: Tue, 22 Oct 2024 18:46:16 +0300 Subject: [PATCH] cleanup and joys --- .github/workflows/posix.yml | 2 +- .github/workflows/ruby.yml | 43 ------------------- ext/iodine/iodine_connection.h | 64 +++++++++++------------------ ext/iodine/iodine_mustache.h | 75 ++++++++++++++++++++-------------- ext/iodine/iodine_threads.h | 5 --- lib/iodine/benchmark.rb | 36 ++++++++-------- 6 files changed, 86 insertions(+), 139 deletions(-) delete mode 100644 .github/workflows/ruby.yml diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 41b5534..a53c77a 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -37,7 +37,7 @@ jobs: echo cflags = $cflags echo HOME = $HOME ruby -e 'puts Gem.default_dir' - sudo bundle exec rake install --trace + bundle exec rake compile --trace # env VERBOSE=1 bundle exec rspec --format documentation # - name: Run tests # run: bundle exec rake diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml deleted file mode 100644 index 306784c..0000000 --- a/.github/workflows/ruby.yml +++ /dev/null @@ -1,43 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support documentation. -# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake -# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby - -name: Building iodine - -on: - push: - branches: [ "master", "rw8.0"] - pull_request: - branches: [ "master" ] - -permissions: - contents: read - -jobs: - test: - strategy: - fail-fast: false - matrix: - ruby-version: ['3.1', '3.2', '3.3'] - os: [ubuntu-24.04, macos-14, windows-2022] # , windows-latest - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - name: Set up Ruby # see https://github.com/ruby/setup-ruby#versioning) - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version }} - - name: Install Gems - run: bundle install - - name: Build and Test Iodine - run: | - echo CFLAGS = $CFLAGS - echo cflags = $cflags - echo HOME = $HOME - ruby -e 'puts Gem.default_dir' - env VERBOSE=1 bundle exec rake install --trace -# env VERBOSE=1 bundle exec rspec --format documentation -# - name: Run tests -# run: bundle exec rake diff --git a/ext/iodine/iodine_connection.h b/ext/iodine/iodine_connection.h index 9a6fdc0..065fb2f 100644 --- a/ext/iodine/iodine_connection.h +++ b/ext/iodine/iodine_connection.h @@ -1571,35 +1571,17 @@ IODINE_CONNECTION_DEF_CB(on_authenticate_websocket, IODINE_CONNECTION_UPGRADE_WS); #undef IODINE_CONNECTION_DEF_CB -/** Called when an EventSource event is received. */ -static void iodine_io_http_on_eventsource(fio_http_s *h, - fio_buf_info_s id, - fio_buf_info_s event, - fio_buf_info_s data) { - /* TODO: FIXME! move into GVL and create message struct to pass to callback - */ - VALUE connection = (VALUE)fio_http_udata2(h); - if (!connection || connection == Qnil) - return; - iodine_connection_s *c = iodine_connection_ptr(connection); - if (!c) - return; - iodine_ruby_call_outside(c->store[IODINE_CONNECTION_STORE_handler], - IODINE_ON_EVENTSOURCE_ID, - 1, - &connection); -} typedef struct { fio_http_s *h; fio_buf_info_s id; fio_buf_info_s event; fio_buf_info_s data; -} iodine_http_on_eventsource_internal_s; +} iodine_io_http_on_eventsource_internal_s; static void *iodine_io_http_on_eventsource_reconnect_internal(void *info_) { - iodine_http_on_eventsource_internal_s *i = - (iodine_http_on_eventsource_internal_s *)info_; + iodine_io_http_on_eventsource_internal_s *i = + (iodine_io_http_on_eventsource_internal_s *)info_; VALUE connection = (VALUE)fio_http_udata2(i->h); if (!connection || connection == Qnil) return NULL; @@ -1621,14 +1603,14 @@ static void iodine_io_http_on_eventsource_reconnect(fio_http_s *h, VALUE connection = (VALUE)fio_http_udata2(h); if (!connection || connection == Qnil) return; - iodine_http_on_eventsource_internal_s info = {.h = h, .id = id}; + iodine_io_http_on_eventsource_internal_s info = {.h = h, .id = id}; rb_thread_call_with_gvl(iodine_io_http_on_eventsource_reconnect_internal, &info); } -static void *iodine_http_on_eventsource_internal(void *info_) { - iodine_http_on_eventsource_internal_s *i = - (iodine_http_on_eventsource_internal_s *)info_; +static void *iodine_io_http_on_eventsource_internal(void *info_) { + iodine_io_http_on_eventsource_internal_s *i = + (iodine_io_http_on_eventsource_internal_s *)info_; VALUE connection = (VALUE)fio_http_udata2(i->h); if (!connection || connection == Qnil) return NULL; @@ -1647,15 +1629,15 @@ static void *iodine_http_on_eventsource_internal(void *info_) { return NULL; } /** Called when an EventSource event is received. */ -static void iodine_http_on_eventsource(fio_http_s *h, - fio_buf_info_s id, - fio_buf_info_s event, - fio_buf_info_s data) { - iodine_http_on_eventsource_internal_s info = {.h = h, - .id = id, - .event = event, - .data = data}; - rb_thread_call_with_gvl(iodine_http_on_eventsource_internal, &info); +static void iodine_io_http_on_eventsource(fio_http_s *h, + fio_buf_info_s id, + fio_buf_info_s event, + fio_buf_info_s data) { + iodine_io_http_on_eventsource_internal_s info = {.h = h, + .id = id, + .event = event, + .data = data}; + rb_thread_call_with_gvl(iodine_io_http_on_eventsource_internal, &info); } typedef struct { @@ -1804,7 +1786,7 @@ FIO_IFUNC iodine_connection_args_s iodine_connection_parse_args(int argc, iodine_io_http_on_authenticate_websocket, .on_open = iodine_io_http_on_open, .on_message = iodine_io_http_on_message, - .on_eventsource = iodine_http_on_eventsource, + .on_eventsource = iodine_io_http_on_eventsource, .on_eventsource_reconnect = iodine_io_http_on_eventsource_reconnect, .on_ready = iodine_io_http_on_ready, @@ -1961,18 +1943,18 @@ static int iodine_connection___client_headers(VALUE n, VALUE v, VALUE h_) { goto is_array; if (!RB_TYPE_P(v, RUBY_T_STRING)) return ST_CONTINUE; - iodine_connection___add_header(h, - (fio_str_info_s)IODINE_RSTR_INFO(n), - (fio_str_info_s)IODINE_RSTR_INFO(v)); + iodine_connection___client_headers_add(h, + (fio_str_info_s)IODINE_RSTR_INFO(n), + (fio_str_info_s)IODINE_RSTR_INFO(v)); return ST_CONTINUE; is_array: for (size_t i = 0; i < (size_t)RARRAY_LEN(v); ++i) { VALUE t = RARRAY_PTR(v)[i]; if (!RB_TYPE_P(t, RUBY_T_STRING)) continue; - iodine_connection___add_header(h, - (fio_str_info_s)IODINE_RSTR_INFO(n), - (fio_str_info_s)IODINE_RSTR_INFO(t)); + iodine_connection___client_headers_add(h, + (fio_str_info_s)IODINE_RSTR_INFO(n), + (fio_str_info_s)IODINE_RSTR_INFO(t)); } return ST_CONTINUE; } diff --git a/ext/iodine/iodine_mustache.h b/ext/iodine/iodine_mustache.h index cc2b582..a376da3 100644 --- a/ext/iodine/iodine_mustache.h +++ b/ext/iodine/iodine_mustache.h @@ -99,33 +99,47 @@ static void mus_on_yaml_front_matter(fio_buf_info_s yaml_front_matter, Ruby Object. ***************************************************************************** */ -typedef struct fio_mustache_wrapper_s { - fio_mustache_s *m; -} fio_mustache_wrapper_s; - -static size_t fio_mustache_wrapper_size(void *ptr_) { - return fio_bstr_len((const char *)ptr_) + 8; +static size_t fio_mustache_wrapper_size(const void *ptr_) { + return fio_bstr_len(*(const char **)ptr_) + 8; } static void fio_mustache_wrapper_free(void *p) { - fio_mustache_wrapper_s *wrapper = (fio_mustache_wrapper_s *)p; - fio_mustache_free(wrapper->m); + fio_mustache_s **pm = (fio_mustache_s **)p; + fio_mustache_free(*pm); FIO_LEAK_COUNTER_ON_FREE(iodine_mustache); - free(wrapper); + ruby_xfree(pm); } +static const rb_data_type_t IODINE_MUSTACHE_DATA_TYPE = { + .wrap_struct_name = "IodineMustache", + .function = + { + .dfree = fio_mustache_wrapper_free, + .dsize = fio_mustache_wrapper_size, + }, + .data = NULL, + // .flags = RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE fio_mustache_wrapper_alloc(VALUE klass) { - fio_mustache_wrapper_s *wrapper; - VALUE o = Data_Make_Struct(klass, - fio_mustache_wrapper_s, - NULL, - fio_mustache_wrapper_free, - wrapper); - *wrapper = (fio_mustache_wrapper_s){NULL}; + fio_mustache_s **mp; + VALUE o = TypedData_Make_Struct(klass, + fio_mustache_s *, + &IODINE_MUSTACHE_DATA_TYPE, + mp); + *mp = NULL; FIO_LEAK_COUNTER_ON_ALLOC(iodine_mustache); return o; } +static fio_mustache_s **fio_mustache_wrapper_get(VALUE self) { + fio_mustache_s **mp; + return TypedData_Get_Struct(self, + fio_mustache_s *, + &IODINE_MUSTACHE_DATA_TYPE, + mp); +} + /* ***************************************************************************** API ***************************************************************************** */ @@ -176,9 +190,8 @@ static VALUE mus_load_template(int argc, VALUE *argv, VALUE self) { // clang-for if (!m) rb_raise(rb_eStandardError, "template couldn't be found or empty, nothing to build."); - fio_mustache_wrapper_s *wrapper; - Data_Get_Struct(self, fio_mustache_wrapper_s, wrapper); - wrapper->m = m; + fio_mustache_s **mp = fio_mustache_wrapper_get(self); + *mp = m; return self; } @@ -192,19 +205,19 @@ static VALUE mus_load_template(int argc, VALUE *argv, VALUE self) { // clang-for * @return [String] returns a String containing the rendered template. */ static VALUE mus_render(VALUE self, VALUE ctx) { - fio_mustache_wrapper_s *wrapper; - Data_Get_Struct(self, fio_mustache_wrapper_s, wrapper); - if (!wrapper->m) + fio_mustache_s **mp = fio_mustache_wrapper_get(self); + if (!*mp) rb_raise(rb_eStandardError, "mustache template is empty, couldn't render."); - char *result = fio_mustache_build(wrapper->m, - .get_var = mus_get_var, - .array_length = mus_get_array_len, - .get_var_index = mus_get_var_index, - .var2str = mus_var2str, - .var_is_truthful = mus_var_is_truthful, - .release_var = mus_release_var, - .is_lambda = mus_is_lambda, - .ctx = (void *)ctx); + char *result = + (char *)fio_mustache_build(*mp, + .get_var = mus_get_var, + .array_length = mus_get_array_len, + .get_var_index = mus_get_var_index, + .var2str = mus_var2str, + .var_is_truthful = mus_var_is_truthful, + .release_var = mus_release_var, + .is_lambda = mus_is_lambda, + .ctx = (void *)ctx); if (!result) return Qnil; VALUE str = rb_utf8_str_new(result, fio_bstr_len(result)); diff --git a/ext/iodine/iodine_threads.h b/ext/iodine/iodine_threads.h index f78dd87..45affdd 100644 --- a/ext/iodine/iodine_threads.h +++ b/ext/iodine/iodine_threads.h @@ -4,11 +4,6 @@ API for forking processes ***************************************************************************** */ -static void *iodine_call_ruby_fork(void *r) { - return (void *)rb_funcallv(rb_mProcess, rb_intern2("fork", 4), 0, NULL); - (void)r; -} - /** Should behave the same as the POSIX system call `fork`. */ FIO_IFUNC fio_thread_pid_t fio_thread_fork(void) { iodine_caller_result_s r = diff --git a/lib/iodine/benchmark.rb b/lib/iodine/benchmark.rb index 800b436..1c6d022 100644 --- a/lib/iodine/benchmark.rb +++ b/lib/iodine/benchmark.rb @@ -82,7 +82,7 @@ def self.json(data_length = 1000) # # The test is, sadly, biased and doesn't test for missing elements, proc/method resolution or template partials. # - def self.mustache + def self.mustache(items = 1000) require 'benchmark/ips' require 'mustache' template = """ @@ -103,20 +103,20 @@ def self.mustache """ # fill Hash objects with values for template rendering - data_1000 = { + data = { products: [] } - data_1000_escaped = { + data_escaped = { products: [] } - 1000.times do - data_1000[:products] << { + items.times do + data[:products] << { :external_index=>"product", :url=>"/products/7", :image=>"products/product.jpg" } - data_1000_escaped[:products] << { + data_escaped[:products] << { :external_index=>"This should've been \"properly\" escaped.", :url=>"/products/7", :image=>"products/product.jpg" @@ -133,25 +133,25 @@ def self.mustache # benchmark different use cases ::Benchmark.ips do |x| - x.report("Ruby Mustache render list of 1000") do |times| - view.render(data_1000) + x.report("Ruby Mustache render list of #{items.to_s}") do |times| + view.render(data) end - x.report("Iodine::Mustache render list of 1000") do |times| - mus_view.render(data_1000) + x.report("Iodine::Mustache render list of #{items.to_s}") do |times| + mus_view.render(data) end - x.report("Ruby Mustache render list of 1000 with escaped data") do |times| - view.render(data_1000_escaped) + x.report("Ruby Mustache render list of #{items.to_s} with escaped data") do |times| + view.render(data_escaped) end - x.report("Iodine::Mustache render list of 1000 with escaped data") do |times| - mus_view.render(data_1000_escaped) + x.report("Iodine::Mustache render list of #{items.to_s} with escaped data") do |times| + mus_view.render(data_escaped) end - x.report("Ruby Mustache - no caching - render list of 1000") do |times| - ::Mustache.render(template, data_1000) + x.report("Ruby Mustache - no caching - render list of #{items.to_s}") do |times| + ::Mustache.render(template, data) end - x.report("Iodine::Mustache - no caching - render list of 1000") do |times| - Iodine::Mustache.render(template: template, ctx: data_1000) + x.report("Iodine::Mustache - no caching - render list of #{items.to_s}") do |times| + Iodine::Mustache.render(template: template, ctx: data) end x.compare! end ; nil