module PG::Connection::Pollable

def polling_loop(poll_meth)

The downside is that this connects only once to hosts which are listed twice when they timeout.

- When a timeout occurs, connecting is restarted with the remaining hosts.
- When the polling status changes to `PG::PGRES_POLLING_FAILED` connecting is aborted and a PG::ConnectionBad is raised with details to all connection attepts.
- When the polling status changes to `PG::PGRES_POLLING_OK` the connection is returned and ready to use.
- As soon as the host is tried to connect the related host is removed from the hosts list
- All hosts are passed to PG::Connection.connect_start
Connecting to multiple hosts is done like so:

Track the progress of the connection, waiting for the socket to become readable/writable before polling it.
def polling_loop(poll_meth)
_timeout = conninfo_hash[:connect_timeout]
eo = connect_timeout.to_i) && timeo > 0
ount = (conninfo_hash[:hostaddr].to_s.empty? ? conninfo_hash[:host] : conninfo_hash[:hostaddr]).to_s.count(",") + 1
ime = timeo * host_count + Process.clock_gettime(Process::CLOCK_MONOTONIC)
 conninfo_hash.compact
ion_errors = []
atus = PG::PGRES_POLLING_WRITING
oll_status == PG::PGRES_POLLING_OK ||
status == PG::PGRES_POLLING_FAILED
single timeout to parameter "connect_timeout" but
t exceed total connection time of number-of-hosts * connect_timeout.
t = [timeo, stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)].min if stop_time
t = remove_current_host(iopts)
= if !timeout || timeout >= 0
the socket needs to read, wait 'til it becomes readable to poll again
poll_status
PG::PGRES_POLLING_READING
efined?(IO::READABLE) # ruby-3.0+
ket_io.wait(IO::READABLE | IO::PRIORITY, timeout)

select([socket_io], nil, [socket_io], timeout)
and the same for when the socket needs to write
PG::PGRES_POLLING_WRITING
efined?(IO::WRITABLE) # ruby-3.0+
se wait instead of wait_readable, since connection errors are delivered as
xceptional/priority events on Windows.
ket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout)

o#wait on ruby-2.x doesn't wait for priority, so fallback to IO.select
select(nil, [socket_io], [socket_io], timeout)
ection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad)
ection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory
 event
ction_errors << (error_message + "timeout expired")
stcnt > 0
t_start2(self.class.parse_connect_args(iopts))
start polling with waiting for writable.
herwise "not connected" error is raised on Windows.
_status = PG::PGRES_POLLING_WRITING

sh
e PG::ConnectionBad.new(connection_errors.join("\n").b, connection: self)
k to see if it's finished or failed yet
tatus = send( poll_meth )
status == PG::CONNECTION_OK
error_message

PG::ConnectionBad.new(connection_errors.map{|e| e + "\n" }.join.b + msg, connection: self)

def remove_current_host(iopts)

Return the number of remaining hosts.

- :port
- :hostaddr
- :host
Affected options are:
Remove the host to which the connection is currently established from the option hash.
def remove_current_host(iopts)
= iopts[:host]&.split(",", -1)
drs = iopts[:hostaddr]&.split(",", -1)
= iopts[:port]&.split(",", -1)
= iports * (ihosts || ihostaddrs || [1]).size if iports&.size == 1
ihosts || ihostaddrs || iports).index.with_index do |_, i|
s ? ihosts[i] == host : true) &&
addrs && respond_to?(:hostaddr, true) ? ihostaddrs[i] == hostaddr : true) &&
s ? iports[i].to_i == port : true)
&.delete_at(idx)
ddrs&.delete_at(idx)
&.delete_at(idx)
merge!(
 ihosts.join(",")) if ihosts
merge!(
ddr: ihostaddrs.join(",")) if ihostaddrs
merge!(
 iports.join(",")) if iports
 || ihostaddrs || iports).size