out with eden connections, keep closed around

connection bookkeeping on the pool changes, where all conections are kept around, even the ones that close during the scope of the requests; new requests may then find them, reset them, an reselect them. this is a major improvement, as objects get more reused, so less gc and object movement. this also changes the way pool terminates, as connections nonw follow a termination protocol, instead of just closing (which they can while scope is open)
This commit is contained in:
HoneyryderChuck 2023-11-09 18:11:16 +00:00
parent b24ed83a8b
commit ce7eb0b91a
10 changed files with 35 additions and 33 deletions

View File

@ -231,6 +231,12 @@ module HTTPX
@parser.close if @parser
end
def terminate
@connected_at = nil if @state == :closed
close
end
# bypasses the state machine to force closing of connections still connecting.
# **only** used for Happy Eyeballs v2.
def force_reset
@ -580,14 +586,14 @@ module HTTPX
when :inactive
return unless @state == :open
when :closing
return unless @state == :open
return unless @state == :idle || @state == :open
when :closed
return unless @state == :closing
return unless @write_buffer.empty?
purge_after_closed
emit(:close)
emit(:close) if @pending.empty?
when :already_open
nextstate = :open
# the first check for given io readiness must still use a timeout.

View File

@ -73,11 +73,11 @@ module HTTPX
end
def close
emit(:close)
unless @connection.state == :closed
@connection.goaway
emit(:timeout, @options.timeout[:close_handshake_timeout])
end
emit(:close, true)
end
def empty?

View File

@ -17,8 +17,6 @@ module HTTPX
@timers = Timers.new
@selector = Selector.new
@connections = []
@eden_connections = []
@connected_connections = 0
end
def empty?
@ -52,9 +50,8 @@ module HTTPX
def close(connections = @connections)
return if connections.empty?
@eden_connections.clear
connections = connections.reject(&:inflight?)
connections.each(&:close)
connections.each(&:terminate)
next_tick until connections.none? { |c| c.state != :idle && @connections.include?(c) }
# close resolvers
@ -68,16 +65,13 @@ module HTTPX
resolver.close unless resolver.closed?
end
# for https resolver
resolver_connections.each(&:close)
resolver_connections.each(&:terminate)
next_tick until resolver_connections.none? { |c| c.state != :idle && @connections.include?(c) }
end
def init_connection(connection, _options)
resolve_connection(connection) unless connection.family
connection.timers = @timers
connection.on(:open) do
@connected_connections += 1
end
connection.on(:activate) do
select_connection(connection)
end
@ -98,6 +92,9 @@ module HTTPX
connection.on(:close) do
unregister_connection(connection)
end
connection.on(:terminate) do
unregister_connection(connection, true)
end
end
def deactivate(connections)
@ -116,16 +113,15 @@ module HTTPX
connection.match?(uri, options)
end
unless conn
@eden_connections.delete_if do |connection|
is_expired = connection.expired?
conn = connection if conn.nil? && !is_expired && connection.match?(uri, options)
is_expired
end
return unless conn
if conn
case conn.state
when :closed
conn.idling
select_connection(conn)
when :closing
conn.once(:close) do
conn.idling
@connections << conn
select_connection(conn)
end
end
@ -232,18 +228,12 @@ module HTTPX
end
def register_connection(connection)
if connection.state == :open
# if open, an IO was passed upstream, therefore
# consider it connected already.
@connected_connections += 1
end
select_connection(connection)
end
def unregister_connection(connection)
@connections.delete(connection)
@eden_connections << connection if connection.used? && !@eden_connections.include?(connection)
@connected_connections -= 1 if deselect_connection(connection)
def unregister_connection(connection, cleanup = !connection.used?)
@connections.delete(connection) if cleanup
deselect_connection(connection)
end
def select_connection(connection)

View File

@ -27,7 +27,7 @@ module HTTPX
use_get: false,
}.freeze
def_delegators :@resolver_connection, :state, :connecting?, :to_io, :call, :close
def_delegators :@resolver_connection, :state, :connecting?, :to_io, :call, :close, :terminate
def initialize(_, options)
super

View File

@ -38,6 +38,8 @@ module HTTPX
def close; end
alias_method :terminate, :close
def closed?
true
end

View File

@ -201,6 +201,7 @@ module HTTPX
end
connection.merge(existing_connection)
existing_connection.terminate
connection
rescue UnsupportedSchemeError
altsvc["noop"] = true

View File

@ -74,6 +74,8 @@ module HTTPX
def call: () -> void
def terminate: () -> void
def close: () -> void
def reset: () -> void

View File

@ -6,8 +6,6 @@ module HTTPX
@timers: Timers
@selector: Selector
@connections: Array[Connection]
@eden_connections: Array[Connection]
@connected_connections: Integer
def empty?: () -> void
@ -37,7 +35,7 @@ module HTTPX
def register_connection: (Connection) -> void
def unregister_connection: (Connection) -> void
def unregister_connection: (Connection, ?bool cleanup) -> void
def select_connection: (Selector::selectable) -> void

View File

@ -14,6 +14,8 @@ module HTTPX
def close: () -> void
alias terminate close
def closed?: () -> bool
def empty?: () -> bool

View File

@ -54,7 +54,8 @@ module Requests
HTTPX.plugin(SessionWithPool).plugin(ResponseErrorEmitter).wrap do |http|
response = http.get(uri)
verify_error_response(response, "done with it")
assert http.pool.connections.empty?
assert http.pool.connections.size == 1
assert http.pool.connections.first.state == :closed
end
end
end