]> git.ipfire.org Git - thirdparty/postgresql.git/blob
406c405
[thirdparty/postgresql.git] /
1
2 # Copyright (c) 2021-2024, PostgreSQL Global Development Group
3
4 =pod
5
6 =head1 NAME
7
8 PostgreSQL::Test::Cluster - class representing PostgreSQL server instance
9
10 =head1 SYNOPSIS
11
12 use PostgreSQL::Test::Cluster;
13
14 my $node = PostgreSQL::Test::Cluster->new('mynode');
15
16 # Create a data directory with initdb
17 $node->init();
18
19 # Start the PostgreSQL server
20 $node->start();
21
22 # Add a setting and restart
23 $node->append_conf('postgresql.conf', 'hot_standby = on');
24 $node->restart();
25
26 # Modify or delete an existing setting
27 $node->adjust_conf('postgresql.conf', 'max_wal_senders', '10');
28
29 # get pg_config settings
30 # all the settings in one string
31 $pgconfig = $node->config_data;
32 # all the settings as a map
33 %config_map = ($node->config_data);
34 # specified settings
35 ($incdir, $sharedir) = $node->config_data(qw(--includedir --sharedir));
36
37 # run a query with psql, like:
38 # echo 'SELECT 1' | psql -qAXt postgres -v ON_ERROR_STOP=1
39 $psql_stdout = $node->safe_psql('postgres', 'SELECT 1');
40
41 # Run psql with a timeout, capturing stdout and stderr
42 # as well as the psql exit code. Pass some extra psql
43 # options. If there's an error from psql raise an exception.
44 my ($stdout, $stderr, $timed_out);
45 my $cmdret = $node->psql('postgres', 'SELECT pg_sleep(600)',
46 stdout => \$stdout, stderr => \$stderr,
47 timeout => $PostgreSQL::Test::Utils::timeout_default,
48 timed_out => \$timed_out,
49 extra_params => ['--single-transaction'],
50 on_error_die => 1)
51 print "Sleep timed out" if $timed_out;
52
53 # Similar thing, more convenient in common cases
54 my ($cmdret, $stdout, $stderr) =
55 $node->psql('postgres', 'SELECT 1');
56
57 # run query every second until it returns 't'
58 # or times out
59 $node->poll_query_until('postgres', q|SELECT random() < 0.1;|')
60 or die "timed out";
61
62 # Do an online pg_basebackup
63 my $ret = $node->backup('testbackup1');
64
65 # Take a backup of a running server
66 my $ret = $node->backup_fs_hot('testbackup2');
67
68 # Take a backup of a stopped server
69 $node->stop;
70 my $ret = $node->backup_fs_cold('testbackup3')
71
72 # Restore it to create a new independent node (not a replica)
73 my $other_node = PostgreSQL::Test::Cluster->new('mycopy');
74 $other_node->init_from_backup($node, 'testbackup');
75 $other_node->start;
76
77 # Stop the server
78 $node->stop('fast');
79
80 # Find a free, unprivileged TCP port to bind some other service to
81 my $port = PostgreSQL::Test::Cluster::get_free_port();
82
83 =head1 DESCRIPTION
84
85 PostgreSQL::Test::Cluster contains a set of routines able to work on a PostgreSQL node,
86 allowing to start, stop, backup and initialize it with various options.
87 The set of nodes managed by a given test is also managed by this module.
88
89 In addition to node management, PostgreSQL::Test::Cluster instances have some wrappers
90 around Test::More functions to run commands with an environment set up to
91 point to the instance.
92
93 The IPC::Run module is required.
94
95 =cut
96
97 package PostgreSQL::Test::Cluster;
98
99 use strict;
100 use warnings FATAL => 'all';
101
102 use Carp;
103 use Config;
104 use Fcntl qw(:mode :flock :seek :DEFAULT);
105 use File::Basename;
106 use File::Path qw(rmtree mkpath);
107 use File::Spec;
108 use File::stat qw(stat);
109 use File::Temp ();
110 use IPC::Run;
111 use PostgreSQL::Version;
112 use PostgreSQL::Test::RecursiveCopy;
113 use Socket;
114 use Test::More;
115 use PostgreSQL::Test::Utils ();
116 use PostgreSQL::Test::BackgroundPsql ();
117 use Time::HiRes qw(usleep);
118 use Scalar::Util qw(blessed);
119
120 our ($use_tcp, $test_localhost, $test_pghost, $last_host_assigned,
121 $last_port_assigned, @all_nodes, $died, $portdir);
122
123 # the minimum version we believe to be compatible with this package without
124 # subclassing.
125 our $min_compat = 12;
126
127 # list of file reservations made by get_free_port
128 my @port_reservation_files;
129
130 INIT
131 {
132
133 # Set PGHOST for backward compatibility. This doesn't work for own_host
134 # nodes, so prefer to not rely on this when writing new tests.
135 $use_tcp = !$PostgreSQL::Test::Utils::use_unix_sockets;
136 $test_localhost = "127.0.0.1";
137 $last_host_assigned = 1;
138 if ($use_tcp)
139 {
140 $test_pghost = $test_localhost;
141 }
142 else
143 {
144 # On windows, replace windows-style \ path separators with / when
145 # putting socket directories either in postgresql.conf or libpq
146 # connection strings, otherwise they are interpreted as escapes.
147 $test_pghost = PostgreSQL::Test::Utils::tempdir_short;
148 $test_pghost =~ s!\\!/!g if $PostgreSQL::Test::Utils::windows_os;
149 }
150 $ENV{PGHOST} = $test_pghost;
151 $ENV{PGDATABASE} = 'postgres';
152
153 # Tracking of last port value assigned to accelerate free port lookup.
154 $last_port_assigned = int(rand() * 16384) + 49152;
155
156 # Set the port lock directory
157
158 # If we're told to use a directory (e.g. from a buildfarm client)
159 # explicitly, use that
160 $portdir = $ENV{PG_TEST_PORT_DIR};
161 # Otherwise, try to use a directory at the top of the build tree
162 # or as a last resort use the tmp_check directory
163 my $build_dir =
164 $ENV{MESON_BUILD_ROOT}
165 || $ENV{top_builddir}
166 || $PostgreSQL::Test::Utils::tmp_check;
167 $portdir ||= "$build_dir/portlock";
168 $portdir =~ s!\\!/!g;
169 # Make sure the directory exists
170 mkpath($portdir) unless -d $portdir;
171 }
172
173 =pod
174
175 =head1 METHODS
176
177 =over
178
179 =item $node->port()
180
181 Get the port number assigned to the host. This won't necessarily be a TCP port
182 open on the local host since we prefer to use unix sockets if possible.
183
184 Use $node->connstr() if you want a connection string.
185
186 =cut
187
188 sub port
189 {
190 my ($self) = @_;
191 return $self->{_port};
192 }
193
194 =pod
195
196 =item $node->host()
197
198 Return the host (like PGHOST) for this instance. May be a UNIX socket path.
199
200 Use $node->connstr() if you want a connection string.
201
202 =cut
203
204 sub host
205 {
206 my ($self) = @_;
207 return $self->{_host};
208 }
209
210 =pod
211
212 =item $node->basedir()
213
214 The directory all the node's files will be within - datadir, archive directory,
215 backups, etc.
216
217 =cut
218
219 sub basedir
220 {
221 my ($self) = @_;
222 return $self->{_basedir};
223 }
224
225 =pod
226
227 =item $node->name()
228
229 The name assigned to the node at creation time.
230
231 =cut
232
233 sub name
234 {
235 my ($self) = @_;
236 return $self->{_name};
237 }
238
239 =pod
240
241 =item $node->logfile()
242
243 Path to the PostgreSQL log file for this instance.
244
245 =cut
246
247 sub logfile
248 {
249 my ($self) = @_;
250 return $self->{_logfile};
251 }
252
253 =pod
254
255 =item $node->connstr()
256
257 Get a libpq connection string that will establish a connection to
258 this node. Suitable for passing to psql, DBD::Pg, etc.
259
260 =cut
261
262 sub connstr
263 {
264 my ($self, $dbname) = @_;
265 my $pgport = $self->port;
266 my $pghost = $self->host;
267 if (!defined($dbname))
268 {
269 return "port=$pgport host=$pghost";
270 }
271
272 # Escape properly the database string before using it, only
273 # single quotes and backslashes need to be treated this way.
274 $dbname =~ s#\\#\\\\#g;
275 $dbname =~ s#\'#\\\'#g;
276
277 return "port=$pgport host=$pghost dbname='$dbname'";
278 }
279
280 =pod
281
282 =item $node->group_access()
283
284 Does the data dir allow group access?
285
286 =cut
287
288 sub group_access
289 {
290 my ($self) = @_;
291
292 my $dir_stat = stat($self->data_dir);
293
294 defined($dir_stat)
295 or die('unable to stat ' . $self->data_dir);
296
297 return (S_IMODE($dir_stat->mode) == 0750);
298 }
299
300 =pod
301
302 =item $node->data_dir()
303
304 Returns the path to the data directory. postgresql.conf and pg_hba.conf are
305 always here.
306
307 =cut
308
309 sub data_dir
310 {
311 my ($self) = @_;
312 my $res = $self->basedir;
313 return "$res/pgdata";
314 }
315
316 =pod
317
318 =item $node->archive_dir()
319
320 If archiving is enabled, WAL files go here.
321
322 =cut
323
324 sub archive_dir
325 {
326 my ($self) = @_;
327 my $basedir = $self->basedir;
328 return "$basedir/archives";
329 }
330
331 =pod
332
333 =item $node->backup_dir()
334
335 The output path for backups taken with $node->backup()
336
337 =cut
338
339 sub backup_dir
340 {
341 my ($self) = @_;
342 my $basedir = $self->basedir;
343 return "$basedir/backup";
344 }
345
346 =pod
347
348 =item $node->install_path()
349
350 The configured install path (if any) for the node.
351
352 =cut
353
354 sub install_path
355 {
356 my ($self) = @_;
357 return $self->{_install_path};
358 }
359
360 =pod
361
362 =item $node->pg_version()
363
364 The version number for the node, from PostgreSQL::Version.
365
366 =cut
367
368 sub pg_version
369 {
370 my ($self) = @_;
371 return $self->{_pg_version};
372 }
373
374 =pod
375
376 =item $node->config_data( option ...)
377
378 Return configuration data from pg_config, using options (if supplied).
379 The options will be things like '--sharedir'.
380
381 If no options are supplied, return a string in scalar context or a map in
382 array context.
383
384 If options are supplied, return the list of values.
385
386 =cut
387
388 sub config_data
389 {
390 my ($self, @options) = @_;
391 local %ENV = $self->_get_env();
392
393 my ($stdout, $stderr);
394 my $result =
395 IPC::Run::run [ $self->installed_command('pg_config'), @options ],
396 '>', \$stdout, '2>', \$stderr
397 or die "could not execute pg_config";
398 # standardize line endings
399 $stdout =~ s/\r(?=\n)//g;
400 # no options, scalar context: just hand back the output
401 return $stdout unless (wantarray || @options);
402 chomp($stdout);
403 # exactly one option: hand back the output (minus LF)
404 return $stdout if (@options == 1);
405 my @lines = split(/\n/, $stdout);
406 # more than one option: hand back the list of values;
407 return @lines if (@options);
408 # no options, array context: return a map
409 my @map;
410 foreach my $line (@lines)
411 {
412 my ($k, $v) = split(/ = /, $line, 2);
413 push(@map, $k, $v);
414 }
415 return @map;
416 }
417
418 =pod
419
420 =item $node->info()
421
422 Return a string containing human-readable diagnostic information (paths, etc)
423 about this node.
424
425 =cut
426
427 sub info
428 {
429 my ($self) = @_;
430 my $_info = '';
431 open my $fh, '>', \$_info or die;
432 print $fh "Name: " . $self->name . "\n";
433 print $fh "Version: " . $self->{_pg_version} . "\n"
434 if $self->{_pg_version};
435 print $fh "Data directory: " . $self->data_dir . "\n";
436 print $fh "Backup directory: " . $self->backup_dir . "\n";
437 print $fh "Archive directory: " . $self->archive_dir . "\n";
438 print $fh "Connection string: " . $self->connstr . "\n";
439 print $fh "Log file: " . $self->logfile . "\n";
440 print $fh "Install Path: ", $self->{_install_path} . "\n"
441 if $self->{_install_path};
442 close $fh or die;
443 return $_info;
444 }
445
446 =pod
447
448 =item $node->dump_info()
449
450 Print $node->info()
451
452 =cut
453
454 sub dump_info
455 {
456 my ($self) = @_;
457 print $self->info;
458 return;
459 }
460
461
462 # Internal method to set up trusted pg_hba.conf for replication. Not
463 # documented because you shouldn't use it, it's called automatically if needed.
464 sub set_replication_conf
465 {
466 my ($self) = @_;
467 my $pgdata = $self->data_dir;
468
469 $self->host eq $test_pghost
470 or croak "set_replication_conf only works with the default host";
471
472 open my $hba, '>>', "$pgdata/pg_hba.conf";
473 print $hba
474 "\n# Allow replication (set up by PostgreSQL::Test::Cluster.pm)\n";
475 if ($PostgreSQL::Test::Utils::windows_os
476 && !$PostgreSQL::Test::Utils::use_unix_sockets)
477 {
478 print $hba
479 "host replication all $test_localhost/32 sspi include_realm=1 map=regress\n";
480 }
481 close $hba;
482 return;
483 }
484
485 =pod
486
487 =item $node->init(...)
488
489 Initialize a new cluster for testing.
490
491 Authentication is set up so that only the current OS user can access the
492 cluster. On Unix, we use Unix domain socket connections, with the socket in
493 a directory that's only accessible to the current user to ensure that.
494 On Windows, we use SSPI authentication to ensure the same (by pg_regress
495 --config-auth).
496
497 WAL archiving can be enabled on this node by passing the keyword parameter
498 has_archiving => 1. This is disabled by default.
499
500 postgresql.conf can be set up for replication by passing the keyword
501 parameter allows_streaming => 'logical' or 'physical' (passing 1 will also
502 suffice for physical replication) depending on type of replication that
503 should be enabled. This is disabled by default.
504
505 The new node is set up in a fast but unsafe configuration where fsync is
506 disabled.
507
508 =cut
509
510 sub init
511 {
512 my ($self, %params) = @_;
513 my $port = $self->port;
514 my $pgdata = $self->data_dir;
515 my $host = $self->host;
516
517 local %ENV = $self->_get_env();
518
519 $params{allows_streaming} = 0 unless defined $params{allows_streaming};
520 $params{has_archiving} = 0 unless defined $params{has_archiving};
521
522 mkdir $self->backup_dir;
523 mkdir $self->archive_dir;
524
525 # If available and if there aren't any parameters, use a previously
526 # initdb'd cluster as a template by copying it. For a lot of tests, that's
527 # substantially cheaper. Do so only if there aren't parameters, it doesn't
528 # seem worth figuring out whether they affect compatibility.
529 #
530 # There's very similar code in pg_regress.c, but we can't easily
531 # deduplicate it until we require perl at build time.
532 if (defined $params{extra} or !defined $ENV{INITDB_TEMPLATE})
533 {
534 note("initializing database system by running initdb");
535 PostgreSQL::Test::Utils::system_or_bail('initdb', '-D', $pgdata, '-A',
536 'trust', '-N', @{ $params{extra} });
537 }
538 else
539 {
540 my @copycmd;
541 my $expected_exitcode;
542
543 note("initializing database system by copying initdb template");
544
545 if ($PostgreSQL::Test::Utils::windows_os)
546 {
547 @copycmd = qw(robocopy /E /NJS /NJH /NFL /NDL /NP);
548 $expected_exitcode = 1; # 1 denotes files were copied
549 }
550 else
551 {
552 @copycmd = qw(cp -RPp);
553 $expected_exitcode = 0;
554 }
555
556 @copycmd = (@copycmd, $ENV{INITDB_TEMPLATE}, $pgdata);
557
558 my $ret = PostgreSQL::Test::Utils::system_log(@copycmd);
559
560 # See http://perldoc.perl.org/perlvar.html#%24CHILD_ERROR
561 if ($ret & 127 or $ret >> 8 != $expected_exitcode)
562 {
563 BAIL_OUT(
564 sprintf("failed to execute command \"%s\": $ret",
565 join(" ", @copycmd)));
566 }
567 }
568
569 PostgreSQL::Test::Utils::system_or_bail($ENV{PG_REGRESS},
570 '--config-auth', $pgdata, @{ $params{auth_extra} });
571
572 open my $conf, '>>', "$pgdata/postgresql.conf";
573 print $conf "\n# Added by PostgreSQL::Test::Cluster.pm\n";
574 print $conf "fsync = off\n";
575 print $conf "restart_after_crash = off\n";
576 print $conf "log_line_prefix = '%m [%p] %q%a '\n";
577 print $conf "log_statement = all\n";
578 print $conf "log_replication_commands = on\n";
579 print $conf "wal_retrieve_retry_interval = '500ms'\n";
580
581 # If a setting tends to affect whether tests pass or fail, print it after
582 # TEMP_CONFIG. Otherwise, print it before TEMP_CONFIG, thereby permitting
583 # overrides. Settings that merely improve performance or ease debugging
584 # belong before TEMP_CONFIG.
585 print $conf PostgreSQL::Test::Utils::slurp_file($ENV{TEMP_CONFIG})
586 if defined $ENV{TEMP_CONFIG};
587
588 if ($params{allows_streaming})
589 {
590 if ($params{allows_streaming} eq "logical")
591 {
592 print $conf "wal_level = logical\n";
593 }
594 else
595 {
596 print $conf "wal_level = replica\n";
597 }
598 print $conf "max_wal_senders = 10\n";
599 print $conf "max_replication_slots = 10\n";
600 print $conf "wal_log_hints = on\n";
601 print $conf "hot_standby = on\n";
602 # conservative settings to ensure we can run multiple postmasters:
603 print $conf "shared_buffers = 1MB\n";
604 print $conf "max_connections = 10\n";
605 # limit disk space consumption, too:
606 print $conf "max_wal_size = 128MB\n";
607 }
608 else
609 {
610 print $conf "wal_level = minimal\n";
611 print $conf "max_wal_senders = 0\n";
612 }
613
614 print $conf "port = $port\n";
615 if ($use_tcp)
616 {
617 print $conf "unix_socket_directories = ''\n";
618 print $conf "listen_addresses = '$host'\n";
619 }
620 else
621 {
622 print $conf "unix_socket_directories = '$host'\n";
623 print $conf "listen_addresses = ''\n";
624 }
625 close $conf;
626
627 chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
628 or die("unable to set permissions for $pgdata/postgresql.conf");
629
630 $self->set_replication_conf if $params{allows_streaming};
631 $self->enable_archiving if $params{has_archiving};
632 return;
633 }
634
635 =pod
636
637 =item $node->append_conf(filename, str)
638
639 A shortcut method to append to files like pg_hba.conf and postgresql.conf.
640
641 Does no validation or sanity checking. Does not reload the configuration
642 after writing.
643
644 A newline is automatically appended to the string.
645
646 =cut
647
648 sub append_conf
649 {
650 my ($self, $filename, $str) = @_;
651
652 my $conffile = $self->data_dir . '/' . $filename;
653
654 PostgreSQL::Test::Utils::append_to_file($conffile, $str . "\n");
655
656 chmod($self->group_access() ? 0640 : 0600, $conffile)
657 or die("unable to set permissions for $conffile");
658
659 return;
660 }
661
662 =pod
663
664 =item $node->adjust_conf(filename, setting, value, skip_equals)
665
666 Modify the named config file setting with the value. If the value is undefined,
667 instead delete the setting. If the setting is not present no action is taken.
668
669 This will write "$setting = $value\n" in place of the existing line,
670 unless skip_equals is true, in which case it will write
671 "$setting $value\n". If the value needs to be quoted it is the caller's
672 responsibility to do that.
673
674 =cut
675
676 sub adjust_conf
677 {
678 my ($self, $filename, $setting, $value, $skip_equals) = @_;
679
680 my $conffile = $self->data_dir . '/' . $filename;
681
682 my $contents = PostgreSQL::Test::Utils::slurp_file($conffile);
683 my @lines = split(/\n/, $contents);
684 my @result;
685 my $eq = $skip_equals ? '' : '= ';
686 foreach my $line (@lines)
687 {
688 if ($line !~ /^$setting\W/)
689 {
690 push(@result, "$line\n");
691 }
692 elsif (defined $value)
693 {
694 push(@result, "$setting $eq$value\n");
695 }
696 }
697 open my $fh, ">", $conffile
698 or croak "could not write \"$conffile\": $!";
699 print $fh @result;
700 close $fh;
701
702 chmod($self->group_access() ? 0640 : 0600, $conffile)
703 or die("unable to set permissions for $conffile");
704 }
705
706 =pod
707
708 =item $node->backup(backup_name)
709
710 Create a hot backup with B<pg_basebackup> in subdirectory B<backup_name> of
711 B<< $node->backup_dir >>, including the WAL.
712
713 By default, WAL files are fetched at the end of the backup, not streamed.
714 You can adjust that and other things by passing an array of additional
715 B<pg_basebackup> command line options in the keyword parameter backup_options.
716
717 You'll have to configure a suitable B<max_wal_senders> on the
718 target server since it isn't done by default.
719
720 =cut
721
722 sub backup
723 {
724 my ($self, $backup_name, %params) = @_;
725 my $backup_path = $self->backup_dir . '/' . $backup_name;
726 my $name = $self->name;
727
728 local %ENV = $self->_get_env();
729
730 print "# Taking pg_basebackup $backup_name from node \"$name\"\n";
731 PostgreSQL::Test::Utils::system_or_bail(
732 'pg_basebackup', '-D',
733 $backup_path, '-h',
734 $self->host, '-p',
735 $self->port, '--checkpoint',
736 'fast', '--no-sync',
737 @{ $params{backup_options} });
738 print "# Backup finished\n";
739 return;
740 }
741
742 =item $node->backup_fs_cold(backup_name)
743
744 Create a backup with a filesystem level copy in subdirectory B<backup_name> of
745 B<< $node->backup_dir >>, including WAL. The server must be
746 stopped as no attempt to handle concurrent writes is made.
747
748 Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
749
750 =cut
751
752 sub backup_fs_cold
753 {
754 my ($self, $backup_name) = @_;
755
756 PostgreSQL::Test::RecursiveCopy::copypath(
757 $self->data_dir,
758 $self->backup_dir . '/' . $backup_name,
759 filterfn => sub {
760 my $src = shift;
761 return ($src ne 'log' and $src ne 'postmaster.pid');
762 });
763
764 return;
765 }
766
767 =pod
768
769 =item $node->init_from_backup(root_node, backup_name)
770
771 Initialize a node from a backup, which may come from this node or a different
772 node. root_node must be a PostgreSQL::Test::Cluster reference, backup_name the string name
773 of a backup previously created on that node with $node->backup.
774
775 Does not start the node after initializing it.
776
777 By default, the backup is assumed to be plain format. To restore from
778 a tar-format backup, pass the name of the tar program to use in the
779 keyword parameter tar_program. Note that tablespace tar files aren't
780 handled here.
781
782 To restore from an incremental backup, pass the parameter combine_with_prior
783 as a reference to an array of prior backup names with which this backup
784 is to be combined using pg_combinebackup.
785
786 Streaming replication can be enabled on this node by passing the keyword
787 parameter has_streaming => 1. This is disabled by default.
788
789 Restoring WAL segments from archives using restore_command can be enabled
790 by passing the keyword parameter has_restoring => 1. This is disabled by
791 default.
792
793 If has_restoring is used, standby mode is used by default. To use
794 recovery mode instead, pass the keyword parameter standby => 0.
795
796 The backup is copied, leaving the original unmodified. pg_hba.conf is
797 unconditionally set to enable replication connections.
798
799 =cut
800
801 sub init_from_backup
802 {
803 my ($self, $root_node, $backup_name, %params) = @_;
804 my $backup_path = $root_node->backup_dir . '/' . $backup_name;
805 my $host = $self->host;
806 my $port = $self->port;
807 my $node_name = $self->name;
808 my $root_name = $root_node->name;
809
810 $params{has_streaming} = 0 unless defined $params{has_streaming};
811 $params{has_restoring} = 0 unless defined $params{has_restoring};
812 $params{standby} = 1 unless defined $params{standby};
813
814 print
815 "# Initializing node \"$node_name\" from backup \"$backup_name\" of node \"$root_name\"\n";
816 croak "Backup \"$backup_name\" does not exist at $backup_path"
817 unless -d $backup_path;
818
819 mkdir $self->backup_dir;
820 mkdir $self->archive_dir;
821
822 my $data_path = $self->data_dir;
823 if (defined $params{combine_with_prior})
824 {
825 my @prior_backups = @{$params{combine_with_prior}};
826 my @prior_backup_path;
827
828 for my $prior_backup_name (@prior_backups)
829 {
830 push @prior_backup_path,
831 $root_node->backup_dir . '/' . $prior_backup_name;
832 }
833
834 local %ENV = $self->_get_env();
835 PostgreSQL::Test::Utils::system_or_bail('pg_combinebackup', '-d',
836 @prior_backup_path, $backup_path, '-o', $data_path);
837 }
838 elsif (defined $params{tar_program})
839 {
840 mkdir($data_path);
841 PostgreSQL::Test::Utils::system_or_bail($params{tar_program}, 'xf',
842 $backup_path . '/base.tar',
843 '-C', $data_path);
844 PostgreSQL::Test::Utils::system_or_bail(
845 $params{tar_program}, 'xf',
846 $backup_path . '/pg_wal.tar', '-C',
847 $data_path . '/pg_wal');
848 }
849 else
850 {
851 rmdir($data_path);
852 PostgreSQL::Test::RecursiveCopy::copypath($backup_path, $data_path);
853 }
854 chmod(0700, $data_path);
855
856 # Base configuration for this node
857 $self->append_conf(
858 'postgresql.conf',
859 qq(
860 port = $port
861 ));
862 if ($use_tcp)
863 {
864 $self->append_conf('postgresql.conf', "listen_addresses = '$host'");
865 }
866 else
867 {
868 $self->append_conf('postgresql.conf',
869 "unix_socket_directories = '$host'");
870 }
871 $self->enable_streaming($root_node) if $params{has_streaming};
872 $self->enable_restoring($root_node, $params{standby})
873 if $params{has_restoring};
874 return;
875 }
876
877 =pod
878
879 =item $node->rotate_logfile()
880
881 Switch to a new PostgreSQL log file. This does not alter any running
882 PostgreSQL process. Subsequent method calls, including pg_ctl invocations,
883 will use the new name. Return the new name.
884
885 =cut
886
887 sub rotate_logfile
888 {
889 my ($self) = @_;
890 $self->{_logfile} = sprintf('%s_%d.log',
891 $self->{_logfile_base},
892 ++$self->{_logfile_generation});
893 return $self->{_logfile};
894 }
895
896 =pod
897
898 =item $node->start(%params) => success_or_failure
899
900 Wrapper for pg_ctl start
901
902 Start the node and wait until it is ready to accept connections.
903
904 =over
905
906 =item fail_ok => 1
907
908 By default, failure terminates the entire F<prove> invocation. If given,
909 instead return a true or false value to indicate success or failure.
910
911 =back
912
913 =cut
914
915 sub start
916 {
917 my ($self, %params) = @_;
918 my $port = $self->port;
919 my $pgdata = $self->data_dir;
920 my $name = $self->name;
921 my $ret;
922
923 BAIL_OUT("node \"$name\" is already running") if defined $self->{_pid};
924
925 print("### Starting node \"$name\"\n");
926
927 # Temporarily unset PGAPPNAME so that the server doesn't
928 # inherit it. Otherwise this could affect libpqwalreceiver
929 # connections in confusing ways.
930 local %ENV = $self->_get_env(PGAPPNAME => undef);
931
932 # Note: We set the cluster_name here, not in postgresql.conf (in
933 # sub init) so that it does not get copied to standbys.
934 # -w is now the default but having it here does no harm and helps
935 # compatibility with older versions.
936 $ret = PostgreSQL::Test::Utils::system_log(
937 'pg_ctl', '-w', '-D', $self->data_dir,
938 '-l', $self->logfile, '-o', "--cluster-name=$name",
939 'start');
940
941 if ($ret != 0)
942 {
943 print "# pg_ctl start failed; logfile:\n";
944 print PostgreSQL::Test::Utils::slurp_file($self->logfile);
945
946 # pg_ctl could have timed out, so check to see if there's a pid file;
947 # otherwise our END block will fail to shut down the new postmaster.
948 $self->_update_pid(-1);
949
950 BAIL_OUT("pg_ctl start failed") unless $params{fail_ok};
951 return 0;
952 }
953
954 $self->_update_pid(1);
955 return 1;
956 }
957
958 =pod
959
960 =item $node->kill9()
961
962 Send SIGKILL (signal 9) to the postmaster.
963
964 Note: if the node is already known stopped, this does nothing.
965 However, if we think it's running and it's not, it's important for
966 this to fail. Otherwise, tests might fail to detect server crashes.
967
968 =cut
969
970 sub kill9
971 {
972 my ($self) = @_;
973 my $name = $self->name;
974 return unless defined $self->{_pid};
975
976 local %ENV = $self->_get_env();
977
978 print "### Killing node \"$name\" using signal 9\n";
979 kill(9, $self->{_pid});
980 $self->{_pid} = undef;
981 return;
982 }
983
984 =pod
985
986 =item $node->stop(mode)
987
988 Stop the node using pg_ctl -m $mode and wait for it to stop.
989
990 Note: if the node is already known stopped, this does nothing.
991 However, if we think it's running and it's not, it's important for
992 this to fail. Otherwise, tests might fail to detect server crashes.
993
994 With optional extra param fail_ok => 1, returns 0 for failure
995 instead of bailing out.
996
997 =cut
998
999 sub stop
1000 {
1001 my ($self, $mode, %params) = @_;
1002 my $pgdata = $self->data_dir;
1003 my $name = $self->name;
1004 my $ret;
1005
1006 local %ENV = $self->_get_env();
1007
1008 $mode = 'fast' unless defined $mode;
1009 return 1 unless defined $self->{_pid};
1010
1011 print "### Stopping node \"$name\" using mode $mode\n";
1012 $ret = PostgreSQL::Test::Utils::system_log('pg_ctl', '-D', $pgdata,
1013 '-m', $mode, 'stop');
1014
1015 if ($ret != 0)
1016 {
1017 print "# pg_ctl stop failed: $ret\n";
1018
1019 # Check to see if we still have a postmaster or not.
1020 $self->_update_pid(-1);
1021
1022 BAIL_OUT("pg_ctl stop failed") unless $params{fail_ok};
1023 return 0;
1024 }
1025
1026 $self->_update_pid(0);
1027 return 1;
1028 }
1029
1030 =pod
1031
1032 =item $node->reload()
1033
1034 Reload configuration parameters on the node.
1035
1036 =cut
1037
1038 sub reload
1039 {
1040 my ($self) = @_;
1041 my $port = $self->port;
1042 my $pgdata = $self->data_dir;
1043 my $name = $self->name;
1044
1045 local %ENV = $self->_get_env();
1046
1047 print "### Reloading node \"$name\"\n";
1048 PostgreSQL::Test::Utils::system_or_bail('pg_ctl', '-D', $pgdata,
1049 'reload');
1050 return;
1051 }
1052
1053 =pod
1054
1055 =item $node->restart()
1056
1057 Wrapper for pg_ctl restart.
1058
1059 With optional extra param fail_ok => 1, returns 0 for failure
1060 instead of bailing out.
1061
1062 =cut
1063
1064 sub restart
1065 {
1066 my ($self, %params) = @_;
1067 my $name = $self->name;
1068 my $ret;
1069
1070 local %ENV = $self->_get_env(PGAPPNAME => undef);
1071
1072 print "### Restarting node \"$name\"\n";
1073
1074 # -w is now the default but having it here does no harm and helps
1075 # compatibility with older versions.
1076 $ret = PostgreSQL::Test::Utils::system_log(
1077 'pg_ctl', '-w', '-D', $self->data_dir,
1078 '-l', $self->logfile, 'restart');
1079
1080 if ($ret != 0)
1081 {
1082 print "# pg_ctl restart failed; logfile:\n";
1083 print PostgreSQL::Test::Utils::slurp_file($self->logfile);
1084
1085 # pg_ctl could have timed out, so check to see if there's a pid file;
1086 # otherwise our END block will fail to shut down the new postmaster.
1087 $self->_update_pid(-1);
1088
1089 BAIL_OUT("pg_ctl restart failed") unless $params{fail_ok};
1090 return 0;
1091 }
1092
1093 $self->_update_pid(1);
1094 return 1;
1095 }
1096
1097 =pod
1098
1099 =item $node->promote()
1100
1101 Wrapper for pg_ctl promote
1102
1103 =cut
1104
1105 sub promote
1106 {
1107 my ($self) = @_;
1108 my $port = $self->port;
1109 my $pgdata = $self->data_dir;
1110 my $logfile = $self->logfile;
1111 my $name = $self->name;
1112
1113 local %ENV = $self->_get_env();
1114
1115 print "### Promoting node \"$name\"\n";
1116 PostgreSQL::Test::Utils::system_or_bail('pg_ctl', '-D', $pgdata, '-l',
1117 $logfile, 'promote');
1118 return;
1119 }
1120
1121 =pod
1122
1123 =item $node->logrotate()
1124
1125 Wrapper for pg_ctl logrotate
1126
1127 =cut
1128
1129 sub logrotate
1130 {
1131 my ($self) = @_;
1132 my $port = $self->port;
1133 my $pgdata = $self->data_dir;
1134 my $logfile = $self->logfile;
1135 my $name = $self->name;
1136
1137 local %ENV = $self->_get_env();
1138
1139 print "### Rotating log in node \"$name\"\n";
1140 PostgreSQL::Test::Utils::system_or_bail('pg_ctl', '-D', $pgdata, '-l',
1141 $logfile, 'logrotate');
1142 return;
1143 }
1144
1145 # Internal routine to enable streaming replication on a standby node.
1146 sub enable_streaming
1147 {
1148 my ($self, $root_node) = @_;
1149 my $root_connstr = $root_node->connstr;
1150 my $name = $self->name;
1151
1152 print "### Enabling streaming replication for node \"$name\"\n";
1153 $self->append_conf(
1154 $self->_recovery_file, qq(
1155 primary_conninfo='$root_connstr'
1156 ));
1157 $self->set_standby_mode();
1158 return;
1159 }
1160
1161 # Internal routine to enable archive recovery command on a standby node
1162 sub enable_restoring
1163 {
1164 my ($self, $root_node, $standby) = @_;
1165 my $path = $root_node->archive_dir;
1166 my $name = $self->name;
1167
1168 print "### Enabling WAL restore for node \"$name\"\n";
1169
1170 # On Windows, the path specified in the restore command needs to use
1171 # double back-slashes to work properly and to be able to detect properly
1172 # the file targeted by the copy command, so the directory value used
1173 # in this routine, using only one back-slash, need to be properly changed
1174 # first. Paths also need to be double-quoted to prevent failures where
1175 # the path contains spaces.
1176 $path =~ s{\\}{\\\\}g if ($PostgreSQL::Test::Utils::windows_os);
1177 my $copy_command =
1178 $PostgreSQL::Test::Utils::windows_os
1179 ? qq{copy "$path\\\\%f" "%p"}
1180 : qq{cp "$path/%f" "%p"};
1181
1182 $self->append_conf(
1183 $self->_recovery_file, qq(
1184 restore_command = '$copy_command'
1185 ));
1186 if ($standby)
1187 {
1188 $self->set_standby_mode();
1189 }
1190 else
1191 {
1192 $self->set_recovery_mode();
1193 }
1194 return;
1195 }
1196
1197 sub _recovery_file { return "postgresql.conf"; }
1198
1199 =pod
1200
1201 =item $node->set_recovery_mode()
1202
1203 Place recovery.signal file.
1204
1205 =cut
1206
1207 sub set_recovery_mode
1208 {
1209 my ($self) = @_;
1210
1211 $self->append_conf('recovery.signal', '');
1212 return;
1213 }
1214
1215 =pod
1216
1217 =item $node->set_standby_mode()
1218
1219 Place standby.signal file.
1220
1221 =cut
1222
1223 sub set_standby_mode
1224 {
1225 my ($self) = @_;
1226
1227 $self->append_conf('standby.signal', '');
1228 return;
1229 }
1230
1231 # Internal routine to enable archiving
1232 sub enable_archiving
1233 {
1234 my ($self) = @_;
1235 my $path = $self->archive_dir;
1236 my $name = $self->name;
1237
1238 print "### Enabling WAL archiving for node \"$name\"\n";
1239
1240 # On Windows, the path specified in the restore command needs to use
1241 # double back-slashes to work properly and to be able to detect properly
1242 # the file targeted by the copy command, so the directory value used
1243 # in this routine, using only one back-slash, need to be properly changed
1244 # first. Paths also need to be double-quoted to prevent failures where
1245 # the path contains spaces.
1246 $path =~ s{\\}{\\\\}g if ($PostgreSQL::Test::Utils::windows_os);
1247 my $copy_command =
1248 $PostgreSQL::Test::Utils::windows_os
1249 ? qq{copy "%p" "$path\\\\%f"}
1250 : qq{cp "%p" "$path/%f"};
1251
1252 # Enable archive_mode and archive_command on node
1253 $self->append_conf(
1254 'postgresql.conf', qq(
1255 archive_mode = on
1256 archive_command = '$copy_command'
1257 ));
1258 return;
1259 }
1260
1261 # Internal method to update $self->{_pid}
1262 # $is_running = 1: pid file should be there
1263 # $is_running = 0: pid file should NOT be there
1264 # $is_running = -1: we aren't sure
1265 sub _update_pid
1266 {
1267 my ($self, $is_running) = @_;
1268 my $name = $self->name;
1269
1270 # If we can open the PID file, read its first line and that's the PID we
1271 # want.
1272 if (open my $pidfile, '<', $self->data_dir . "/postmaster.pid")
1273 {
1274 chomp($self->{_pid} = <$pidfile>);
1275 close $pidfile;
1276
1277 # If we aren't sure what to expect, validate the PID using kill().
1278 # This protects against stale PID files left by crashed postmasters.
1279 if ($is_running == -1 && kill(0, $self->{_pid}) == 0)
1280 {
1281 print
1282 "# Stale postmaster.pid file for node \"$name\": PID $self->{_pid} no longer exists\n";
1283 $self->{_pid} = undef;
1284 return;
1285 }
1286
1287 print "# Postmaster PID for node \"$name\" is $self->{_pid}\n";
1288
1289 # If we found a pidfile when there shouldn't be one, complain.
1290 BAIL_OUT("postmaster.pid unexpectedly present") if $is_running == 0;
1291 return;
1292 }
1293
1294 $self->{_pid} = undef;
1295 print "# No postmaster PID for node \"$name\"\n";
1296
1297 # Complain if we expected to find a pidfile.
1298 BAIL_OUT("postmaster.pid unexpectedly not present") if $is_running == 1;
1299 return;
1300 }
1301
1302 =pod
1303
1304 =item PostgreSQL::Test::Cluster->new(node_name, %params)
1305
1306 Build a new object of class C<PostgreSQL::Test::Cluster> (or of a subclass, if you have
1307 one), assigning a free port number. Remembers the node, to prevent its port
1308 number from being reused for another node, and to ensure that it gets
1309 shut down when the test script exits.
1310
1311 =over
1312
1313 =item port => [1,65535]
1314
1315 By default, this function assigns a port number to each node. Specify this to
1316 force a particular port number. The caller is responsible for evaluating
1317 potential conflicts and privilege requirements.
1318
1319 =item own_host => 1
1320
1321 By default, all nodes use the same PGHOST value. If specified, generate a
1322 PGHOST specific to this node. This allows multiple nodes to use the same
1323 port.
1324
1325 =item install_path => '/path/to/postgres/installation'
1326
1327 Using this parameter is it possible to have nodes pointing to different
1328 installations, for testing different versions together or the same version
1329 with different build parameters. The provided path must be the parent of the
1330 installation's 'bin' and 'lib' directories. In the common case where this is
1331 not provided, Postgres binaries will be found in the caller's PATH.
1332
1333 =back
1334
1335 =cut
1336
1337 sub new
1338 {
1339 my $class = shift;
1340 my ($name, %params) = @_;
1341
1342 # Select a port.
1343 my $port;
1344 if (defined $params{port})
1345 {
1346 $port = $params{port};
1347 }
1348 else
1349 {
1350 # When selecting a port, we look for an unassigned TCP port number,
1351 # even if we intend to use only Unix-domain sockets. This is clearly
1352 # necessary on $use_tcp (Windows) configurations, and it seems like a
1353 # good idea on Unixen as well.
1354 $port = get_free_port();
1355 }
1356
1357 # Select a host.
1358 my $host = $test_pghost;
1359 if ($params{own_host})
1360 {
1361 if ($use_tcp)
1362 {
1363 $last_host_assigned++;
1364 $last_host_assigned > 254 and BAIL_OUT("too many own_host nodes");
1365 $host = '127.0.0.' . $last_host_assigned;
1366 }
1367 else
1368 {
1369 $host = "$test_pghost/$name"; # Assume $name =~ /^[-_a-zA-Z0-9]+$/
1370 mkdir $host;
1371 }
1372 }
1373
1374 my $testname = basename($0);
1375 $testname =~ s/\.[^.]+$//;
1376 my $node = {
1377 _port => $port,
1378 _host => $host,
1379 _basedir =>
1380 "$PostgreSQL::Test::Utils::tmp_check/t_${testname}_${name}_data",
1381 _name => $name,
1382 _logfile_generation => 0,
1383 _logfile_base =>
1384 "$PostgreSQL::Test::Utils::log_path/${testname}_${name}",
1385 _logfile =>
1386 "$PostgreSQL::Test::Utils::log_path/${testname}_${name}.log"
1387 };
1388
1389 if ($params{install_path})
1390 {
1391 $node->{_install_path} = $params{install_path};
1392 }
1393
1394 bless $node, $class;
1395 mkdir $node->{_basedir}
1396 or
1397 BAIL_OUT("could not create data directory \"$node->{_basedir}\": $!");
1398
1399 $node->dump_info;
1400
1401 $node->_set_pg_version;
1402
1403 my $ver = $node->{_pg_version};
1404
1405 # Use a subclass as defined below (or elsewhere) if this version
1406 # isn't fully compatible. Warn if the version is too old and thus we don't
1407 # have a subclass of this class.
1408 if (ref $ver && $ver < $min_compat)
1409 {
1410 my $maj = $ver->major(separator => '_');
1411 my $subclass = $class . "::V_$maj";
1412 if ($subclass->isa($class))
1413 {
1414 bless $node, $subclass;
1415 }
1416 else
1417 {
1418 carp
1419 "PostgreSQL::Test::Cluster isn't fully compatible with version $ver";
1420 }
1421 }
1422
1423 # Add node to list of nodes
1424 push(@all_nodes, $node);
1425
1426 return $node;
1427 }
1428
1429 # Private routine to run the pg_config binary found in our environment (or in
1430 # our install_path, if we have one), and set the version from it
1431 #
1432 sub _set_pg_version
1433 {
1434 my ($self) = @_;
1435 my $inst = $self->{_install_path};
1436 my $pg_config = "pg_config";
1437
1438 if (defined $inst)
1439 {
1440 # If the _install_path is invalid, our PATH variables might find an
1441 # unrelated pg_config executable elsewhere. Sanity check the
1442 # directory.
1443 BAIL_OUT("directory not found: $inst")
1444 unless -d $inst;
1445
1446 # If the directory exists but is not the root of a postgresql
1447 # installation, or if the user configured using
1448 # --bindir=$SOMEWHERE_ELSE, we're not going to find pg_config, so
1449 # complain about that, too.
1450 $pg_config = "$inst/bin/pg_config";
1451 BAIL_OUT("pg_config not found: $pg_config")
1452 unless -e $pg_config
1453 or ($PostgreSQL::Test::Utils::windows_os and -e "$pg_config.exe");
1454 BAIL_OUT("pg_config not executable: $pg_config")
1455 unless $PostgreSQL::Test::Utils::windows_os or -x $pg_config;
1456
1457 # Leave $pg_config install_path qualified, to be sure we get the right
1458 # version information, below, or die trying
1459 }
1460
1461 local %ENV = $self->_get_env();
1462
1463 # We only want the version field
1464 my $version_line = qx{$pg_config --version};
1465 BAIL_OUT("$pg_config failed: $!") if $?;
1466
1467 $self->{_pg_version} = PostgreSQL::Version->new($version_line);
1468
1469 BAIL_OUT("could not parse pg_config --version output: $version_line")
1470 unless defined $self->{_pg_version};
1471 }
1472
1473 # Private routine to return a copy of the environment with the PATH and
1474 # (DY)LD_LIBRARY_PATH correctly set when there is an install path set for
1475 # the node.
1476 #
1477 # Routines that call Postgres binaries need to call this routine like this:
1478 #
1479 # local %ENV = $self->_get_env([%extra_settings]);
1480 #
1481 # A copy of the environment is taken and node's host and port settings are
1482 # added as PGHOST and PGPORT, then the extra settings (if any) are applied.
1483 # Any setting in %extra_settings with a value that is undefined is deleted;
1484 # the remainder are set. Then the PATH and (DY)LD_LIBRARY_PATH are adjusted
1485 # if the node's install path is set, and the copy environment is returned.
1486 #
1487 # The install path set in new() needs to be a directory containing
1488 # bin and lib subdirectories as in a standard PostgreSQL installation, so this
1489 # can't be used with installations where the bin and lib directories don't have
1490 # a common parent directory.
1491 sub _get_env
1492 {
1493 my $self = shift;
1494 my %inst_env = (%ENV, PGHOST => $self->{_host}, PGPORT => $self->{_port});
1495 # the remaining arguments are modifications to make to the environment
1496 my %mods = (@_);
1497 while (my ($k, $v) = each %mods)
1498 {
1499 if (defined $v)
1500 {
1501 $inst_env{$k} = "$v";
1502 }
1503 else
1504 {
1505 delete $inst_env{$k};
1506 }
1507 }
1508 # now fix up the new environment for the install path
1509 my $inst = $self->{_install_path};
1510 if ($inst)
1511 {
1512 if ($PostgreSQL::Test::Utils::windows_os)
1513 {
1514 # Windows picks up DLLs from the PATH rather than *LD_LIBRARY_PATH
1515 # choose the right path separator
1516 if ($Config{osname} eq 'MSWin32')
1517 {
1518 $inst_env{PATH} = "$inst/bin;$inst/lib;$ENV{PATH}";
1519 }
1520 else
1521 {
1522 $inst_env{PATH} = "$inst/bin:$inst/lib:$ENV{PATH}";
1523 }
1524 }
1525 else
1526 {
1527 my $dylib_name =
1528 $Config{osname} eq 'darwin'
1529 ? "DYLD_LIBRARY_PATH"
1530 : "LD_LIBRARY_PATH";
1531 $inst_env{PATH} = "$inst/bin:$ENV{PATH}";
1532 if (exists $ENV{$dylib_name})
1533 {
1534 $inst_env{$dylib_name} = "$inst/lib:$ENV{$dylib_name}";
1535 }
1536 else
1537 {
1538 $inst_env{$dylib_name} = "$inst/lib";
1539 }
1540 }
1541 }
1542 return (%inst_env);
1543 }
1544
1545 # Private routine to get an installation path qualified command.
1546 #
1547 # IPC::Run maintains a cache, %cmd_cache, mapping commands to paths. Tests
1548 # which use nodes spanning more than one postgres installation path need to
1549 # avoid confusing which installation's binaries get run. Setting $ENV{PATH} is
1550 # insufficient, as IPC::Run does not check to see if the path has changed since
1551 # caching a command.
1552 sub installed_command
1553 {
1554 my ($self, $cmd) = @_;
1555
1556 # Nodes using alternate installation locations use their installation's
1557 # bin/ directory explicitly
1558 return join('/', $self->{_install_path}, 'bin', $cmd)
1559 if defined $self->{_install_path};
1560
1561 # Nodes implicitly using the default installation location rely on IPC::Run
1562 # to find the right binary, which should not cause %cmd_cache confusion,
1563 # because no nodes with other installation paths do it that way.
1564 return $cmd;
1565 }
1566
1567 =pod
1568
1569 =item get_free_port()
1570
1571 Locate an unprivileged (high) TCP port that's not currently bound to
1572 anything. This is used by C<new()>, and also by some test cases that need to
1573 start other, non-Postgres servers.
1574
1575 Ports assigned to existing PostgreSQL::Test::Cluster objects are automatically
1576 excluded, even if those servers are not currently running.
1577
1578 The port number is reserved so that other concurrent test programs will not
1579 try to use the same port.
1580
1581 Note: this is not an instance method. As it's not exported it should be
1582 called from outside the module as C<PostgreSQL::Test::Cluster::get_free_port()>.
1583
1584 =cut
1585
1586 sub get_free_port
1587 {
1588 my $found = 0;
1589 my $port = $last_port_assigned;
1590
1591 while ($found == 0)
1592 {
1593
1594 # advance $port, wrapping correctly around range end
1595 $port = 49152 if ++$port >= 65536;
1596 print "# Checking port $port\n";
1597
1598 # Check first that candidate port number is not included in
1599 # the list of already-registered nodes.
1600 $found = 1;
1601 foreach my $node (@all_nodes)
1602 {
1603 $found = 0 if ($node->port == $port);
1604 }
1605
1606 # Check to see if anything else is listening on this TCP port.
1607 # Seek a port available for all possible listen_addresses values,
1608 # so callers can harness this port for the widest range of purposes.
1609 # The 0.0.0.0 test achieves that for MSYS, which automatically sets
1610 # SO_EXCLUSIVEADDRUSE. Testing 0.0.0.0 is insufficient for Windows
1611 # native Perl (https://stackoverflow.com/a/14388707), so we also
1612 # have to test individual addresses. Doing that for 127.0.0/24
1613 # addresses other than 127.0.0.1 might fail with EADDRNOTAVAIL on
1614 # non-Linux, non-Windows kernels.
1615 #
1616 # Thus, 0.0.0.0 and individual 127.0.0/24 addresses are tested
1617 # only on Windows and only when TCP usage is requested.
1618 if ($found == 1)
1619 {
1620 foreach my $addr (qw(127.0.0.1),
1621 ($use_tcp && $PostgreSQL::Test::Utils::windows_os)
1622 ? qw(127.0.0.2 127.0.0.3 0.0.0.0)
1623 : ())
1624 {
1625 if (!can_bind($addr, $port))
1626 {
1627 $found = 0;
1628 last;
1629 }
1630 }
1631 $found = _reserve_port($port) if $found;
1632 }
1633 }
1634
1635 print "# Found port $port\n";
1636
1637 # Update port for next time
1638 $last_port_assigned = $port;
1639
1640 return $port;
1641 }
1642
1643 # Internal routine to check whether a host:port is available to bind
1644 sub can_bind
1645 {
1646 my ($host, $port) = @_;
1647 my $iaddr = inet_aton($host);
1648 my $paddr = sockaddr_in($port, $iaddr);
1649
1650 socket(SOCK, PF_INET, SOCK_STREAM, 0)
1651 or die "socket failed: $!";
1652
1653 # As in postmaster, don't use SO_REUSEADDR on Windows
1654 setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
1655 unless $PostgreSQL::Test::Utils::windows_os;
1656 my $ret = bind(SOCK, $paddr) && listen(SOCK, SOMAXCONN);
1657 close(SOCK);
1658 return $ret;
1659 }
1660
1661 # Internal routine to reserve a port number
1662 # Returns 1 if successful, 0 if port is already reserved.
1663 sub _reserve_port
1664 {
1665 my $port = shift;
1666 # open in rw mode so we don't have to reopen it and lose the lock
1667 my $filename = "$portdir/$port.rsv";
1668 sysopen(my $portfile, $filename, O_RDWR | O_CREAT)
1669 || die "opening port file $filename: $!";
1670 # take an exclusive lock to avoid concurrent access
1671 flock($portfile, LOCK_EX) || die "locking port file $filename: $!";
1672 # see if someone else has or had a reservation of this port
1673 my $pid = <$portfile> || "0";
1674 chomp $pid;
1675 if ($pid + 0 > 0)
1676 {
1677 if (kill 0, $pid)
1678 {
1679 # process exists and is owned by us, so we can't reserve this port
1680 flock($portfile, LOCK_UN);
1681 close($portfile);
1682 return 0;
1683 }
1684 }
1685 # All good, go ahead and reserve the port
1686 seek($portfile, 0, SEEK_SET);
1687 # print the pid with a fixed width so we don't leave any trailing junk
1688 print $portfile sprintf("%10d\n", $$);
1689 flock($portfile, LOCK_UN);
1690 close($portfile);
1691 push(@port_reservation_files, $filename);
1692 return 1;
1693 }
1694
1695 # Automatically shut down any still-running nodes (in the same order the nodes
1696 # were created in) when the test script exits.
1697 END
1698 {
1699
1700 # take care not to change the script's exit value
1701 my $exit_code = $?;
1702
1703 foreach my $node (@all_nodes)
1704 {
1705 # During unclean termination (which could be a signal or some
1706 # other failure), we're not sure that the status of our nodes
1707 # has been correctly set up already, so try and update it to
1708 # improve our chances of shutting them down.
1709 $node->_update_pid(-1) if $exit_code != 0;
1710
1711 # If that fails, don't let that foil other nodes' shutdown
1712 $node->teardown_node(fail_ok => 1);
1713
1714 # skip clean if we are requested to retain the basedir
1715 next if defined $ENV{'PG_TEST_NOCLEAN'};
1716
1717 # clean basedir on clean test invocation
1718 $node->clean_node
1719 if $exit_code == 0 && PostgreSQL::Test::Utils::all_tests_passing();
1720 }
1721
1722 unlink @port_reservation_files;
1723
1724 $? = $exit_code;
1725 }
1726
1727 =pod
1728
1729 =item $node->teardown_node()
1730
1731 Do an immediate stop of the node
1732
1733 Any optional extra parameter is passed to ->stop.
1734
1735 =cut
1736
1737 sub teardown_node
1738 {
1739 my ($self, %params) = @_;
1740
1741 $self->stop('immediate', %params);
1742 return;
1743 }
1744
1745 =pod
1746
1747 =item $node->clean_node()
1748
1749 Remove the base directory of the node if the node has been stopped.
1750
1751 =cut
1752
1753 sub clean_node
1754 {
1755 my $self = shift;
1756
1757 rmtree $self->{_basedir} unless defined $self->{_pid};
1758 return;
1759 }
1760
1761 =pod
1762
1763 =item $node->safe_psql($dbname, $sql) => stdout
1764
1765 Invoke B<psql> to run B<sql> on B<dbname> and return its stdout on success.
1766 Die if the SQL produces an error. Runs with B<ON_ERROR_STOP> set.
1767
1768 Takes optional extra params like timeout and timed_out parameters with the same
1769 options as psql.
1770
1771 =cut
1772
1773 sub safe_psql
1774 {
1775 my ($self, $dbname, $sql, %params) = @_;
1776
1777 local %ENV = $self->_get_env();
1778
1779 my ($stdout, $stderr);
1780
1781 my $ret = $self->psql(
1782 $dbname, $sql,
1783 %params,
1784 stdout => \$stdout,
1785 stderr => \$stderr,
1786 on_error_die => 1,
1787 on_error_stop => 1);
1788
1789 # psql can emit stderr from NOTICEs etc
1790 if ($stderr ne "")
1791 {
1792 print "#### Begin standard error\n";
1793 print $stderr;
1794 print "\n#### End standard error\n";
1795 }
1796
1797 return $stdout;
1798 }
1799
1800 =pod
1801
1802 =item $node->psql($dbname, $sql, %params) => psql_retval
1803
1804 Invoke B<psql> to execute B<$sql> on B<$dbname> and return the return value
1805 from B<psql>, which is run with on_error_stop by default so that it will
1806 stop running sql and return 3 if the passed SQL results in an error.
1807
1808 As a convenience, if B<psql> is called in array context it returns an
1809 array containing ($retval, $stdout, $stderr).
1810
1811 psql is invoked in tuples-only unaligned mode with reading of B<.psqlrc>
1812 disabled. That may be overridden by passing extra psql parameters.
1813
1814 stdout and stderr are transformed to UNIX line endings if on Windows. Any
1815 trailing newline is removed.
1816
1817 Dies on failure to invoke psql but not if psql exits with a nonzero
1818 return code (unless on_error_die specified).
1819
1820 If psql exits because of a signal, an exception is raised.
1821
1822 =over
1823
1824 =item stdout => \$stdout
1825
1826 B<stdout>, if given, must be a scalar reference to which standard output is
1827 written. If not given, standard output is not redirected and will be printed
1828 unless B<psql> is called in array context, in which case it's captured and
1829 returned.
1830
1831 =item stderr => \$stderr
1832
1833 Same as B<stdout> but gets standard error. If the same scalar is passed for
1834 both B<stdout> and B<stderr> the results may be interleaved unpredictably.
1835
1836 =item on_error_stop => 1
1837
1838 By default, the B<psql> method invokes the B<psql> program with ON_ERROR_STOP=1
1839 set, so SQL execution is stopped at the first error and exit code 3 is
1840 returned. Set B<on_error_stop> to 0 to ignore errors instead.
1841
1842 =item on_error_die => 0
1843
1844 By default, this method returns psql's result code. Pass on_error_die to
1845 instead die with an informative message.
1846
1847 =item timeout => 'interval'
1848
1849 Set a timeout for the psql call as an interval accepted by B<IPC::Run::timer>
1850 (integer seconds is fine). This method raises an exception on timeout, unless
1851 the B<timed_out> parameter is also given.
1852
1853 =item timed_out => \$timed_out
1854
1855 If B<timeout> is set and this parameter is given, the scalar it references
1856 is set to true if the psql call times out.
1857
1858 =item connstr => B<value>
1859
1860 If set, use this as the connection string for the connection to the
1861 backend.
1862
1863 =item replication => B<value>
1864
1865 If set, add B<replication=value> to the conninfo string.
1866 Passing the literal value C<database> results in a logical replication
1867 connection.
1868
1869 =item extra_params => ['--single-transaction']
1870
1871 If given, it must be an array reference containing additional parameters to B<psql>.
1872
1873 =back
1874
1875 e.g.
1876
1877 my ($stdout, $stderr, $timed_out);
1878 my $cmdret = $node->psql('postgres', 'SELECT pg_sleep(600)',
1879 stdout => \$stdout, stderr => \$stderr,
1880 timeout => $PostgreSQL::Test::Utils::timeout_default,
1881 timed_out => \$timed_out,
1882 extra_params => ['--single-transaction'])
1883
1884 will set $cmdret to undef and $timed_out to a true value.
1885
1886 $node->psql('postgres', $sql, on_error_die => 1);
1887
1888 dies with an informative message if $sql fails.
1889
1890 =cut
1891
1892 sub psql
1893 {
1894 my ($self, $dbname, $sql, %params) = @_;
1895
1896 local %ENV = $self->_get_env();
1897
1898 my $stdout = $params{stdout};
1899 my $stderr = $params{stderr};
1900 my $replication = $params{replication};
1901 my $timeout = undef;
1902 my $timeout_exception = 'psql timed out';
1903
1904 # Build the connection string.
1905 my $psql_connstr;
1906 if (defined $params{connstr})
1907 {
1908 $psql_connstr = $params{connstr};
1909 }
1910 else
1911 {
1912 $psql_connstr = $self->connstr($dbname);
1913 }
1914 $psql_connstr .= defined $replication ? " replication=$replication" : "";
1915
1916 my @psql_params = (
1917 $self->installed_command('psql'),
1918 '-XAtq', '-d', $psql_connstr, '-f', '-');
1919
1920 # If the caller wants an array and hasn't passed stdout/stderr
1921 # references, allocate temporary ones to capture them so we
1922 # can return them. Otherwise we won't redirect them at all.
1923 if (wantarray)
1924 {
1925 if (!defined($stdout))
1926 {
1927 my $temp_stdout = "";
1928 $stdout = \$temp_stdout;
1929 }
1930 if (!defined($stderr))
1931 {
1932 my $temp_stderr = "";
1933 $stderr = \$temp_stderr;
1934 }
1935 }
1936
1937 $params{on_error_stop} = 1 unless defined $params{on_error_stop};
1938 $params{on_error_die} = 0 unless defined $params{on_error_die};
1939
1940 push @psql_params, '-v', 'ON_ERROR_STOP=1' if $params{on_error_stop};
1941 push @psql_params, @{ $params{extra_params} }
1942 if defined $params{extra_params};
1943
1944 $timeout =
1945 IPC::Run::timeout($params{timeout}, exception => $timeout_exception)
1946 if (defined($params{timeout}));
1947
1948 ${ $params{timed_out} } = 0 if defined $params{timed_out};
1949
1950 # IPC::Run would otherwise append to existing contents:
1951 $$stdout = "" if ref($stdout);
1952 $$stderr = "" if ref($stderr);
1953
1954 my $ret;
1955
1956 # Run psql and capture any possible exceptions. If the exception is
1957 # because of a timeout and the caller requested to handle that, just return
1958 # and set the flag. Otherwise, and for any other exception, rethrow.
1959 #
1960 # For background, see
1961 # https://metacpan.org/release/ETHER/Try-Tiny-0.24/view/lib/Try/Tiny.pm
1962 do
1963 {
1964 local $@;
1965 eval {
1966 my @ipcrun_opts = (\@psql_params, '<', \$sql);
1967 push @ipcrun_opts, '>', $stdout if defined $stdout;
1968 push @ipcrun_opts, '2>', $stderr if defined $stderr;
1969 push @ipcrun_opts, $timeout if defined $timeout;
1970
1971 IPC::Run::run @ipcrun_opts;
1972 $ret = $?;
1973 };
1974 my $exc_save = $@;
1975 if ($exc_save)
1976 {
1977
1978 # IPC::Run::run threw an exception. re-throw unless it's a
1979 # timeout, which we'll handle by testing is_expired
1980 die $exc_save
1981 if (blessed($exc_save)
1982 || $exc_save !~ /^\Q$timeout_exception\E/);
1983
1984 $ret = undef;
1985
1986 die "Got timeout exception '$exc_save' but timer not expired?!"
1987 unless $timeout->is_expired;
1988
1989 if (defined($params{timed_out}))
1990 {
1991 ${ $params{timed_out} } = 1;
1992 }
1993 else
1994 {
1995 die "psql timed out: stderr: '$$stderr'\n"
1996 . "while running '@psql_params'";
1997 }
1998 }
1999 };
2000
2001 if (defined $$stdout)
2002 {
2003 chomp $$stdout;
2004 }
2005
2006 if (defined $$stderr)
2007 {
2008 chomp $$stderr;
2009 }
2010
2011 # See http://perldoc.perl.org/perlvar.html#%24CHILD_ERROR
2012 # We don't use IPC::Run::Simple to limit dependencies.
2013 #
2014 # We always die on signal.
2015 my $core = $ret & 128 ? " (core dumped)" : "";
2016 die "psql exited with signal "
2017 . ($ret & 127)
2018 . "$core: '$$stderr' while running '@psql_params'"
2019 if $ret & 127;
2020 $ret = $ret >> 8;
2021
2022 if ($ret && $params{on_error_die})
2023 {
2024 die "psql error: stderr: '$$stderr'\nwhile running '@psql_params'"
2025 if $ret == 1;
2026 die "connection error: '$$stderr'\nwhile running '@psql_params'"
2027 if $ret == 2;
2028 die
2029 "error running SQL: '$$stderr'\nwhile running '@psql_params' with sql '$sql'"
2030 if $ret == 3;
2031 die "psql returns $ret: '$$stderr'\nwhile running '@psql_params'";
2032 }
2033
2034 if (wantarray)
2035 {
2036 return ($ret, $$stdout, $$stderr);
2037 }
2038 else
2039 {
2040 return $ret;
2041 }
2042 }
2043
2044 =pod
2045
2046 =item $node->background_psql($dbname, %params) => PostgreSQL::Test::BackgroundPsql instance
2047
2048 Invoke B<psql> on B<$dbname> and return a BackgroundPsql object.
2049
2050 psql is invoked in tuples-only unaligned mode with reading of B<.psqlrc>
2051 disabled. That may be overridden by passing extra psql parameters.
2052
2053 Dies on failure to invoke psql, or if psql fails to connect. Errors occurring
2054 later are the caller's problem. psql runs with on_error_stop by default so
2055 that it will stop running sql and return 3 if passed SQL results in an error.
2056
2057 Be sure to "quit" the returned object when done with it.
2058
2059 =over
2060
2061 =item on_error_stop => 1
2062
2063 By default, the B<psql> method invokes the B<psql> program with ON_ERROR_STOP=1
2064 set, so SQL execution is stopped at the first error and exit code 3 is
2065 returned. Set B<on_error_stop> to 0 to ignore errors instead.
2066
2067 =item timeout => 'interval'
2068
2069 Set a timeout for a background psql session. By default, timeout of
2070 $PostgreSQL::Test::Utils::timeout_default is set up.
2071
2072 =item replication => B<value>
2073
2074 If set, add B<replication=value> to the conninfo string.
2075 Passing the literal value C<database> results in a logical replication
2076 connection.
2077
2078 =item extra_params => ['--single-transaction']
2079
2080 If given, it must be an array reference containing additional parameters to B<psql>.
2081
2082 =back
2083
2084 =cut
2085
2086 sub background_psql
2087 {
2088 my ($self, $dbname, %params) = @_;
2089
2090 local %ENV = $self->_get_env();
2091
2092 my $replication = $params{replication};
2093 my $timeout = undef;
2094
2095 my @psql_params = (
2096 $self->installed_command('psql'),
2097 '-XAtq',
2098 '-d',
2099 $self->connstr($dbname)
2100 . (defined $replication ? " replication=$replication" : ""),
2101 '-f',
2102 '-');
2103
2104 $params{on_error_stop} = 1 unless defined $params{on_error_stop};
2105 $timeout = $params{timeout} if defined $params{timeout};
2106
2107 push @psql_params, '-v', 'ON_ERROR_STOP=1' if $params{on_error_stop};
2108 push @psql_params, @{ $params{extra_params} }
2109 if defined $params{extra_params};
2110
2111 return PostgreSQL::Test::BackgroundPsql->new(0, \@psql_params, $timeout);
2112 }
2113
2114 =pod
2115
2116 =item $node->interactive_psql($dbname, %params) => BackgroundPsql instance
2117
2118 Invoke B<psql> on B<$dbname> and return a BackgroundPsql object, which the
2119 caller may use to send interactive input to B<psql>.
2120
2121 A timeout of $PostgreSQL::Test::Utils::timeout_default is set up.
2122
2123 psql is invoked in tuples-only unaligned mode with reading of B<.psqlrc>
2124 disabled. That may be overridden by passing extra psql parameters.
2125
2126 Dies on failure to invoke psql, or if psql fails to connect.
2127 Errors occurring later are the caller's problem.
2128
2129 Be sure to "quit" the returned object when done with it.
2130
2131 =over
2132
2133 =item extra_params => ['--single-transaction']
2134
2135 If given, it must be an array reference containing additional parameters to B<psql>.
2136
2137 =item history_file => B<path>
2138
2139 Cause the interactive B<psql> session to write its command history to B<path>.
2140 If not given, the history is sent to B</dev/null>.
2141
2142 =back
2143
2144 This requires IO::Pty in addition to IPC::Run.
2145
2146 =cut
2147
2148 sub interactive_psql
2149 {
2150 my ($self, $dbname, %params) = @_;
2151
2152 local %ENV = $self->_get_env();
2153
2154 # Since the invoked psql will believe it's interactive, it will use
2155 # readline/libedit if available. We need to adjust some environment
2156 # settings to prevent unwanted side-effects.
2157
2158 # Developers would not appreciate tests adding a bunch of junk to
2159 # their ~/.psql_history, so redirect readline history somewhere else.
2160 # If the calling script doesn't specify anything, just bit-bucket it.
2161 $ENV{PSQL_HISTORY} = $params{history_file} || '/dev/null';
2162
2163 # Another pitfall for developers is that they might have a ~/.inputrc
2164 # file that changes readline's behavior enough to affect the test.
2165 # So ignore any such file.
2166 $ENV{INPUTRC} = '/dev/null';
2167
2168 # Unset TERM so that readline/libedit won't use any terminal-dependent
2169 # escape sequences; that leads to way too many cross-version variations
2170 # in the output.
2171 delete $ENV{TERM};
2172 # Some versions of readline inspect LS_COLORS, so for luck unset that too.
2173 delete $ENV{LS_COLORS};
2174
2175 my @psql_params = (
2176 $self->installed_command('psql'),
2177 '-XAt', '-d', $self->connstr($dbname));
2178
2179 push @psql_params, @{ $params{extra_params} }
2180 if defined $params{extra_params};
2181
2182 return PostgreSQL::Test::BackgroundPsql->new(1, \@psql_params);
2183 }
2184
2185 # Common sub of pgbench-invoking interfaces. Makes any requested script files
2186 # and returns pgbench command-line options causing use of those files.
2187 sub _pgbench_make_files
2188 {
2189 my ($self, $files) = @_;
2190 my @file_opts;
2191
2192 if (defined $files)
2193 {
2194
2195 # note: files are ordered for determinism
2196 for my $fn (sort keys %$files)
2197 {
2198 my $filename = $self->basedir . '/' . $fn;
2199 push @file_opts, '-f', $filename;
2200
2201 # cleanup file weight
2202 $filename =~ s/\@\d+$//;
2203
2204 # filenames are expected to be unique on a test
2205 if (-e $filename)
2206 {
2207 ok(0, "$filename must not already exist");
2208 unlink $filename or die "cannot unlink $filename: $!";
2209 }
2210 PostgreSQL::Test::Utils::append_to_file($filename, $$files{$fn});
2211 }
2212 }
2213
2214 return @file_opts;
2215 }
2216
2217 =pod
2218
2219 =item $node->pgbench($opts, $stat, $out, $err, $name, $files, @args)
2220
2221 Invoke B<pgbench>, with parameters and files.
2222
2223 =over
2224
2225 =item $opts
2226
2227 Options as a string to be split on spaces.
2228
2229 =item $stat
2230
2231 Expected exit status.
2232
2233 =item $out
2234
2235 Reference to a regexp list that must match stdout.
2236
2237 =item $err
2238
2239 Reference to a regexp list that must match stderr.
2240
2241 =item $name
2242
2243 Name of test for error messages.
2244
2245 =item $files
2246
2247 Reference to filename/contents dictionary.
2248
2249 =item @args
2250
2251 Further raw options or arguments.
2252
2253 =back
2254
2255 =cut
2256
2257 sub pgbench
2258 {
2259 local $Test::Builder::Level = $Test::Builder::Level + 1;
2260
2261 my ($self, $opts, $stat, $out, $err, $name, $files, @args) = @_;
2262 my @cmd = (
2263 'pgbench',
2264 split(/\s+/, $opts),
2265 $self->_pgbench_make_files($files), @args);
2266
2267 $self->command_checks_all(\@cmd, $stat, $out, $err, $name);
2268 }
2269
2270 =pod
2271
2272 =item $node->connect_ok($connstr, $test_name, %params)
2273
2274 Attempt a connection with a custom connection string. This is expected
2275 to succeed.
2276
2277 =over
2278
2279 =item sql => B<value>
2280
2281 If this parameter is set, this query is used for the connection attempt
2282 instead of the default.
2283
2284 =item expected_stdout => B<value>
2285
2286 If this regular expression is set, matches it with the output generated.
2287
2288 =item log_like => [ qr/required message/ ]
2289
2290 =item log_unlike => [ qr/prohibited message/ ]
2291
2292 See C<log_check(...)>.
2293
2294 =back
2295
2296 =cut
2297
2298 sub connect_ok
2299 {
2300 local $Test::Builder::Level = $Test::Builder::Level + 1;
2301 my ($self, $connstr, $test_name, %params) = @_;
2302
2303 my $sql;
2304 if (defined($params{sql}))
2305 {
2306 $sql = $params{sql};
2307 }
2308 else
2309 {
2310 $sql = "SELECT \$\$connected with $connstr\$\$";
2311 }
2312
2313 my $log_location = -s $self->logfile;
2314
2315 # Never prompt for a password, any callers of this routine should
2316 # have set up things properly, and this should not block.
2317 my ($ret, $stdout, $stderr) = $self->psql(
2318 'postgres',
2319 $sql,
2320 extra_params => ['-w'],
2321 connstr => "$connstr",
2322 on_error_stop => 0);
2323
2324 is($ret, 0, $test_name);
2325
2326 if (defined($params{expected_stdout}))
2327 {
2328 like($stdout, $params{expected_stdout}, "$test_name: stdout matches");
2329 }
2330
2331 is($stderr, "", "$test_name: no stderr");
2332
2333 $self->log_check($test_name, $log_location, %params);
2334 }
2335
2336 =pod
2337
2338 =item $node->connect_fails($connstr, $test_name, %params)
2339
2340 Attempt a connection with a custom connection string. This is expected
2341 to fail.
2342
2343 =over
2344
2345 =item expected_stderr => B<value>
2346
2347 If this regular expression is set, matches it with the output generated.
2348
2349 =item log_like => [ qr/required message/ ]
2350
2351 =item log_unlike => [ qr/prohibited message/ ]
2352
2353 See C<log_check(...)>.
2354
2355 =back
2356
2357 =cut
2358
2359 sub connect_fails
2360 {
2361 local $Test::Builder::Level = $Test::Builder::Level + 1;
2362 my ($self, $connstr, $test_name, %params) = @_;
2363
2364 my $log_location = -s $self->logfile;
2365
2366 # Never prompt for a password, any callers of this routine should
2367 # have set up things properly, and this should not block.
2368 my ($ret, $stdout, $stderr) = $self->psql(
2369 'postgres',
2370 undef,
2371 extra_params => ['-w'],
2372 connstr => "$connstr");
2373
2374 isnt($ret, 0, $test_name);
2375
2376 if (defined($params{expected_stderr}))
2377 {
2378 like($stderr, $params{expected_stderr}, "$test_name: matches");
2379 }
2380
2381 $self->log_check($test_name, $log_location, %params);
2382 }
2383
2384 =pod
2385
2386 =item $node->poll_query_until($dbname, $query [, $expected ])
2387
2388 Run B<$query> repeatedly, until it returns the B<$expected> result
2389 ('t', or SQL boolean true, by default).
2390 Continues polling if B<psql> returns an error result.
2391 Times out after $PostgreSQL::Test::Utils::timeout_default seconds.
2392 Returns 1 if successful, 0 if timed out.
2393
2394 =cut
2395
2396 sub poll_query_until
2397 {
2398 my ($self, $dbname, $query, $expected) = @_;
2399
2400 local %ENV = $self->_get_env();
2401
2402 $expected = 't' unless defined($expected); # default value
2403
2404 my $cmd = [
2405 $self->installed_command('psql'), '-XAt',
2406 '-d', $self->connstr($dbname)
2407 ];
2408 my ($stdout, $stderr);
2409 my $max_attempts = 10 * $PostgreSQL::Test::Utils::timeout_default;
2410 my $attempts = 0;
2411
2412 while ($attempts < $max_attempts)
2413 {
2414 my $result = IPC::Run::run $cmd, '<', \$query,
2415 '>', \$stdout, '2>', \$stderr;
2416
2417 chomp($stdout);
2418 chomp($stderr);
2419
2420 if ($stdout eq $expected && $stderr eq '')
2421 {
2422 return 1;
2423 }
2424
2425 # Wait 0.1 second before retrying.
2426 usleep(100_000);
2427
2428 $attempts++;
2429 }
2430
2431 # Give up. Print the output from the last attempt, hopefully that's useful
2432 # for debugging.
2433 diag qq(poll_query_until timed out executing this query:
2434 $query
2435 expecting this output:
2436 $expected
2437 last actual query output:
2438 $stdout
2439 with stderr:
2440 $stderr);
2441 return 0;
2442 }
2443
2444 =pod
2445
2446 =item $node->command_ok(...)
2447
2448 Runs a shell command like PostgreSQL::Test::Utils::command_ok, but with PGHOST and PGPORT set
2449 so that the command will default to connecting to this PostgreSQL::Test::Cluster.
2450
2451 =cut
2452
2453 sub command_ok
2454 {
2455 local $Test::Builder::Level = $Test::Builder::Level + 1;
2456
2457 my $self = shift;
2458
2459 local %ENV = $self->_get_env();
2460
2461 PostgreSQL::Test::Utils::command_ok(@_);
2462 return;
2463 }
2464
2465 =pod
2466
2467 =item $node->command_fails(...)
2468
2469 PostgreSQL::Test::Utils::command_fails with our connection parameters. See command_ok(...)
2470
2471 =cut
2472
2473 sub command_fails
2474 {
2475 local $Test::Builder::Level = $Test::Builder::Level + 1;
2476
2477 my $self = shift;
2478
2479 local %ENV = $self->_get_env();
2480
2481 PostgreSQL::Test::Utils::command_fails(@_);
2482 return;
2483 }
2484
2485 =pod
2486
2487 =item $node->command_like(...)
2488
2489 PostgreSQL::Test::Utils::command_like with our connection parameters. See command_ok(...)
2490
2491 =cut
2492
2493 sub command_like
2494 {
2495 local $Test::Builder::Level = $Test::Builder::Level + 1;
2496
2497 my $self = shift;
2498
2499 local %ENV = $self->_get_env();
2500
2501 PostgreSQL::Test::Utils::command_like(@_);
2502 return;
2503 }
2504
2505 =pod
2506
2507 =item $node->command_fails_like(...)
2508
2509 PostgreSQL::Test::Utils::command_fails_like with our connection parameters. See command_ok(...)
2510
2511 =cut
2512
2513 sub command_fails_like
2514 {
2515 local $Test::Builder::Level = $Test::Builder::Level + 1;
2516
2517 my $self = shift;
2518
2519 local %ENV = $self->_get_env();
2520
2521 PostgreSQL::Test::Utils::command_fails_like(@_);
2522 return;
2523 }
2524
2525 =pod
2526
2527 =item $node->command_checks_all(...)
2528
2529 PostgreSQL::Test::Utils::command_checks_all with our connection parameters. See
2530 command_ok(...)
2531
2532 =cut
2533
2534 sub command_checks_all
2535 {
2536 local $Test::Builder::Level = $Test::Builder::Level + 1;
2537
2538 my $self = shift;
2539
2540 local %ENV = $self->_get_env();
2541
2542 PostgreSQL::Test::Utils::command_checks_all(@_);
2543 return;
2544 }
2545
2546 =pod
2547
2548 =item $node->issues_sql_like(cmd, expected_sql, test_name)
2549
2550 Run a command on the node, then verify that $expected_sql appears in the
2551 server log file.
2552
2553 =cut
2554
2555 sub issues_sql_like
2556 {
2557 local $Test::Builder::Level = $Test::Builder::Level + 1;
2558
2559 my ($self, $cmd, $expected_sql, $test_name) = @_;
2560
2561 local %ENV = $self->_get_env();
2562
2563 my $log_location = -s $self->logfile;
2564
2565 my $result = PostgreSQL::Test::Utils::run_log($cmd);
2566 ok($result, "@$cmd exit code 0");
2567 my $log =
2568 PostgreSQL::Test::Utils::slurp_file($self->logfile, $log_location);
2569 like($log, $expected_sql, "$test_name: SQL found in server log");
2570 return;
2571 }
2572
2573 =pod
2574
2575 =item $node->log_content()
2576
2577 Returns the contents of log of the node
2578
2579 =cut
2580
2581 sub log_content
2582 {
2583 my ($self) = @_;
2584 return PostgreSQL::Test::Utils::slurp_file($self->logfile);
2585 }
2586
2587 =pod
2588
2589 =item $node->log_check($offset, $test_name, %parameters)
2590
2591 Check contents of server logs.
2592
2593 =over
2594
2595 =item $test_name
2596
2597 Name of test for error messages.
2598
2599 =item $offset
2600
2601 Offset of the log file.
2602
2603 =item log_like => [ qr/required message/ ]
2604
2605 If given, it must be an array reference containing a list of regular
2606 expressions that must match against the server log, using
2607 C<Test::More::like()>.
2608
2609 =item log_unlike => [ qr/prohibited message/ ]
2610
2611 If given, it must be an array reference containing a list of regular
2612 expressions that must NOT match against the server log. They will be
2613 passed to C<Test::More::unlike()>.
2614
2615 =back
2616
2617 =cut
2618
2619 sub log_check
2620 {
2621 my ($self, $test_name, $offset, %params) = @_;
2622
2623 my (@log_like, @log_unlike);
2624 if (defined($params{log_like}))
2625 {
2626 @log_like = @{ $params{log_like} };
2627 }
2628 if (defined($params{log_unlike}))
2629 {
2630 @log_unlike = @{ $params{log_unlike} };
2631 }
2632
2633 if (@log_like or @log_unlike)
2634 {
2635 my $log_contents =
2636 PostgreSQL::Test::Utils::slurp_file($self->logfile, $offset);
2637
2638 while (my $regex = shift @log_like)
2639 {
2640 like($log_contents, $regex, "$test_name: log matches");
2641 }
2642 while (my $regex = shift @log_unlike)
2643 {
2644 unlike($log_contents, $regex, "$test_name: log does not match");
2645 }
2646 }
2647 }
2648
2649 =pod
2650
2651 =item log_contains(pattern, offset)
2652
2653 Find pattern in logfile of node after offset byte.
2654
2655 =cut
2656
2657 sub log_contains
2658 {
2659 my ($self, $pattern, $offset) = @_;
2660
2661 return PostgreSQL::Test::Utils::slurp_file($self->logfile, $offset) =~
2662 m/$pattern/;
2663 }
2664
2665 =pod
2666
2667 =item $node->run_log(...)
2668
2669 Runs a shell command like PostgreSQL::Test::Utils::run_log, but with connection parameters set
2670 so that the command will default to connecting to this PostgreSQL::Test::Cluster.
2671
2672 =cut
2673
2674 sub run_log
2675 {
2676 my $self = shift;
2677
2678 local %ENV = $self->_get_env();
2679
2680 return PostgreSQL::Test::Utils::run_log(@_);
2681 }
2682
2683 =pod
2684
2685 =item $node->lsn(mode)
2686
2687 Look up WAL locations on the server:
2688
2689 * insert location (primary only, error on replica)
2690 * write location (primary only, error on replica)
2691 * flush location (primary only, error on replica)
2692 * receive location (always undef on primary)
2693 * replay location (always undef on primary)
2694
2695 mode must be specified.
2696
2697 =cut
2698
2699 sub lsn
2700 {
2701 my ($self, $mode) = @_;
2702 my %modes = (
2703 'insert' => 'pg_current_wal_insert_lsn()',
2704 'flush' => 'pg_current_wal_flush_lsn()',
2705 'write' => 'pg_current_wal_lsn()',
2706 'receive' => 'pg_last_wal_receive_lsn()',
2707 'replay' => 'pg_last_wal_replay_lsn()');
2708
2709 $mode = '<undef>' if !defined($mode);
2710 croak "unknown mode for 'lsn': '$mode', valid modes are "
2711 . join(', ', keys %modes)
2712 if !defined($modes{$mode});
2713
2714 my $result = $self->safe_psql('postgres', "SELECT $modes{$mode}");
2715 chomp($result);
2716 if ($result eq '')
2717 {
2718 return;
2719 }
2720 else
2721 {
2722 return $result;
2723 }
2724 }
2725
2726 =pod
2727
2728 =item $node->wait_for_catchup(standby_name, mode, target_lsn)
2729
2730 Wait for the replication connection with application_name standby_name until
2731 its 'mode' replication column in pg_stat_replication equals or passes the
2732 specified or default target_lsn. By default the replay_lsn is waited for,
2733 but 'mode' may be specified to wait for any of sent|write|flush|replay.
2734 The replication connection must be in a streaming state.
2735
2736 When doing physical replication, the standby is usually identified by
2737 passing its PostgreSQL::Test::Cluster instance. When doing logical
2738 replication, standby_name identifies a subscription.
2739
2740 When not in recovery, the default value of target_lsn is $node->lsn('write'),
2741 which ensures that the standby has caught up to what has been committed on
2742 the primary.
2743
2744 When in recovery, the default value of target_lsn is $node->lsn('replay')
2745 instead which ensures that the cascaded standby has caught up to what has been
2746 replayed on the standby.
2747
2748 If you pass an explicit value of target_lsn, it should almost always be
2749 the primary's write LSN; so this parameter is seldom needed except when
2750 querying some intermediate replication node rather than the primary.
2751
2752 If there is no active replication connection from this peer, waits until
2753 poll_query_until timeout.
2754
2755 Requires that the 'postgres' db exists and is accessible.
2756
2757 This is not a test. It die()s on failure.
2758
2759 =cut
2760
2761 sub wait_for_catchup
2762 {
2763 my ($self, $standby_name, $mode, $target_lsn) = @_;
2764 $mode = defined($mode) ? $mode : 'replay';
2765 my %valid_modes =
2766 ('sent' => 1, 'write' => 1, 'flush' => 1, 'replay' => 1);
2767 croak "unknown mode $mode for 'wait_for_catchup', valid modes are "
2768 . join(', ', keys(%valid_modes))
2769 unless exists($valid_modes{$mode});
2770
2771 # Allow passing of a PostgreSQL::Test::Cluster instance as shorthand
2772 if (blessed($standby_name)
2773 && $standby_name->isa("PostgreSQL::Test::Cluster"))
2774 {
2775 $standby_name = $standby_name->name;
2776 }
2777 if (!defined($target_lsn))
2778 {
2779 my $isrecovery =
2780 $self->safe_psql('postgres', "SELECT pg_is_in_recovery()");
2781 chomp($isrecovery);
2782 if ($isrecovery eq 't')
2783 {
2784 $target_lsn = $self->lsn('replay');
2785 }
2786 else
2787 {
2788 $target_lsn = $self->lsn('write');
2789 }
2790 }
2791 print "Waiting for replication conn "
2792 . $standby_name . "'s "
2793 . $mode
2794 . "_lsn to pass "
2795 . $target_lsn . " on "
2796 . $self->name . "\n";
2797 # Before release 12 walreceiver just set the application name to
2798 # "walreceiver"
2799 my $query = qq[SELECT '$target_lsn' <= ${mode}_lsn AND state = 'streaming'
2800 FROM pg_catalog.pg_stat_replication
2801 WHERE application_name IN ('$standby_name', 'walreceiver')];
2802 if (!$self->poll_query_until('postgres', $query))
2803 {
2804 if (PostgreSQL::Test::Utils::has_wal_read_bug)
2805 {
2806 # Mimic having skipped the test file. If >0 tests have run, the
2807 # harness won't accept a skip; otherwise, it won't accept
2808 # done_testing(). Force a nonzero count by running one test.
2809 ok(1, 'dummy test before skip for filesystem bug');
2810 carp "skip rest: timed out waiting for catchup & filesystem bug";
2811 done_testing();
2812 exit 0;
2813 }
2814 else
2815 {
2816 croak "timed out waiting for catchup";
2817 }
2818 }
2819 print "done\n";
2820 return;
2821 }
2822
2823 =pod
2824
2825 =item $node->wait_for_replay_catchup($standby_name [, $base_node ])
2826
2827 Wait for the replication connection with application_name I<$standby_name>
2828 until its B<replay> replication column in pg_stat_replication in I<$node>
2829 equals or passes the I<$base_node>'s B<replay_lsn>. If I<$base_node> is
2830 omitted, the LSN to wait for is obtained from I<$node>.
2831
2832 The replication connection must be in a streaming state.
2833
2834 Requires that the 'postgres' db exists and is accessible.
2835
2836 This is not a test. It die()s on failure.
2837
2838 =cut
2839
2840 sub wait_for_replay_catchup
2841 {
2842 my ($self, $standby_name, $node) = @_;
2843 $node = defined($node) ? $node : $self;
2844
2845 $self->wait_for_catchup($standby_name, 'replay', $node->lsn('flush'));
2846 }
2847
2848 =item $node->wait_for_slot_catchup(slot_name, mode, target_lsn)
2849
2850 Wait for the named replication slot to equal or pass the supplied target_lsn.
2851 The location used is the restart_lsn unless mode is given, in which case it may
2852 be 'restart' or 'confirmed_flush'.
2853
2854 Requires that the 'postgres' db exists and is accessible.
2855
2856 This is not a test. It die()s on failure.
2857
2858 If the slot is not active, will time out after poll_query_until's timeout.
2859
2860 target_lsn may be any arbitrary lsn, but is typically $primary_node->lsn('insert').
2861
2862 Note that for logical slots, restart_lsn is held down by the oldest in-progress tx.
2863
2864 =cut
2865
2866 sub wait_for_slot_catchup
2867 {
2868 my ($self, $slot_name, $mode, $target_lsn) = @_;
2869 $mode = defined($mode) ? $mode : 'restart';
2870 if (!($mode eq 'restart' || $mode eq 'confirmed_flush'))
2871 {
2872 croak "valid modes are restart, confirmed_flush";
2873 }
2874 croak 'target lsn must be specified' unless defined($target_lsn);
2875 print "Waiting for replication slot "
2876 . $slot_name . "'s "
2877 . $mode
2878 . "_lsn to pass "
2879 . $target_lsn . " on "
2880 . $self->name . "\n";
2881 my $query =
2882 qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name';];
2883 $self->poll_query_until('postgres', $query)
2884 or croak "timed out waiting for catchup";
2885 print "done\n";
2886 return;
2887 }
2888
2889 =pod
2890
2891 =item $node->wait_for_subscription_sync(publisher, subname, dbname)
2892
2893 Wait for all tables in pg_subscription_rel to complete the initial
2894 synchronization (i.e to be either in 'syncdone' or 'ready' state).
2895
2896 If the publisher node is given, additionally, check if the subscriber has
2897 caught up to what has been committed on the primary. This is useful to
2898 ensure that the initial data synchronization has been completed after
2899 creating a new subscription.
2900
2901 If there is no active replication connection from this peer, wait until
2902 poll_query_until timeout.
2903
2904 This is not a test. It die()s on failure.
2905
2906 =cut
2907
2908 sub wait_for_subscription_sync
2909 {
2910 my ($self, $publisher, $subname, $dbname) = @_;
2911 my $name = $self->name;
2912
2913 $dbname = defined($dbname) ? $dbname : 'postgres';
2914
2915 # Wait for all tables to finish initial sync.
2916 print "Waiting for all subscriptions in \"$name\" to synchronize data\n";
2917 my $query =
2918 qq[SELECT count(1) = 0 FROM pg_subscription_rel WHERE srsubstate NOT IN ('r', 's');];
2919 $self->poll_query_until($dbname, $query)
2920 or croak "timed out waiting for subscriber to synchronize data";
2921
2922 # Then, wait for the replication to catchup if required.
2923 if (defined($publisher))
2924 {
2925 croak 'subscription name must be specified' unless defined($subname);
2926 $publisher->wait_for_catchup($subname);
2927 }
2928
2929 print "done\n";
2930 return;
2931 }
2932
2933 =pod
2934
2935 =item $node->wait_for_log(regexp, offset)
2936
2937 Waits for the contents of the server log file, starting at the given offset, to
2938 match the supplied regular expression. Checks the entire log if no offset is
2939 given. Times out after $PostgreSQL::Test::Utils::timeout_default seconds.
2940
2941 If successful, returns the length of the entire log file, in bytes.
2942
2943 =cut
2944
2945 sub wait_for_log
2946 {
2947 my ($self, $regexp, $offset) = @_;
2948 $offset = 0 unless defined $offset;
2949
2950 my $max_attempts = 10 * $PostgreSQL::Test::Utils::timeout_default;
2951 my $attempts = 0;
2952
2953 while ($attempts < $max_attempts)
2954 {
2955 my $log =
2956 PostgreSQL::Test::Utils::slurp_file($self->logfile, $offset);
2957
2958 return $offset + length($log) if ($log =~ m/$regexp/);
2959
2960 # Wait 0.1 second before retrying.
2961 usleep(100_000);
2962
2963 $attempts++;
2964 }
2965
2966 croak "timed out waiting for match: $regexp";
2967 }
2968
2969 =pod
2970
2971 =item $node->query_hash($dbname, $query, @columns)
2972
2973 Execute $query on $dbname, replacing any appearance of the string __COLUMNS__
2974 within the query with a comma-separated list of @columns.
2975
2976 If __COLUMNS__ does not appear in the query, its result columns must EXACTLY
2977 match the order and number (but not necessarily alias) of supplied @columns.
2978
2979 The query must return zero or one rows.
2980
2981 Return a hash-ref representation of the results of the query, with any empty
2982 or null results as defined keys with an empty-string value. There is no way
2983 to differentiate between null and empty-string result fields.
2984
2985 If the query returns zero rows, return a hash with all columns empty. There
2986 is no way to differentiate between zero rows returned and a row with only
2987 null columns.
2988
2989 =cut
2990
2991 sub query_hash
2992 {
2993 my ($self, $dbname, $query, @columns) = @_;
2994 croak 'calls in array context for multi-row results not supported yet'
2995 if (wantarray);
2996
2997 # Replace __COLUMNS__ if found
2998 substr($query, index($query, '__COLUMNS__'), length('__COLUMNS__')) =
2999 join(', ', @columns)
3000 if index($query, '__COLUMNS__') >= 0;
3001 my $result = $self->safe_psql($dbname, $query);
3002
3003 # hash slice, see http://stackoverflow.com/a/16755894/398670 .
3004 #
3005 # Fills the hash with empty strings produced by x-operator element
3006 # duplication if result is an empty row
3007 #
3008 my %val;
3009 @val{@columns} =
3010 $result ne '' ? split(qr/\|/, $result, -1) : ('',) x scalar(@columns);
3011 return \%val;
3012 }
3013
3014 =pod
3015
3016 =item $node->slot(slot_name)
3017
3018 Return hash-ref of replication slot data for the named slot, or a hash-ref with
3019 all values '' if not found. Does not differentiate between null and empty string
3020 for fields, no field is ever undef.
3021
3022 The restart_lsn and confirmed_flush_lsn fields are returned verbatim, and also
3023 as a 2-list of [highword, lowword] integer. Since we rely on Perl 5.14 we can't
3024 "use bigint", it's from 5.20, and we can't assume we have Math::Bigint from CPAN
3025 either.
3026
3027 =cut
3028
3029 sub slot
3030 {
3031 my ($self, $slot_name) = @_;
3032 my @columns = (
3033 'plugin', 'slot_type', 'datoid', 'database',
3034 'active', 'active_pid', 'xmin', 'catalog_xmin',
3035 'restart_lsn');
3036 return $self->query_hash(
3037 'postgres',
3038 "SELECT __COLUMNS__ FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name'",
3039 @columns);
3040 }
3041
3042 =pod
3043
3044 =item $node->pg_recvlogical_upto(self, dbname, slot_name, endpos, timeout_secs, ...)
3045
3046 Invoke pg_recvlogical to read from slot_name on dbname until LSN endpos, which
3047 corresponds to pg_recvlogical --endpos. Gives up after timeout (if nonzero).
3048
3049 Disallows pg_recvlogical from internally retrying on error by passing --no-loop.
3050
3051 Plugin options are passed as additional keyword arguments.
3052
3053 If called in scalar context, returns stdout, and die()s on timeout or nonzero return.
3054
3055 If called in array context, returns a tuple of (retval, stdout, stderr, timeout).
3056 timeout is the IPC::Run::Timeout object whose is_expired method can be tested
3057 to check for timeout. retval is undef on timeout.
3058
3059 =cut
3060
3061 sub pg_recvlogical_upto
3062 {
3063 my ($self, $dbname, $slot_name, $endpos, $timeout_secs, %plugin_options)
3064 = @_;
3065
3066 local %ENV = $self->_get_env();
3067
3068 my ($stdout, $stderr);
3069
3070 my $timeout_exception = 'pg_recvlogical timed out';
3071
3072 croak 'slot name must be specified' unless defined($slot_name);
3073 croak 'endpos must be specified' unless defined($endpos);
3074
3075 my @cmd = (
3076 $self->installed_command('pg_recvlogical'),
3077 '-S', $slot_name, '--dbname', $self->connstr($dbname));
3078 push @cmd, '--endpos', $endpos;
3079 push @cmd, '-f', '-', '--no-loop', '--start';
3080
3081 while (my ($k, $v) = each %plugin_options)
3082 {
3083 croak "= is not permitted to appear in replication option name"
3084 if ($k =~ qr/=/);
3085 push @cmd, "-o", "$k=$v";
3086 }
3087
3088 my $timeout;
3089 $timeout =
3090 IPC::Run::timeout($timeout_secs, exception => $timeout_exception)
3091 if $timeout_secs;
3092 my $ret = 0;
3093
3094 do
3095 {
3096 local $@;
3097 eval {
3098 IPC::Run::run(\@cmd, ">", \$stdout, "2>", \$stderr, $timeout);
3099 $ret = $?;
3100 };
3101 my $exc_save = $@;
3102 if ($exc_save)
3103 {
3104
3105 # IPC::Run::run threw an exception. re-throw unless it's a
3106 # timeout, which we'll handle by testing is_expired
3107 die $exc_save
3108 if (blessed($exc_save) || $exc_save !~ qr/$timeout_exception/);
3109
3110 $ret = undef;
3111
3112 die "Got timeout exception '$exc_save' but timer not expired?!"
3113 unless $timeout->is_expired;
3114
3115 die
3116 "$exc_save waiting for endpos $endpos with stdout '$stdout', stderr '$stderr'"
3117 unless wantarray;
3118 }
3119 };
3120
3121 if (wantarray)
3122 {
3123 return ($ret, $stdout, $stderr, $timeout);
3124 }
3125 else
3126 {
3127 die
3128 "pg_recvlogical exited with code '$ret', stdout '$stdout' and stderr '$stderr'"
3129 if $ret;
3130 return $stdout;
3131 }
3132 }
3133
3134 =pod
3135
3136 =item $node->corrupt_page_checksum(self, file, page_offset)
3137
3138 Intentionally corrupt the checksum field of one page in a file.
3139 The server must be stopped for this to work reliably.
3140
3141 The file name should be specified relative to the cluster datadir.
3142 page_offset had better be a multiple of the cluster's block size.
3143
3144 =cut
3145
3146 sub corrupt_page_checksum
3147 {
3148 my ($self, $file, $page_offset) = @_;
3149 my $pgdata = $self->data_dir;
3150 my $pageheader;
3151
3152 open my $fh, '+<', "$pgdata/$file" or die "open($file) failed: $!";
3153 binmode $fh;
3154 sysseek($fh, $page_offset, 0) or die "sysseek failed: $!";
3155 sysread($fh, $pageheader, 24) or die "sysread failed: $!";
3156 # This inverts the pd_checksum field (only); see struct PageHeaderData
3157 $pageheader ^= "\0\0\0\0\0\0\0\0\xff\xff";
3158 sysseek($fh, $page_offset, 0) or die "sysseek failed: $!";
3159 syswrite($fh, $pageheader) or die "syswrite failed: $!";
3160 close $fh;
3161
3162 return;
3163 }
3164
3165 #
3166 # Signal handlers
3167 #
3168 $SIG{TERM} = $SIG{INT} = sub {
3169 die "death by signal";
3170 };
3171
3172 =pod
3173
3174 =item $node->create_logical_slot_on_standby(self, primary, slot_name, dbname)
3175
3176 Create logical replication slot on given standby
3177
3178 =cut
3179
3180 sub create_logical_slot_on_standby
3181 {
3182 my ($self, $primary, $slot_name, $dbname) = @_;
3183 my ($stdout, $stderr);
3184
3185 my $handle;
3186
3187 $handle = IPC::Run::start(
3188 [
3189 'pg_recvlogical', '-d',
3190 $self->connstr($dbname), '-P',
3191 'test_decoding', '-S',
3192 $slot_name, '--create-slot'
3193 ],
3194 '>',
3195 \$stdout,
3196 '2>',
3197 \$stderr);
3198
3199 # Once the slot's restart_lsn is determined, the standby looks for
3200 # xl_running_xacts WAL record from the restart_lsn onwards. First wait
3201 # until the slot restart_lsn is determined.
3202
3203 $self->poll_query_until(
3204 'postgres', qq[
3205 SELECT restart_lsn IS NOT NULL
3206 FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name'
3207 ])
3208 or die
3209 "timed out waiting for logical slot to calculate its restart_lsn";
3210
3211 # Then arrange for the xl_running_xacts record for which pg_recvlogical is
3212 # waiting.
3213 $primary->safe_psql('postgres', 'SELECT pg_log_standby_snapshot()');
3214
3215 $handle->finish();
3216
3217 is($self->slot($slot_name)->{'slot_type'},
3218 'logical', $slot_name . ' on standby created')
3219 or die "could not create slot" . $slot_name;
3220 }
3221
3222 =pod
3223
3224 =item $node->advance_wal(num)
3225
3226 Advance WAL of node by given number of segments.
3227
3228 =cut
3229
3230 sub advance_wal
3231 {
3232 my ($self, $num) = @_;
3233
3234 # Advance by $n segments (= (wal_segment_size * $num) bytes).
3235 # pg_switch_wal() forces a WAL flush, making pg_logical_emit_message()
3236 # safe to use in non-transactional mode.
3237 for (my $i = 0; $i < $num; $i++)
3238 {
3239 $self->safe_psql(
3240 'postgres', qq{
3241 SELECT pg_logical_emit_message(false, '', 'foo');
3242 SELECT pg_switch_wal();
3243 });
3244 }
3245 }
3246
3247 =pod
3248
3249 =back
3250
3251 =cut
3252
3253 ##########################################################################
3254
3255 package PostgreSQL::Test::Cluster::V_11
3256 ; ## no critic (ProhibitMultiplePackages)
3257
3258 use parent -norequire, qw(PostgreSQL::Test::Cluster);
3259
3260 # https://www.postgresql.org/docs/11/release-11.html
3261
3262 # max_wal_senders + superuser_reserved_connections must be < max_connections
3263 # uses recovery.conf
3264
3265 sub _recovery_file { return "recovery.conf"; }
3266
3267 sub set_standby_mode
3268 {
3269 my $self = shift;
3270 $self->append_conf("recovery.conf", "standby_mode = on\n");
3271 }
3272
3273 sub init
3274 {
3275 my ($self, %params) = @_;
3276 $self->SUPER::init(%params);
3277 $self->adjust_conf('postgresql.conf', 'max_wal_senders',
3278 $params{allows_streaming} ? 5 : 0);
3279 }
3280
3281 ##########################################################################
3282
3283 package PostgreSQL::Test::Cluster::V_10
3284 ; ## no critic (ProhibitMultiplePackages)
3285
3286 use parent -norequire, qw(PostgreSQL::Test::Cluster::V_11);
3287
3288 # https://www.postgresql.org/docs/10/release-10.html
3289
3290 ########################################################################
3291
3292 1;