Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4b9013d

Browse files
committed
Prevent port collisions between concurrent TAP tests
Currently there is a race condition where if concurrent TAP tests bothtest that they can open a port they will assume that it is free and useit, causing one of them to fail. To prevent this we record a reservationusing an exclusive lock, and any TAP test that discovers a reservationchecks to see if the reserving process is still alive, and looks foranother free port if it is.Ports are reserved in a directory set by the environment settingPG_TEST_PORT_DIR, or if that doesn't exist a subdirectory of the topbuild directory as set by Makefile.global, or its owntmp_check directory.The prove_check recipe in Makefile.global.in is extended to exporttop_builddir to the TAP tests. This was already exported by theprove_installcheck recipes.Per complaint from Andres FreundBackpatched from9b4eafc to all live branchesDiscussion:https://postgr.es/m/20221002164931.d57hlutrcz4d2zi7@awork3.anarazel.de
1 parent36eeb37 commit4b9013d

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

‎src/Makefile.global.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ rm -rf '$(CURDIR)'/tmp_check
471471
$(MKDIR_P) '$(CURDIR)'/tmp_check
472472
cd$(srcdir) && \
473473
TESTDIR='$(CURDIR)'$(with_temp_install) PGPORT='6$(DEF_PGPORT)' \
474+
top_builddir='$(CURDIR)/$(top_builddir)' \
474475
PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' \
475476
$(PROVE)$(PG_PROVE_FLAGS)$(PROVE_FLAGS)$(if$(PROVE_TESTS),$(PROVE_TESTS),t/*.pl)
476477
endef

‎src/test/perl/PostgresNode.pm

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ use Carp;
9090
use Config;
9191
use Cwd;
9292
use Exporter'import';
93-
use Fcntlqw(:mode);
93+
use Fcntlqw(:mode :flock :seek :DEFAULT);
9494
use File::Basename;
95-
use File::Pathqw(rmtree);
95+
use File::Pathqw(rmtree mkpath);
9696
use File::Spec;
9797
use File::statqw(stat);
9898
use File::Temp ();
@@ -110,7 +110,10 @@ our @EXPORT = qw(
110110
);
111111

112112
our ($use_tcp,$test_localhost,$test_pghost,$last_host_assigned,
113-
$last_port_assigned,@all_nodes,$died);
113+
$last_port_assigned,@all_nodes,$died,$portdir);
114+
115+
# list of file reservations made by get_free_port
116+
my@port_reservation_files;
114117

115118
INIT
116119
{
@@ -126,6 +129,20 @@ INIT
126129

127130
# Tracking of last port value assigned to accelerate free port lookup.
128131
$last_port_assigned =int(rand() * 16384) + 49152;
132+
133+
# Set the port lock directory
134+
135+
# If we're told to use a directory (e.g. from a buildfarm client)
136+
# explicitly, use that
137+
$portdir =$ENV{PG_TEST_PORT_DIR};
138+
# Otherwise, try to use a directory at the top of the build tree
139+
# or as a last resort use the tmp_check directory
140+
my$build_dir =$ENV{top_builddir}
141+
||$TestLib::tmp_check ;
142+
$portdir ||="$build_dir/portlock";
143+
$portdir =~s!\\!/!g;
144+
# Make sure the directory exists
145+
mkpath($portdir)unless-d$portdir;
129146
}
130147

131148
=pod
@@ -1210,8 +1227,8 @@ by test cases that need to start other, non-Postgres servers.
12101227
Ports assigned to existing PostgresNode objects are automatically
12111228
excluded, even if those servers are not currently running.
12121229
1213-
XXX Aportavailable now may become unavailable by the time we start
1214-
thedesired service.
1230+
Theportnumber is reserved so that other concurrent test programs will not
1231+
try to usethesame port.
12151232
12161233
=cut
12171234

@@ -1260,6 +1277,7 @@ sub get_free_port
12601277
last;
12611278
}
12621279
}
1280+
$found = _reserve_port($port)if$found;
12631281
}
12641282
}
12651283

@@ -1290,6 +1308,40 @@ sub can_bind
12901308
return$ret;
12911309
}
12921310

1311+
# Internal routine to reserve a port number
1312+
# Returns 1 if successful, 0 if port is already reserved.
1313+
sub_reserve_port
1314+
{
1315+
my$port =shift;
1316+
# open in rw mode so we don't have to reopen it and lose the lock
1317+
my$filename ="$portdir/$port.rsv";
1318+
sysopen(my$portfile,$filename, O_RDWR|O_CREAT)
1319+
||die"opening port file$filename:$!";
1320+
# take an exclusive lock to avoid concurrent access
1321+
flock($portfile, LOCK_EX) ||die"locking port file$filename:$!";
1322+
# see if someone else has or had a reservation of this port
1323+
my$pid = <$portfile>;
1324+
chomp$pid;
1325+
if ($pid +0 > 0)
1326+
{
1327+
if (kill 0,$pid)
1328+
{
1329+
# process exists and is owned by us, so we can't reserve this port
1330+
flock($portfile, LOCK_UN);
1331+
close($portfile);
1332+
return 0;
1333+
}
1334+
}
1335+
# All good, go ahead and reserve the port
1336+
seek($portfile, 0, SEEK_SET);
1337+
# print the pid with a fixed width so we don't leave any trailing junk
1338+
print$portfilesprintf("%10d\n",$$);
1339+
flock($portfile, LOCK_UN);
1340+
close($portfile);
1341+
push(@port_reservation_files,$filename);
1342+
return 1;
1343+
}
1344+
12931345
# Automatically shut down any still-running nodes when the test script exits.
12941346
# Note that this just stops the postmasters (in the same order the nodes were
12951347
# created in). Any temporary directories are deleted, in an unspecified
@@ -1311,6 +1363,8 @@ END
13111363
$node->clean_nodeif$exit_code == 0 && TestLib::all_tests_passing();
13121364
}
13131365

1366+
unlink@port_reservation_files;
1367+
13141368
$? =$exit_code;
13151369
}
13161370

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp