Skip to content

Commit 85ec945

Browse files
committed
Add test for dead-end backends
The code path for launching a dead-end backend because we're out of slots was not covered by any tests, so add one. (Some tests did hit the case of launching a dead-end backend because the server is still starting up, though, so the gap in our test coverage wasn't as big as it sounds.) Reviewed-by: Andres Freund <andres@anarazel.de> Discussion: https://www.postgresql.org/message-id/a102f15f-eac4-4ff2-af02-f9ff209ec66f@iki.fi
1 parent 6a1d0d4 commit 85ec945

File tree

2 files changed

+119
-1
lines changed

2 files changed

+119
-1
lines changed

src/test/perl/PostgreSQL/Test/Cluster.pm

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ use File::Path qw(rmtree mkpath);
104104
use File::Spec;
105105
use File::stat qw(stat);
106106
use File::Temp ();
107+
use IO::Socket::INET;
107108
use IPC::Run;
108109
use PostgreSQL::Version;
109110
use PostgreSQL::Test::RecursiveCopy;
@@ -291,6 +292,83 @@ sub connstr
291292

292293
=pod
293294
295+
=item $node->raw_connect()
296+
297+
Open a raw TCP or Unix domain socket connection to the server. This is
298+
used by low-level protocol and connection limit tests.
299+
300+
=cut
301+
302+
sub raw_connect
303+
{
304+
my ($self) = @_;
305+
my $pgport = $self->port;
306+
my $pghost = $self->host;
307+
308+
my $socket;
309+
if ($PostgreSQL::Test::Utils::use_unix_sockets)
310+
{
311+
require IO::Socket::UNIX;
312+
my $path = "$pghost/.s.PGSQL.$pgport";
313+
314+
$socket = IO::Socket::UNIX->new(
315+
Type => SOCK_STREAM(),
316+
Peer => $path,
317+
) or die "Cannot create socket - $IO::Socket::errstr\n";
318+
}
319+
else
320+
{
321+
$socket = IO::Socket::INET->new(
322+
PeerHost => $pghost,
323+
PeerPort => $pgport,
324+
Proto => 'tcp'
325+
) or die "Cannot create socket - $IO::Socket::errstr\n";
326+
}
327+
return $socket;
328+
}
329+
330+
=pod
331+
332+
=item $node->raw_connect_works()
333+
334+
Check if raw_connect() function works on this platform. This should
335+
be called to SKIP any tests that require raw_connect().
336+
337+
This tries to connect to the server, to test whether it works or not,,
338+
so the server is up and running. Otherwise this can return 0 even if
339+
there's nothing wrong with raw_connect() itself.
340+
341+
Notably, raw_connect() does not work on Unix domain sockets on
342+
Strawberry perl 5.26.3.1 on Windows, which we use in Cirrus CI images
343+
as of this writing. It dies with "not implemented on this
344+
architecture".
345+
346+
=cut
347+
348+
sub raw_connect_works
349+
{
350+
my ($self) = @_;
351+
352+
# If we're using Unix domain sockets, we need a working
353+
# IO::Socket::UNIX implementation.
354+
if ($PostgreSQL::Test::Utils::use_unix_sockets)
355+
{
356+
diag "checking if IO::Socket::UNIX works";
357+
eval {
358+
my $sock = $self->raw_connect();
359+
$sock->close();
360+
};
361+
if ($@ =~ /not implemented/)
362+
{
363+
diag "IO::Socket::UNIX does not work: $@";
364+
return 0;
365+
}
366+
}
367+
return 1
368+
}
369+
370+
=pod
371+
294372
=item $node->group_access()
295373
296374
Does the data dir allow group access?

src/test/postmaster/t/001_connection_limits.pl

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ sub background_psql_as_user
4343
}
4444

4545
my @sessions = ();
46+
my @raw_connections = ();
4647

4748
push(@sessions, background_psql_as_user('regress_regular'));
4849
push(@sessions, background_psql_as_user('regress_regular'));
@@ -69,11 +70,50 @@ sub background_psql_as_user
6970
"superuser_reserved_connections limit",
7071
expected_stderr => qr/FATAL: sorry, too many clients already/);
7172

72-
# TODO: test that query cancellation is still possible
73+
# We can still open TCP (or Unix domain socket) connections, but
74+
# beyond a certain number (roughly 2x max_connections), they will be
75+
# "dead-end backends".
76+
SKIP:
77+
{
78+
skip "this test requies working raw_connect()" unless $node->raw_connect_works();
79+
80+
for (my $i = 0; $i <= 20; $i++)
81+
{
82+
my $sock = $node->raw_connect();
83+
84+
# On a busy system, the server might reject connections if
85+
# postmaster cannot accept() them fast enough. The exact limit
86+
# and behavior depends on the platform. To make this reliable,
87+
# we attempt SSL negotiation on each connection before opening
88+
# next one. The server will reject the SSL negotations, but
89+
# when it does so, we know that the backend has been launched
90+
# and we should be able to open another connection.
91+
92+
# SSLRequest packet consists of packet length followed by
93+
# NEGOTIATE_SSL_CODE.
94+
my $negotiate_ssl_code = pack("Nnn", 8, 1234, 5679);
95+
my $sent = $sock->send($negotiate_ssl_code);
96+
97+
# Read reply. We expect the server to reject it with 'N'
98+
my $reply = "";
99+
$sock->recv($reply, 1);
100+
is($reply, "N", "dead-end connection $i");
73101

102+
push(@raw_connections, $sock);
103+
}
104+
}
105+
106+
# TODO: test that query cancellation is still possible. A dead-end
107+
# backend can process a query cancellation packet.
108+
109+
# Clean up
74110
foreach my $session (@sessions)
75111
{
76112
$session->quit;
77113
}
114+
foreach my $socket (@raw_connections)
115+
{
116+
$socket->close();
117+
}
78118

79119
done_testing();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy