From 0d1ec2d1b864f3d39b4bf67fa6ac6c4aedc18136 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 30 Jun 2015 02:38:55 +0000 Subject: reduce constants and optimize for Ruby 2.2+ Ruby (MRI) 2.1 optimizes allocations away on String#freeze with literal strings. Furthermore, Ruby 2.2 optimizes away literal string allocations when they are used as arguments to Hash#[] and Hash#[]= Thus we can avoid expensive constant lookups and cache overhead by taking advantage of advancements in Ruby. Since Ruby 2.2 has been out for 7 months, now; it ought to be safe to introduce minor performance regressions for folks using older Rubies (1.9.3+ remains supported) to benefit folks on the latest Ruby. --- lib/yahns/http_client.rb | 16 +++++----------- lib/yahns/http_response.rb | 15 +++++---------- lib/yahns/max_body.rb | 12 ++++-------- lib/yahns/proxy_http_response.rb | 5 +++-- 4 files changed, 17 insertions(+), 31 deletions(-) (limited to 'lib') diff --git a/lib/yahns/http_client.rb b/lib/yahns/http_client.rb index 0c656e8..9a37811 100644 --- a/lib/yahns/http_client.rb +++ b/lib/yahns/http_client.rb @@ -11,12 +11,6 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc: include Yahns::HttpResponse QEV_FLAGS = Yahns::Queue::QEV_RD # used by acceptor - # A frozen format for this is about 15% faster (note from Mongrel) - REMOTE_ADDR = 'REMOTE_ADDR'.freeze - RACK_INPUT = 'rack.input'.freeze - RACK_HIJACK = 'rack.hijack'.freeze - RACK_HIJACK_IO = "rack.hijack_io".freeze - # called from acceptor thread def yahns_init @hs = Unicorn::HttpRequest.new @@ -206,9 +200,9 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc: # input is nil if we needed to wait for writability with # check_client_connection if input - env[REMOTE_ADDR] = @kgio_addr - env[RACK_HIJACK] = self - env[RACK_INPUT] = input + env['REMOTE_ADDR'] = @kgio_addr + env['rack.hijack'] = self + env['rack.input'] = input if k.check_client_connection && @hs.headers? rv = do_ccc and return rv @@ -262,7 +256,7 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc: # this is the env["rack.hijack"] callback exposed to the Rack app def call hijack_cleanup - @hs.env[RACK_HIJACK_IO] = self + @hs.env['rack.hijack_io'] = self end def response_hijacked(fn) @@ -300,7 +294,7 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc: end def app_hijacked?(env, body) - return false unless env.include?(RACK_HIJACK_IO) + return false unless env.include?('rack.hijack_io'.freeze) body.close if body.respond_to?(:close) true end diff --git a/lib/yahns/http_response.rb b/lib/yahns/http_response.rb index b70491d..f50c9a1 100644 --- a/lib/yahns/http_response.rb +++ b/lib/yahns/http_response.rb @@ -23,13 +23,7 @@ module Yahns::HttpResponse # :nodoc: end # avoid GC overhead for frequently used-strings: - CONN_KA = "Connection: keep-alive\r\n\r\n" - CONN_CLOSE = "Connection: close\r\n\r\n" - Z = "" CCC_RESPONSE_START = [ 'HTTP', '/1.1 ' ] - RESPONSE_START = CCC_RESPONSE_START.join - REQUEST_METHOD = "REQUEST_METHOD" - HEAD = "HEAD" # no point in using one without the other, these have been in Linux # for ages @@ -46,7 +40,7 @@ module Yahns::HttpResponse # :nodoc: end def response_start - @hs.response_start_sent ? Z : RESPONSE_START + @hs.response_start_sent ? ''.freeze : 'HTTP/1.1 '.freeze end def response_wait_write(rv) @@ -115,7 +109,7 @@ module Yahns::HttpResponse # :nodoc: end def kv_str(key, value) - if value =~ /\n/ + if value.include?("\n".freeze) # avoiding blank, key-only cookies with /\n+/ value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }.join else @@ -124,7 +118,7 @@ module Yahns::HttpResponse # :nodoc: end def have_more?(value) - value.to_i > 0 && @hs.env[REQUEST_METHOD] != HEAD + value.to_i > 0 && @hs.env['REQUEST_METHOD'] != 'HEAD'.freeze end # writes the rack_response to socket as an HTTP response @@ -163,7 +157,8 @@ module Yahns::HttpResponse # :nodoc: buf << kv_str(key, value) end end - buf << (alive ? CONN_KA : CONN_CLOSE) + buf << (alive ? "Connection: keep-alive\r\n\r\n".freeze + : "Connection: close\r\n\r\n".freeze) case rv = kgio_syssend(buf, flags) when nil # all done, likely break diff --git a/lib/yahns/max_body.rb b/lib/yahns/max_body.rb index fadbddc..e52a10f 100644 --- a/lib/yahns/max_body.rb +++ b/lib/yahns/max_body.rb @@ -28,17 +28,13 @@ class Yahns::MaxBody # :nodoc: @limit = limit end - RACK_INPUT = "rack.input".freeze # :nodoc: - CONTENT_LENGTH = "CONTENT_LENGTH" # :nodoc: - HTTP_TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING" # :nodoc: - # our main Rack middleware endpoint def call(env) # :nodoc: catch(:yahns_EFBIG) do - len = env[CONTENT_LENGTH] + len = env['CONTENT_LENGTH'] if len && len.to_i > @limit return err - elsif /\Achunked\z/i =~ env[HTTP_TRANSFER_ENCODING] + elsif /\Achunked\z/i =~ env['HTTP_TRANSFER_ENCODING'] limit_input!(env) end @app.call(env) @@ -51,9 +47,9 @@ class Yahns::MaxBody # :nodoc: end def limit_input!(env) # :nodoc: - input = env[RACK_INPUT] + input = env['rack.input'] klass = input.respond_to?(:rewind) ? RewindableWrapper : Wrapper - env[RACK_INPUT] = klass.new(input, @limit) + env['rack.input'] = klass.new(input, @limit) end end require_relative 'max_body/wrapper' diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb index 61989c2..50c841d 100644 --- a/lib/yahns/proxy_http_response.rb +++ b/lib/yahns/proxy_http_response.rb @@ -64,7 +64,7 @@ module Yahns::HttpResponse # :nodoc: msg = Rack::Utils::HTTP_STATUS_CODES[code] env = @hs.env have_body = !Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(code) && - env[REQUEST_METHOD] != HEAD + env['REQUEST_METHOD'] != 'HEAD'.freeze flags = MSG_DONTWAIT alive = @hs.next? && self.class.persistent_connections response_headers = env['yahns.proxy_pass.response_headers'] @@ -91,7 +91,8 @@ module Yahns::HttpResponse # :nodoc: # For now, do not add a Date: header, assume upstream already did it # but do not care if they did not - res << (alive ? CONN_KA : CONN_CLOSE) + res << (alive ? "Connection: keep-alive\r\n\r\n" + : "Connection: close\r\n\r\n") # send the headers case rv = kgio_syssend(res, flags) -- cgit v1.2.3-24-ge0c7