text:
=pod

=head1 NAME

PostgresNode - class representing PostgreSQL server instance

=head1 SYNOPSIS

  use PostgresNode;

  my $node = PostgresNode->get_new_node('mynode');

  # Create a data directory with initdb
  $node->init();

  # Start the PostgreSQL server
  $node->start();

  # Change a setting and restart
  $node->append_conf('postgresql.conf', 'hot_standby = on');
  $node->restart();

  # run a query with psql, like:
  #   echo 'SELECT 1' | psql -qAXt postgres -v ON_ERROR_STOP=1
  $psql_stdout = $node->safe_psql('postgres', 'SELECT 1');

  # Run psql with a timeout, capturing stdout and stderr
  # as well as the psql exit code. Pass some extra psql
  # options. If there's an error from psql raise an exception.
  my ($stdout, $stderr, $timed_out);
  my $cmdret = $node->psql('postgres', 'SELECT pg_sleep(60)',
	  stdout => \$stdout, stderr => \$stderr,
	  timeout => 30, timed_out => \$timed_out,
	  extra_params => ['--single-transaction'],
	  on_error_die => 1)
  print "Sleep timed out" if $timed_out;

  # Similar thing, more convenient in common cases
  my ($cmdret, $stdout, $stderr) =
      $node->psql('postgres', 'SELECT 1');

  # run query every second until it returns 't'
  # or times out
  $node->poll_query_until('postgres', q|SELECT random() < 0.1;|')
    or die "timed out";

  # Do an online pg_basebackup
  my $ret = $node->backup('testbackup1');

  # Take a backup of a running server
  my $ret = $node->backup_fs_hot('testbackup2');

  # Take a backup of a stopped server
  $node->stop;
  my $ret = $node->backup_fs_cold('testbackup3')

  # Restore it to create a new independent node (not a replica)
  my $replica = get_new_node('replica');
  $replica->init_from_backup($node, 'testbackup');
  $replica->start;

  # Stop the server
  $node->stop('fast');

=head1 DESCRIPTION

PostgresNode contains a set of routines able to work on a PostgreSQL node,
allowing to start, stop, backup and initialize it with various options.
The set of nodes managed by a given test is also managed by this module.

In addition to node management, PostgresNode instances have some wrappers
around Test::More functions to run commands with an environment set up to
point to the instance.

The IPC::Run module is required.

=cut

package PostgresNode;

use strict;
use warnings;

use Carp;
use Config;
use Cwd;
use Exporter 'import';
use Fcntl qw(:mode);
use File::Basename;
use File::Path qw(rmtree);
use File::Spec;
use File::stat qw(stat);
use File::Temp ();
use IPC::Run;
use RecursiveCopy;
use Socket;
use Test::More;
use TestLib ();
use Time::HiRes qw(usleep);
use Scalar::Util qw(blessed);

our @EXPORT = qw(
  get_new_node
);

our ($use_tcp, $test_localhost, $test_pghost, $last_host_assigned,
	$last_port_assigned, @all_nodes, $died);

our ($last_dbid);

# Windows path to virtual file system root

our $vfs_path = '';
if ($Config{osname} eq 'msys')
{
	$vfs_path = `cd / && pwd -W`;
	chomp $vfs_path;
}

INIT
{

	# Set PGHOST for backward compatibility.  This doesn't work for own_host
	# nodes, so prefer to not rely on this when writing new tests.
	$use_tcp            = $TestLib::windows_os;
	$test_localhost     = "127.0.0.1";
	$last_host_assigned = 1;
	$test_pghost        = $use_tcp ? $test_localhost : TestLib::tempdir_short;
	$ENV{PGHOST}        = $test_pghost;
	$ENV{PGDATABASE}    = 'postgres';

	# Tracking of last port value assigned to accelerate free port lookup.
	$last_port_assigned = int(rand() * 16384) + 49152;

	$last_dbid			= 0
}

=pod

=head1 METHODS

=over

=item PostgresNode::new($class, $name, $pghost, $pgport)

Create a new PostgresNode instance. Does not initdb or start it.

You should generally prefer to use get_new_node() instead since it takes care
of finding port numbers, registering instances for cleanup, etc.

=cut

sub new
{
	my ($class, $name, $pghost, $pgport) = @_;
	my $testname = basename($0);
	$testname =~ s/\.[^.]+$//;

	# GPDB needs unique dbid for each node for certain operations
	$last_dbid = $last_dbid + 1;

	my $self = {
		_port    => $pgport,
		_host    => $pghost,
		_dbid    => $last_dbid,
		_basedir => "$TestLib::tmp_check/t_${testname}_${name}_data",
		_name    => $name,
		_logfile_generation => 0,
		_logfile_base       => "$TestLib::log_path/${testname}_${name}",
		_logfile            => "$TestLib::log_path/${testname}_${name}.log"
	};

	bless $self, $class;
	mkdir $self->{_basedir}
	  or
	  BAIL_OUT("could not create data directory \"$self->{_basedir}\": $!");
	$self->dump_info;

	return $self;
}

=pod

=item $node->port()

Get the port number assigned to the host. This won't necessarily be a TCP port
open on the local host since we prefer to use unix sockets if possible.

Use $node->connstr() if you want a connection string.

=cut

sub port
{
	my ($self) = @_;
	return $self->{_port};
}

=pod

=item $node->host()

Return the host (like PGHOST) for this instance. May be a UNIX socket path.

Use $node->connstr() if you want a connection string.

=cut

sub host
{
	my ($self) = @_;
	return $self->{_host};
}

=pod

=item $node->dbid()

Return the dbid for this instance.

=cut

sub dbid
{
	my ($self) = @_;
	return $self->{_dbid};
}

=pod

=item $node->basedir()

The directory all the node's files will be within - datadir, archive directory,
backups, etc.

=cut

sub basedir
{
	my ($self) = @_;
	return $self->{_basedir};
}

=pod

=item $node->name()

The name assigned to the node at creation time.

=cut

sub name
{
	my ($self) = @_;
	return $self->{_name};
}

=pod

=item $node->logfile()

Path to the PostgreSQL log file for this instance.

=cut

sub logfile
{
	my ($self) = @_;
	return $self->{_logfile};
}

=pod

=item $node->connstr()

Get a libpq connection string that will establish a connection to
this node. Suitable for passing to psql, DBD::Pg, etc.

=cut

sub connstr
{
	my ($self, $dbname) = @_;
	my $pgport = $self->port;
	my $pghost = $self->host;
	if (!defined($dbname))
	{
		return "port=$pgport host=$pghost";
	}

	# Escape properly the database string before using it, only
	# single quotes and backslashes need to be treated this way.
	$dbname =~ s#\\#\\\\#g;
	$dbname =~ s#\'#\\\'#g;

	return "port=$pgport host=$pghost dbname='$dbname'";
}

=pod

=item $node->group_access()

Does the data dir allow group access?

=cut

sub group_access
{
	my ($self) = @_;

	my $dir_stat = stat($self->data_dir);

	defined($dir_stat)
	  or die('unable to stat ' . $self->data_dir);

	return (S_IMODE($dir_stat->mode) == 0750);
}

=pod

=item $node->data_dir()

Returns the path to the data directory. postgresql.conf and pg_hba.conf are
always here.

=cut

sub data_dir
{
	my ($self) = @_;
	my $res = $self->basedir;
	return "$res/pgdata";
}

=pod

=item $node->archive_dir()

If archiving is enabled, WAL files go here.

=cut

sub archive_dir
{
	my ($self) = @_;
	my $basedir = $self->basedir;
	return "$basedir/archives";
}

=pod

=item $node->backup_dir()

The output path for backups taken with $node->backup()

=cut

sub backup_dir
{
	my ($self) = @_;
	my $basedir = $self->basedir;
	return "$basedir/backup";
}

=pod

=item $node->info()

Return a string containing human-readable diagnostic information (paths, etc)
about this node.

=cut

sub info
{
	my ($self) = @_;
	my $_info = '';
	open my $fh, '>', \$_info or die;
	print $fh "Name: " . $self->name . "\n";
	print $fh "Data directory: " . $self->data_dir . "\n";
	print $fh "Backup directory: " . $self->backup_dir . "\n";
	print $fh "Archive directory: " . $self->archive_dir . "\n";
	print $fh "Connection string: " . $self->connstr . "\n";
	print $fh "Log file: " . $self->logfile . "\n";
	close $fh or die;
	return $_info;
}

=pod

=item $node->dump_info()

Print $node->info()

=cut

sub dump_info
{
	my ($self) = @_;
	print $self->info;
	return;
}

# Internal method to set up trusted pg_hba.conf for replication.  Not
# documented because you shouldn't use it, it's called automatically if needed.
sub set_replication_conf
{
	my ($self) = @_;
	my $pgdata = $self->data_dir;

	$self->host eq $test_pghost
	  or croak "set_replication_conf only works with the default host";

	open my $hba, '>>', "$pgdata/pg_hba.conf";
	print $hba "\n# Allow replication (set up by PostgresNode.pm)\n";
	if ($TestLib::windows_os)
	{
		print $hba
		  "host replication all $test_localhost/32 sspi include_realm=1 map=regress\n";
	}
	close $hba;
	return;
}

=pod

=item $node->init(...)

Initialize a new cluster for testing.

Authentication is set up so that only the current OS user can access the
cluster. On Unix, we use Unix domain socket connections, with the socket in
a directory that's only accessible to the current user to ensure that.
On Windows, we use SSPI authentication to ensure the same (by pg_regress
--config-auth).

WAL archiving can be enabled on this node by passing the keyword parameter
has_archiving => 1. This is disabled by default.

postgresql.conf can be set up for replication by passing the keyword
parameter allows_streaming => 'logical' or 'physical' (passing 1 will also
suffice for physical replication) depending on type of replication that
should be enabled. This is disabled by default.

The new node is set up in a fast but unsafe configuration where fsync is
disabled.

=cut

sub init
{
	my ($self, %params) = @_;
	my $port   = $self->port;
	my $pgdata = $self->data_dir;
	my $host   = $self->host;
	my $dbid   = $self->dbid;

	print "####### HOST = $host\n";

	$params{allows_streaming} = 0 unless defined $params{allows_streaming};
	$params{has_archiving}    = 0 unless defined $params{has_archiving};

	mkdir $self->backup_dir;
	mkdir $self->archive_dir;

	TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N',
		@{ $params{extra} });
	TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata,
		@{ $params{auth_extra} });

	open my $conf, '>>', "$pgdata/postgresql.conf";
	print $conf "\n# Added by PostgresNode.pm\n";
	print $conf "fsync = off\n";
	print $conf "restart_after_crash = off\n";
	print $conf "log_line_prefix = '%m [%p] %q%a '\n";
	print $conf "log_statement = all\n";
	print $conf "log_replication_commands = on\n";
	print $conf "wal_retrieve_retry_interval = '500ms'\n";

	# In GPBB, logging_collector is enabled by default. Disable it, so that
	# upstream tests behave the same as in PostgreSQL. In particular, the
	# issues_sql_like() doesn't work if logging_collector is enabled.
	# Individual tests can override this.
	print $conf "logging_collector = off\n";

	# If a setting tends to affect whether tests pass or fail, print it after
	# TEMP_CONFIG.  Otherwise, print it before TEMP_CONFIG, thereby permitting
	# overrides.  Settings that merely improve performance or ease debugging
	# belong before TEMP_CONFIG.
	print $conf TestLib::slurp_file($ENV{TEMP_CONFIG})
	  if defined $ENV{TEMP_CONFIG};

	# XXX Neutralize any stats_temp_directory in TEMP_CONFIG.  Nodes running
	# concurrently must not share a stats_temp_directory.
	print $conf "stats_temp_directory = 'pg_stat_tmp'\n";

	if ($params{allows_streaming})
	{
		if ($params{allows_streaming} eq "logical")
		{
			print $conf "wal_level = logical\n";
		}
		else
		{
			print $conf "wal_level = replica\n";
		}
		print $conf "max_wal_senders = 5\n";
		print $conf "max_replication_slots = 5\n";
		print $conf "max_wal_size = 128MB\n";
		print $conf "shared_buffers = 1MB\n";
		print $conf "wal_log_hints = on\n";
		print $conf "hot_standby = on\n";
		print $conf "max_connections = 20\n";
	}
	else
	{
		print $conf "wal_level = minimal\n";
		print $conf "max_wal_senders = 0\n";
	}

	print $conf "port = $port\n";
	if ($use_tcp)
	{
		print $conf "unix_socket_directories = ''\n";
		print $conf "listen_addresses = '$host'\n";
	}
	else
	{
		print $conf "unix_socket_directories = '$host'\n";
		print $conf "listen_addresses = ''\n";
	}

	# GPDB: Enable Global Deadlock Detector
	print $conf "gp_enable_global_deadlock_detector = on\n";

	close $conf;

	chmod($self->group_access ? 0640 : 0600, "$pgdata/postgresql.conf")
	  or die("unable to set permissions for $pgdata/postgresql.conf");

	$self->set_replication_conf if $params{allows_streaming};
	$self->enable_archiving     if $params{has_archiving};

	# We have to specify the master's dbid explicitly because initdb
	# only creates an empty file. gpconfigurenewseg is tasked with
	# populating the master's dbid.
	open $conf, '>>', "$pgdata/internal.auto.conf";
	print $conf "\n# Added by PostgresNode.pm\n";
	print $conf "gp_dbid=$dbid\n";
	close $conf;

	chmod($self->group_access ? 0640 : 0600, "$pgdata/internal.auto.conf")
	  or die("unable to set permissions for $pgdata/internal.auto.conf");

	return;
}

=pod

=item $node->append_conf(filename, str)

A shortcut method to append to files like pg_hba.conf and postgresql.conf.

Does no validation or sanity checking. Does not reload the configuration
after writing.

A newline is automatically appended to the string.

=cut

sub append_conf
{
	my ($self, $filename, $str) = @_;

	my $conffile = $self->data_dir . '/' . $filename;

	TestLib::append_to_file($conffile, $str . "\n");

	chmod($self->group_access() ? 0640 : 0600, $conffile)
	  or die("unable to set permissions for $conffile");

	return;
}

=pod

=item $node->backup(backup_name)

Create a hot backup with B<pg_basebackup> in subdirectory B<backup_name> of
B<< $node->backup_dir >>, including the WAL. WAL files
fetched at the end of the backup, not streamed.

You'll have to configure a suitable B<max_wal_senders> on the
target server since it isn't done by default.

=cut

sub backup
{
	my ($self, $backup_name) = @_;
	my $backup_path = $self->backup_dir . '/' . $backup_name;
	my $name        = $self->name;

	print "# Taking pg_basebackup $backup_name from node \"$name\"\n";
	TestLib::system_or_bail('pg_basebackup', '-D', $backup_path, '-h',
		$self->host, '-p', $self->port, '--no-sync', '--target-gp-dbid', 99);
	print "# Backup finished\n";
	return;
}

=item $node->backup_fs_hot(backup_name)

Create a backup with a filesystem level copy in subdirectory B<backup_name> of
B<< $node->backup_dir >>, including WAL.

Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
used. This is not checked or enforced.

The backup name is passed as the backup label to B<pg_start_backup()>.

=cut

sub backup_fs_hot
{
	my ($self, $backup_name) = @_;
	$self->_backup_fs($backup_name, 1);
	return;
}

=item $node->backup_fs_cold(backup_name)

Create a backup with a filesystem level copy in subdirectory B<backup_name> of
B<< $node->backup_dir >>, including WAL. The server must be
stopped as no attempt to handle concurrent writes is made.

Use B<backup> or B<backup_fs_hot> if you want to back up a running server.

=cut

sub backup_fs_cold
{
	my ($self, $backup_name) = @_;
	$self->_backup_fs($backup_name, 0);
	return;
}

# Common sub of backup_fs_hot and backup_fs_cold
sub _backup_fs
{
	my ($self, $backup_name, $hot) = @_;
	my $backup_path = $self->backup_dir . '/' . $backup_name;
	my $port        = $self->port;
	my $name        = $self->name;

	print "# Taking filesystem backup $backup_name from node \"$name\"\n";

	if ($hot)
	{
		my $stdout = $self->safe_psql('postgres',
			"SELECT * FROM pg_start_backup('$backup_name');");
		print "# pg_start_backup: $stdout\n";
	}

	RecursiveCopy::copypath(
		$self->data_dir,
		$backup_path,
		filterfn => sub {
			my $src = shift;
			return ($src ne 'log' and $src ne 'postmaster.pid');
		});

	if ($hot)
	{

		# We ignore pg_stop_backup's return value. We also assume archiving
		# is enabled; otherwise the caller will have to copy the remaining
		# segments.
		my $stdout =
		  $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
		print "# pg_stop_backup: $stdout\n";
	}

	print "# Backup finished\n";
	return;
}

=pod

=item $node->init_from_backup(root_node, backup_name)

Initialize a node from a backup, which may come from this node or a different
node. root_node must be a PostgresNode reference, backup_name the string name
of a backup previously created on that node with $node->backup.

Does not start the node after initializing it.

Streaming replication can be enabled on this node by passing the keyword
parameter has_streaming => 1. This is disabled by default.

Restoring WAL segments from archives using restore_command can be enabled
by passing the keyword parameter has_restoring => 1. This is disabled by
default.

The backup is copied, leaving the original unmodified. pg_hba.conf is
unconditionally set to enable replication connections.

=cut

sub init_from_backup
{
	my ($self, $root_node, $backup_name, %params) = @_;
	my $backup_path = $root_node->backup_dir . '/' . $backup_name;
	my $host        = $self->host;
	my $port        = $self->port;
	my $node_name   = $self->name;
	my $root_name   = $root_node->name;

	$params{has_streaming} = 0 unless defined $params{has_streaming};
	$params{has_restoring} = 0 unless defined $params{has_restoring};

	print
	  "# Initializing node \"$node_name\" from backup \"$backup_name\" of node \"$root_name\"\n";
	croak "Backup \"$backup_name\" does not exist at $backup_path"
	  unless -d $backup_path;

	mkdir $self->backup_dir;
	mkdir $self->archive_dir;

	my $data_path = $self->data_dir;
	rmdir($data_path);
	RecursiveCopy::copypath($backup_path, $data_path);
	chmod(0700, $data_path);

	# Base configuration for this node
	$self->append_conf(
		'postgresql.conf',
		qq(
port = $port
));
	if ($use_tcp)
	{
		$self->append_conf('postgresql.conf', "listen_addresses = '$host'");
	}
	else
	{
		$self->append_conf('postgresql.conf',
			"unix_socket_directories = '$host'");
	}
	$self->enable_streaming($root_node) if $params{has_streaming};
	$self->enable_restoring($root_node) if $params{has_restoring};
	return;
}

=pod

=item $node->rotate_logfile()

Switch to a new PostgreSQL log file.  This does not alter any running
PostgreSQL process.  Subsequent method calls, including pg_ctl invocations,
will use the new name.  Return the new name.

=cut

sub rotate_logfile
{
	my ($self) = @_;
	$self->{_logfile} = sprintf('%s_%d.log',
		$self->{_logfile_base},
		++$self->{_logfile_generation});
	return $self->{_logfile};
}

=pod

=item $node->start(%params) => success_or_failure

Wrapper for pg_ctl start

Start the node and wait until it is ready to accept connections.

=over

=item fail_ok => 1

By default, failure terminates the entire F<prove> invocation.  If given,
instead return a true or false value to indicate success or failure.

=back

=cut

sub start
{
	my ($self, %params) = @_;
	my $port   = $self->port;
	my $pgdata = $self->data_dir;
	my $name   = $self->name;
	my $ret;

	BAIL_OUT("node \"$name\" is already running") if defined $self->{_pid};

	print("### Starting node \"$name\"\n");

	{
		# Temporarily unset PGAPPNAME so that the server doesn't
		# inherit it.  Otherwise this could affect libpqwalreceiver
		# connections in confusing ways.
		local %ENV = %ENV;
		delete $ENV{PGAPPNAME};

		# Note: We set the cluster_name here, not in postgresql.conf (in
		# sub init) so that it does not get copied to standbys.
		$ret = TestLib::system_log('pg_ctl', '-D', $self->data_dir, '-l',
		$self->logfile, '-o', "--cluster-name=$name -c gp_role=utility --gp_dbid=$self->{_dbid} --gp_contentid=0",
			'start');
	}

	if ($ret != 0)
	{
		print "# pg_ctl start failed; logfile:\n";
		print TestLib::slurp_file($self->logfile);
		BAIL_OUT("pg_ctl start failed") unless $params{fail_ok};
		return 0;
	}

	$self->_update_pid(1);
	$ENV{PGOPTIONS}      = '-c gp_role=utility';
	return 1;
}

=pod

=item $node->kill9()

Send SIGKILL (signal 9) to the postmaster.

Note: if the node is already known stopped, this does nothing.
However, if we think it's running and it's not, it's important for
this to fail.  Otherwise, tests might fail to detect server crashes.

=cut

sub kill9
{
	my ($self) = @_;
	my $name = $self->name;
	return unless defined $self->{_pid};
	print "### Killing node \"$name\" using signal 9\n";
	# kill(9, ...) fails under msys Perl 5.8.8, so fall back on pg_ctl.
	kill(9, $self->{_pid})
	  or TestLib::system_or_bail('pg_ctl', 'kill', 'KILL', $self->{_pid});
	$self->{_pid} = undef;
	return;
}

=pod

=item $node->stop(mode)

Stop the node using pg_ctl -m $mode and wait for it to stop.

Note: if the node is already known stopped, this does nothing.
However, if we think it's running and it's not, it's important for
this to fail.  Otherwise, tests might fail to detect server crashes.

=cut

sub stop
{
	my ($self, $mode) = @_;
	my $port   = $self->port;
	my $pgdata = $self->data_dir;
	my $name   = $self->name;
	$mode = 'fast' unless defined $mode;
	return unless defined $self->{_pid};
	print "### Stopping node \"$name\" using mode $mode\n";
	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-m', $mode, 'stop');
	$self->_update_pid(0);
	return;
}

=pod

=item $node->reload()

Reload configuration parameters on the node.

=cut

sub reload
{
	my ($self) = @_;
	my $port   = $self->port;
	my $pgdata = $self->data_dir;
	my $name   = $self->name;
	print "### Reloading node \"$name\"\n";
	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, 'reload');
	return;
}

=pod

=item $node->restart()

Wrapper for pg_ctl restart

=cut

sub restart
{
	my ($self)  = @_;
	my $port    = $self->port;
	my $pgdata  = $self->data_dir;
	my $logfile = $self->logfile;
	my $name    = $self->name;

	print "### Restarting node \"$name\"\n";

	{
		local %ENV = %ENV;
		delete $ENV{PGAPPNAME};

		TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
			'restart');
	}

	$self->_update_pid(1);
	return;
}

=pod

=item $node->promote()

Wrapper for pg_ctl promote

=cut

sub promote
{
	my ($self)  = @_;
	my $port    = $self->port;
	my $pgdata  = $self->data_dir;
	my $logfile = $self->logfile;
	my $name    = $self->name;
	print "### Promoting node \"$name\"\n";
	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
		'promote');
	return;
}

=pod

=item $node->logrotate()

Wrapper for pg_ctl logrotate

=cut

sub logrotate
{
	my ($self)  = @_;
	my $port    = $self->port;
	my $pgdata  = $self->data_dir;
	my $logfile = $self->logfile;
	my $name    = $self->name;
	print "### Rotating log in node \"$name\"\n";
	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
		'logrotate');
	return;
}

# Internal routine to enable streaming replication on a standby node.
sub enable_streaming
{
	my ($self, $root_node) = @_;
	my $root_connstr = $root_node->connstr;
	my $name         = $self->name;

	print "### Enabling streaming replication for node \"$name\"\n";
	$self->append_conf(
		'postgresql.conf', qq(
primary_conninfo='$root_connstr'
));
	$self->set_standby_mode();
	return;
}

# Internal routine to enable archive recovery command on a standby node
sub enable_restoring
{
	my ($self, $root_node) = @_;
	my $path = TestLib::perl2host($root_node->archive_dir);
	my $name = $self->name;

	print "### Enabling WAL restore for node \"$name\"\n";

	# On Windows, the path specified in the restore command needs to use
	# double back-slashes to work properly and to be able to detect properly
	# the file targeted by the copy command, so the directory value used
	# in this routine, using only one back-slash, need to be properly changed
	# first. Paths also need to be double-quoted to prevent failures where
	# the path contains spaces.
	$path =~ s{\\}{\\\\}g if ($TestLib::windows_os);
	my $copy_command =
	  $TestLib::windows_os
	  ? qq{copy "$path\\\\%f" "%p"}
	  : qq{cp "$path/%f" "%p"};

	$self->append_conf(
		'postgresql.conf', qq(
restore_command = '$copy_command'
));
	$self->set_standby_mode();
	return;
}

=pod

=item $node->set_standby_mode()

Place standby.signal file.

=cut

sub set_standby_mode
{
	my ($self) = @_;

	$self->append_conf('standby.signal', '');
	return;
}

# Internal routine to enable archiving
sub enable_archiving
{
	my ($self) = @_;
	my $path   = TestLib::perl2host($self->archive_dir);
	my $name   = $self->name;

	print "### Enabling WAL archiving for node \"$name\"\n";

	# On Windows, the path specified in the restore command needs to use
	# double back-slashes to work properly and to be able to detect properly
	# the file targeted by the copy command, so the directory value used
	# in this routine, using only one back-slash, need to be properly changed
	# first. Paths also need to be double-quoted to prevent failures where
	# the path contains spaces.
	$path =~ s{\\}{\\\\}g if ($TestLib::windows_os);
	my $copy_command =
	  $TestLib::windows_os
	  ? qq{copy "%p" "$path\\\\%f"}
	  : qq{cp "%p" "$path/%f"};

	# Enable archive_mode and archive_command on node
	$self->append_conf(
		'postgresql.conf', qq(
archive_mode = on
archive_command = '$copy_command'
));
	return;
}

# Internal method
sub _update_pid
{
	my ($self, $is_running) = @_;
	my $name = $self->name;

	#GPDB_12_MERGE_FIXME: somehow without this fails to find the pid file
	sleep(1);

	# If we can open the PID file, read its first line and that's the PID we
	# want.
	if (open my $pidfile, '<', $self->data_dir . "/postmaster.pid")
	{
		chomp($self->{_pid} = <$pidfile>);
		print "# Postmaster PID for node \"$name\" is $self->{_pid}\n";
		close $pidfile;

		# If we found a pidfile when there shouldn't be one, complain.
		BAIL_OUT("postmaster.pid unexpectedly present") unless $is_running;
		return;
	}

	$self->{_pid} = undef;
	print "# No postmaster PID for node \"$name\"\n";

	# Complain if we expected to find a pidfile.
	BAIL_OUT("postmaster.pid unexpectedly not present") if $is_running;
	return;
}

=pod

=item PostgresNode->get_new_node(node_name, %params)

Build a new object of class C<PostgresNode> (or of a subclass, if you have
one), assigning a free port number.  Remembers the node, to prevent its port
number from being reused for another node, and to ensure that it gets
shut down when the test script exits.

You should generally use this instead of C<PostgresNode::new(...)>.

=over

=item port => [1,65535]

By default, this function assigns a port number to each node.  Specify this to
force a particular port number.  The caller is responsible for evaluating
potential conflicts and privilege requirements.

=item own_host => 1

By default, all nodes use the same PGHOST value.  If specified, generate a
PGHOST specific to this node.  This allows multiple nodes to use the same
port.

=back

For backwards compatibility, it is also exported as a standalone function,
which can only create objects of class C<PostgresNode>.

=cut

sub get_new_node
{
	my $class = 'PostgresNode';
	$class = shift if scalar(@_) % 2 != 1;
	my ($name, %params) = @_;
	my $port_is_forced = defined $params{port};
	my $found          = $port_is_forced;
	my $port = $port_is_forced ? $params{port} : $last_port_assigned;

	while ($found == 0)
	{

		# advance $port, wrapping correctly around range end
		$port = 49152 if ++$port >= 65536;
		print "# Checking port $port\n";

		# Check first that candidate port number is not included in
		# the list of already-registered nodes.
		$found = 1;
		foreach my $node (@all_nodes)
		{
			$found = 0 if ($node->port == $port);
		}

		# Check to see if anything else is listening on this TCP port.  This
		# is *necessary* on $use_tcp (Windows) configurations.  Seek a port
		# available for all possible listen_addresses values, for own_host
		# nodes and so the caller can harness this port for the widest range
		# of purposes.  The 0.0.0.0 test achieves that for post-2006 Cygwin,
		# which automatically sets SO_EXCLUSIVEADDRUSE.  The same holds for
		# MSYS (a Cygwin fork).  Testing 0.0.0.0 is insufficient for Windows
		# native Perl (https://stackoverflow.com/a/14388707), so we also test
		# individual addresses.
		#
		# This seems like a good idea on Unixen as well, even though we don't
		# ask the postmaster to open a TCP port on Unix.  On Non-Linux,
		# non-Windows kernels, binding to 127.0.0.1/24 addresses other than
		# 127.0.0.1 might fail with EADDRNOTAVAIL.  Binding to 0.0.0.0 is
		# unnecessary on non-Windows systems.
		#
		# XXX A port available now may become unavailable by the time we start
		# the postmaster.
		if ($found == 1)
		{
			foreach my $addr (qw(127.0.0.1),
				$use_tcp ? qw(127.0.0.2 127.0.0.3 0.0.0.0) : ())
			{
				can_bind($addr, $port) or $found = 0;
			}
		}
	}

	print "# Found port $port\n";

	# Select a host.
	my $host = $test_pghost;
	if ($params{own_host})
	{
		if ($use_tcp)
		{
			$last_host_assigned++;
			$last_host_assigned > 254 and BAIL_OUT("too many own_host nodes");
			$host = '127.0.0.' . $last_host_assigned;
		}
		else
		{
			$host = "$test_pghost/$name"; # Assume $name =~ /^[-_a-zA-Z0-9]+$/
			mkdir $host;
		}
	}

	# Lock port number found by creating a new node
	my $node = $class->new($name, $host, $port);

	# Add node to list of nodes
	push(@all_nodes, $node);

	# And update port for next time
	$port_is_forced or $last_port_assigned = $port;

	return $node;
}

# Internal routine to check whether a host:port is available to bind
sub can_bind
{
	my ($host, $port) = @_;
	my $iaddr = inet_aton($host);
	my $paddr = sockaddr_in($port, $iaddr);
	my $proto = getprotobyname("tcp");

	socket(SOCK, PF_INET, SOCK_STREAM, $proto)
	  or die "socket failed: $!";

	# As in postmaster, don't use SO_REUSEADDR on Windows
	setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
	  unless $TestLib::windows_os;
	my $ret = bind(SOCK, $paddr) && listen(SOCK, SOMAXCONN);
	close(SOCK);
	return $ret;
}

# Retain the errno on die() if set, else assume a generic errno of 1.
# This will instruct the END handler on how to handle artifacts left
# behind from tests.
$SIG{__DIE__} = sub {
	if ($!)
	{
		$died = $!;
	}
	else
	{
		$died = 1;
	}
};

# Automatically shut down any still-running nodes when the test script exits.
# Note that this just stops the postmasters (in the same order the nodes were
# created in).  Any temporary directories are deleted, in an unspecified
# order, later when the File::Temp objects are destroyed.
END
{

	# take care not to change the script's exit value
	my $exit_code = $?;

	foreach my $node (@all_nodes)
	{
		$node->teardown_node;

		# skip clean if we are requested to retain the basedir
		next if defined $ENV{'PG_TEST_NOCLEAN'};

		# clean basedir on clean test invocation
		$node->clean_node
		  if TestLib::all_tests_passing() && !defined $died && !$exit_code;
	}

	$? = $exit_code;
}

=pod

=item $node->teardown_node()

Do an immediate stop of the node

=cut

sub teardown_node
{
	my $self = shift;

	$self->stop('immediate');
	return;
}

=pod

=item $node->clean_node()

Remove the base directory of the node if the node has been stopped.

=cut

sub clean_node
{
	my $self = shift;

	rmtree $self->{_basedir} unless defined $self->{_pid};
	return;
}

=pod

=item $node->safe_psql($dbname, $sql) => stdout

Invoke B<psql> to run B<sql> on B<dbname> and return its stdout on success.
Die if the SQL produces an error. Runs with B<ON_ERROR_STOP> set.

Takes optional extra params like timeout and timed_out parameters with the same
options as psql.

=cut

sub safe_psql
{
	my ($self, $dbname, $sql, %params) = @_;

	my ($stdout, $stderr);

	my $ret = $self->psql(
		$dbname, $sql,
		%params,
		stdout        => \$stdout,
		stderr        => \$stderr,
		on_error_die  => 1,
		on_error_stop => 1);

	# psql can emit stderr from NOTICEs etc
	if ($stderr ne "")
	{
		print "#### Begin standard error\n";
		print $stderr;
		print "\n#### End standard error\n";
	}

	$stdout =~ s/\r//g if $TestLib::windows_os;
	return $stdout;
}

=pod

=item $node->psql($dbname, $sql, %params) => psql_retval

Invoke B<psql> to execute B<$sql> on B<$dbname> and return the return value
from B<psql>, which is run with on_error_stop by default so that it will
stop running sql and return 3 if the passed SQL results in an error.

As a convenience, if B<psql> is called in array context it returns an
array containing ($retval, $stdout, $stderr).

psql is invoked in tuples-only unaligned mode with reading of B<.psqlrc>
disabled.  That may be overridden by passing extra psql parameters.

stdout and stderr are transformed to UNIX line endings if on Windows. Any
trailing newline is removed.

Dies on failure to invoke psql but not if psql exits with a nonzero
return code (unless on_error_die specified).

If psql exits because of a signal, an exception is raised.

=over

=item stdout => \$stdout

B<stdout>, if given, must be a scalar reference to which standard output is
written.  If not given, standard output is not redirected and will be printed
unless B<psql> is called in array context, in which case it's captured and
returned.

=item stderr => \$stderr

Same as B<stdout> but gets standard error. If the same scalar is passed for
both B<stdout> and B<stderr> the results may be interleaved unpredictably.

=item on_error_stop => 1

By default, the B<psql> method invokes the B<psql> program with ON_ERROR_STOP=1
set, so SQL execution is stopped at the first error and exit code 2 is
returned.  Set B<on_error_stop> to 0 to ignore errors instead.

=item on_error_die => 0

By default, this method returns psql's result code. Pass on_error_die to
instead die with an informative message.

=item timeout => 'interval'

Set a timeout for the psql call as an interval accepted by B<IPC::Run::timer>
(integer seconds is fine).  This method raises an exception on timeout, unless
the B<timed_out> parameter is also given.

=item timed_out => \$timed_out

If B<timeout> is set and this parameter is given, the scalar it references
is set to true if the psql call times out.

=item extra_params => ['--single-transaction']

If given, it must be an array reference containing additional parameters to B<psql>.

=back

e.g.

	my ($stdout, $stderr, $timed_out);
	my $cmdret = $node->psql('postgres', 'SELECT pg_sleep(60)',
		stdout => \$stdout, stderr => \$stderr,
		timeout => 30, timed_out => \$timed_out,
		extra_params => ['--single-transaction'])

will set $cmdret to undef and $timed_out to a true value.

	$node->psql('postgres', $sql, on_error_die => 1);

dies with an informative message if $sql fails.

=cut

sub psql
{
	my ($self, $dbname, $sql, %params) = @_;

	my $stdout            = $params{stdout};
	my $stderr            = $params{stderr};
	my $timeout           = undef;
	my $timeout_exception = 'psql timed out';

	local $ENV{PGOPTIONS} = '-c gp_role=utility';

	my @psql_params =
	  ('psql', '-XAtq', '-d', $self->connstr($dbname), '-f', '-');

	# If the caller wants an array and hasn't passed stdout/stderr
	# references, allocate temporary ones to capture them so we
	# can return them. Otherwise we won't redirect them at all.
	if (wantarray)
	{
		if (!defined($stdout))
		{
			my $temp_stdout = "";
			$stdout = \$temp_stdout;
		}
		if (!defined($stderr))
		{
			my $temp_stderr = "";
			$stderr = \$temp_stderr;
		}
	}

	$params{on_error_stop} = 1 unless defined $params{on_error_stop};
	$params{on_error_die}  = 0 unless defined $params{on_error_die};

	push @psql_params, '-v', 'ON_ERROR_STOP=1' if $params{on_error_stop};
	push @psql_params, @{ $params{extra_params} }
	  if defined $params{extra_params};

	$timeout =
	  IPC::Run::timeout($params{timeout}, exception => $timeout_exception)
	  if (defined($params{timeout}));

	${ $params{timed_out} } = 0 if defined $params{timed_out};

	# IPC::Run would otherwise append to existing contents:
	$$stdout = "" if ref($stdout);
	$$stderr = "" if ref($stderr);

	my $ret;

	# Run psql and capture any possible exceptions.  If the exception is
	# because of a timeout and the caller requested to handle that, just return
	# and set the flag.  Otherwise, and for any other exception, rethrow.
	#
	# For background, see
	# https://metacpan.org/pod/release/ETHER/Try-Tiny-0.24/lib/Try/Tiny.pm
	do
	{
		local $@;
		eval {
			my @ipcrun_opts = (\@psql_params, '<', \$sql);
			push @ipcrun_opts, '>',  $stdout if defined $stdout;
			push @ipcrun_opts, '2>', $stderr if defined $stderr;
			push @ipcrun_opts, $timeout if defined $timeout;

			IPC::Run::run @ipcrun_opts;
			$ret = $?;
		};
		my $exc_save = $@;
		if ($exc_save)
		{

			# IPC::Run::run threw an exception. re-throw unless it's a
			# timeout, which we'll handle by testing is_expired
			die $exc_save
			  if (blessed($exc_save)
				|| $exc_save !~ /^\Q$timeout_exception\E/);

			$ret = undef;

			die "Got timeout exception '$exc_save' but timer not expired?!"
			  unless $timeout->is_expired;

			if (defined($params{timed_out}))
			{
				${ $params{timed_out} } = 1;
			}
			else
			{
				die "psql timed out: stderr: '$$stderr'\n"
				  . "while running '@psql_params'";
			}
		}
	};

	if (defined $$stdout)
	{
		chomp $$stdout;
		$$stdout =~ s/\r//g if $TestLib::windows_os;
	}

	if (defined $$stderr)
	{
		chomp $$stderr;
		$$stderr =~ s/\r//g if $TestLib::windows_os;
	}

	# See http://perldoc.perl.org/perlvar.html#%24CHILD_ERROR
	# We don't use IPC::Run::Simple to limit dependencies.
	#
	# We always die on signal.
	my $core = $ret & 128 ? " (core dumped)" : "";
	die "psql exited with signal "
	  . ($ret & 127)
	  . "$core: '$$stderr' while running '@psql_params'"
	  if $ret & 127;
	$ret = $ret >> 8;

	if ($ret && $params{on_error_die})
	{
		die "psql error: stderr: '$$stderr'\nwhile running '@psql_params'"
		  if $ret == 1;
		die "connection error: '$$stderr'\nwhile running '@psql_params'"
		  if $ret == 2;
		die
		  "error running SQL: '$$stderr'\nwhile running '@psql_params' with sql '$sql'"
		  if $ret == 3;
		die "psql returns $ret: '$$stderr'\nwhile running '@psql_params'";
	}

	if (wantarray)
	{
		return ($ret, $$stdout, $$stderr);
	}
	else
	{
		return $ret;
	}
}

=pod

=item $node->poll_query_until($dbname, $query [, $expected ])

Run B<$query> repeatedly, until it returns the B<$expected> result
('t', or SQL boolean true, by default).
Continues polling if B<psql> returns an error result.
Times out after 180 seconds.
Returns 1 if successful, 0 if timed out.

=cut

sub poll_query_until
{
	my ($self, $dbname, $query, $expected) = @_;

	$expected = 't' unless defined($expected);    # default value

	my $cmd = [ 'psql', '-XAt', '-c', $query, '-d', $self->connstr($dbname) ];
	my ($stdout, $stderr);
	my $max_attempts = 180 * 10;
	my $attempts     = 0;

	while ($attempts < $max_attempts)
	{
		my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr;

		chomp($stdout);
		$stdout =~ s/\r//g if $TestLib::windows_os;

		if ($stdout eq $expected)
		{
			return 1;
		}

		# Wait 0.1 second before retrying.
		usleep(100_000);

		$attempts++;
	}

	# The query result didn't change in 180 seconds. Give up. Print the
	# output from the last attempt, hopefully that's useful for debugging.
	chomp($stderr);
	$stderr =~ s/\r//g if $TestLib::windows_os;
	diag qq(poll_query_until timed out executing this query:
$query
expecting this output:
$expected
last actual query output:
$stdout
with stderr:
$stderr);
	return 0;
}

=pod

=item $node->command_ok(...)

Runs a shell command like TestLib::command_ok, but with PGHOST and PGPORT set
so that the command will default to connecting to this PostgresNode.

=cut

sub command_ok
{
	local $Test::Builder::Level = $Test::Builder::Level + 1;

	my $self = shift;

	local $ENV{PGHOST} = $self->host;
	local $ENV{PGPORT} = $self->port;

	TestLib::command_ok(@_);
	return;
}

=pod

=item $node->command_fails(...)

TestLib::command_fails with our connection parameters. See command_ok(...)

=cut

sub command_fails
{
	local $Test::Builder::Level = $Test::Builder::Level + 1;

	my $self = shift;

	local $ENV{PGHOST} = $self->host;
	local $ENV{PGPORT} = $self->port;

	TestLib::command_fails(@_);
	return;
}

=pod

=item $node->command_like(...)

TestLib::command_like with our connection parameters. See command_ok(...)

=cut

sub command_like
{
	local $Test::Builder::Level = $Test::Builder::Level + 1;

	my $self = shift;

	local $ENV{PGHOST} = $self->host;
	local $ENV{PGPORT} = $self->port;

	TestLib::command_like(@_);
	return;
}

=pod

=item $node->command_checks_all(...)

TestLib::command_checks_all with our connection parameters. See
command_ok(...)

=cut

sub command_checks_all
{
	local $Test::Builder::Level = $Test::Builder::Level + 1;

	my $self = shift;

	local $ENV{PGHOST} = $self->host;
	local $ENV{PGPORT} = $self->port;

	TestLib::command_checks_all(@_);
	return;
}

=pod

=item $node->issues_sql_like(cmd, expected_sql, test_name)

Run a command on the node, then verify that $expected_sql appears in the
server log file.

Reads the whole log file so be careful when working with large log outputs.
The log file is truncated prior to running the command, however.

=cut

sub issues_sql_like
{
	local $Test::Builder::Level = $Test::Builder::Level + 1;

	my ($self, $cmd, $expected_sql, $test_name) = @_;

	local $ENV{PGHOST} = $self->host;
	local $ENV{PGPORT} = $self->port;

	truncate $self->logfile, 0;
	my $result = TestLib::run_log($cmd);
	ok($result, "@$cmd exit code 0");
	my $log = TestLib::slurp_file($self->logfile);
	like($log, $expected_sql, "$test_name: SQL found in server log");
	return;
}

=pod

=item $node->run_log(...)

Runs a shell command like TestLib::run_log, but with connection parameters set
so that the command will default to connecting to this PostgresNode.

=cut

sub run_log
{
	my $self = shift;

	local $ENV{PGHOST} = $self->host;
	local $ENV{PGPORT} = $self->port;

	TestLib::run_log(@_);
	return;
}

=pod

=item $node->lsn(mode)

Look up WAL locations on the server:

 * insert location (master only, error on replica)
 * write location (master only, error on replica)
 * flush location (master only, error on replica)
 * receive location (always undef on master)
 * replay location (always undef on master)

mode must be specified.

=cut

sub lsn
{
	my ($self, $mode) = @_;
	my %modes = (
		'insert'  => 'pg_current_wal_insert_lsn()',
		'flush'   => 'pg_current_wal_flush_lsn()',
		'write'   => 'pg_current_wal_lsn()',
		'receive' => 'pg_last_wal_receive_lsn()',
		'replay'  => 'pg_last_wal_replay_lsn()');

	$mode = '<undef>' if !defined($mode);
	croak "unknown mode for 'lsn': '$mode', valid modes are "
	  . join(', ', keys %modes)
	  if !defined($modes{$mode});

	my $result = $self->safe_psql('postgres', "SELECT $modes{$mode}");
	chomp($result);
	if ($result eq '')
	{
		return;
	}
	else
	{
		return $result;
	}
}

=pod

=item $node->wait_for_catchup(standby_name, mode, target_lsn)

Wait for the node with application_name standby_name (usually from node->name,
also works for logical subscriptions)
until its replication location in pg_stat_replication equals or passes the
upstream's WAL insert point at the time this function is called. By default
the replay_lsn is waited for, but 'mode' may be specified to wait for any of
sent|write|flush|replay. The connection catching up must be in a streaming
state.

If there is no active replication connection from this peer, waits until
poll_query_until timeout.

Requires that the 'postgres' db exists and is accessible.

target_lsn may be any arbitrary lsn, but is typically $master_node->lsn('insert').
If omitted, pg_current_wal_lsn() is used.

This is not a test. It die()s on failure.

=cut

sub wait_for_catchup
{
	my ($self, $standby_name, $mode, $target_lsn) = @_;
	$mode = defined($mode) ? $mode : 'replay';
	my %valid_modes =
	  ('sent' => 1, 'write' => 1, 'flush' => 1, 'replay' => 1);
	croak "unknown mode $mode for 'wait_for_catchup', valid modes are "
	  . join(', ', keys(%valid_modes))
	  unless exists($valid_modes{$mode});

	# Allow passing of a PostgresNode instance as shorthand
	if (blessed($standby_name) && $standby_name->isa("PostgresNode"))
	{
		$standby_name = $standby_name->name;
	}
	my $lsn_expr;
	if (defined($target_lsn))
	{
		$lsn_expr = "'$target_lsn'";
	}
	else
	{
		$lsn_expr = 'pg_current_wal_lsn()';
	}
	print "Waiting for replication conn "
	  . $standby_name . "'s "
	  . $mode
	  . "_lsn to pass "
	  . $lsn_expr . " on "
	  . $self->name . "\n";
	my $query =
	  qq[SELECT $lsn_expr <= ${mode}_lsn AND state = 'streaming' FROM pg_catalog.pg_stat_replication WHERE application_name = '$standby_name';];
	$self->poll_query_until('postgres', $query)
	  or croak "timed out waiting for catchup";
	print "done\n";
	return;
}

=pod

=item $node->wait_for_slot_catchup(slot_name, mode, target_lsn)

Wait for the named replication slot to equal or pass the supplied target_lsn.
The location used is the restart_lsn unless mode is given, in which case it may
be 'restart' or 'confirmed_flush'.

Requires that the 'postgres' db exists and is accessible.

This is not a test. It die()s on failure.

If the slot is not active, will time out after poll_query_until's timeout.

target_lsn may be any arbitrary lsn, but is typically $master_node->lsn('insert').

Note that for logical slots, restart_lsn is held down by the oldest in-progress tx.

=cut

sub wait_for_slot_catchup
{
	my ($self, $slot_name, $mode, $target_lsn) = @_;
	$mode = defined($mode) ? $mode : 'restart';
	if (!($mode eq 'restart' || $mode eq 'confirmed_flush'))
	{
		croak "valid modes are restart, confirmed_flush";
	}
	croak 'target lsn must be specified' unless defined($target_lsn);
	print "Waiting for replication slot "
	  . $slot_name . "'s "
	  . $mode
	  . "_lsn to pass "
	  . $target_lsn . " on "
	  . $self->name . "\n";
	my $query =
	  qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name';];
	$self->poll_query_until('postgres', $query)
	  or croak "timed out waiting for catchup";
	print "done\n";
	return;
}

=pod

=item $node->query_hash($dbname, $query, @columns)

Execute $query on $dbname, replacing any appearance of the string __COLUMNS__
within the query with a comma-separated list of @columns.

If __COLUMNS__ does not appear in the query, its result columns must EXACTLY
match the order and number (but not necessarily alias) of supplied @columns.

The query must return zero or one rows.

Return a hash-ref representation of the results of the query, with any empty
or null results as defined keys with an empty-string value. There is no way
to differentiate between null and empty-string result fields.

If the query returns zero rows, return a hash with all columns empty. There
is no way to differentiate between zero rows returned and a row with only
null columns.

=cut

sub query_hash
{
	my ($self, $dbname, $query, @columns) = @_;
	croak 'calls in array context for multi-row results not supported yet'
	  if (wantarray);

	# Replace __COLUMNS__ if found
	substr($query, index($query, '__COLUMNS__'), length('__COLUMNS__')) =
	  join(', ', @columns)
	  if index($query, '__COLUMNS__') >= 0;
	my $result = $self->safe_psql($dbname, $query);

	# hash slice, see http://stackoverflow.com/a/16755894/398670 .
	#
	# Fills the hash with empty strings produced by x-operator element
	# duplication if result is an empty row
	#
	my %val;
	@val{@columns} =
	  $result ne '' ? split(qr/\|/, $result, -1) : ('',) x scalar(@columns);
	return \%val;
}

=pod

=item $node->slot(slot_name)

Return hash-ref of replication slot data for the named slot, or a hash-ref with
all values '' if not found. Does not differentiate between null and empty string
for fields, no field is ever undef.

The restart_lsn and confirmed_flush_lsn fields are returned verbatim, and also
as a 2-list of [highword, lowword] integer. Since we rely on Perl 5.8.8 we can't
"use bigint", it's from 5.20, and we can't assume we have Math::Bigint from CPAN
either.

=cut

sub slot
{
	my ($self, $slot_name) = @_;
	my @columns = (
		'plugin', 'slot_type',  'datoid', 'database',
		'active', 'active_pid', 'xmin',   'catalog_xmin',
		'restart_lsn');
	return $self->query_hash(
		'postgres',
		"SELECT __COLUMNS__ FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name'",
		@columns);
}

=pod

=item $node->pg_recvlogical_upto(self, dbname, slot_name, endpos, timeout_secs, ...)

Invoke pg_recvlogical to read from slot_name on dbname until LSN endpos, which
corresponds to pg_recvlogical --endpos.  Gives up after timeout (if nonzero).

Disallows pg_recvlogical from internally retrying on error by passing --no-loop.

Plugin options are passed as additional keyword arguments.

If called in scalar context, returns stdout, and die()s on timeout or nonzero return.

If called in array context, returns a tuple of (retval, stdout, stderr, timeout).
timeout is the IPC::Run::Timeout object whose is_expired method can be tested
to check for timeout. retval is undef on timeout.

=cut

sub pg_recvlogical_upto
{
	my ($self, $dbname, $slot_name, $endpos, $timeout_secs, %plugin_options)
	  = @_;
	my ($stdout, $stderr);

	my $timeout_exception = 'pg_recvlogical timed out';

	croak 'slot name must be specified' unless defined($slot_name);
	croak 'endpos must be specified'    unless defined($endpos);

	my @cmd = (
		'pg_recvlogical', '-S', $slot_name, '--dbname',
		$self->connstr($dbname));
	push @cmd, '--endpos', $endpos;
	push @cmd, '-f', '-', '--no-loop', '--start';

	while (my ($k, $v) = each %plugin_options)
	{
		croak "= is not permitted to appear in replication option name"
		  if ($k =~ qr/=/);
		push @cmd, "-o", "$k=$v";
	}

	my $timeout;
	$timeout =
	  IPC::Run::timeout($timeout_secs, exception => $timeout_exception)
	  if $timeout_secs;
	my $ret = 0;

	do
	{
		local $@;
		eval {
			IPC::Run::run(\@cmd, ">", \$stdout, "2>", \$stderr, $timeout);
			$ret = $?;
		};
		my $exc_save = $@;
		if ($exc_save)
		{

			# IPC::Run::run threw an exception. re-throw unless it's a
			# timeout, which we'll handle by testing is_expired
			die $exc_save
			  if (blessed($exc_save) || $exc_save !~ qr/$timeout_exception/);

			$ret = undef;

			die "Got timeout exception '$exc_save' but timer not expired?!"
			  unless $timeout->is_expired;

			die
			  "$exc_save waiting for endpos $endpos with stdout '$stdout', stderr '$stderr'"
			  unless wantarray;
		}
	};

	$stdout =~ s/\r//g if $TestLib::windows_os;
	$stderr =~ s/\r//g if $TestLib::windows_os;

	if (wantarray)
	{
		return ($ret, $stdout, $stderr, $timeout);
	}
	else
	{
		die
		  "pg_recvlogical exited with code '$ret', stdout '$stdout' and stderr '$stderr'"
		  if $ret;
		return $stdout;
	}
}

=pod

=back

=cut

1;

redpajama_set_name: RedPajamaGithub


text:
/*
 * LEFT TO DO:
 * - WRITE TESTS for the stuff in this  file.
 * - Check the creation, maybe make it safer by returning an empty optional or
 *   unique_ptr. --- It looks OK, but RecreateEncoderInstance can perhaps crash
 *   on a valid config. Can run it in the fuzzer for some time. Should prbl also
 *   fuzz the config.
 */

#include "modules/audio_coding/codecs/opus/audio_encoder_multi_channel_opus_impl.h"

#include <algorithm>
#include <memory>
#include <string>
#include <vector>

#include "absl/strings/match.h"
#include "modules/audio_coding/codecs/opus/audio_coder_opus_common.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/string_to_number.h"

namespace webrtc {

namespace {

// Recommended bitrates for one channel:
// 8-12 kb/s for NB speech,
// 16-20 kb/s for WB speech,
// 28-40 kb/s for FB speech,
// 48-64 kb/s for FB mono music, and
// 64-128 kb/s for FB stereo music.
// The current implementation multiplies these values by the number of channels.
constexpr int kOpusBitrateNbBps = 12000;
constexpr int kOpusBitrateWbBps = 20000;
constexpr int kOpusBitrateFbBps = 32000;

constexpr int kDefaultMaxPlaybackRate = 48000;
// These two lists must be sorted from low to high
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60, 120};
#else
constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60};
#endif

int GetBitrateBps(const AudioEncoderMultiChannelOpusConfig& config) {
  RTC_DCHECK(config.IsOk());
  return config.bitrate_bps;
}
int GetMaxPlaybackRate(const SdpAudioFormat& format) {
  const auto param = GetFormatParameter<int>(format, "maxplaybackrate");
  if (param && *param >= 8000) {
    return std::min(*param, kDefaultMaxPlaybackRate);
  }
  return kDefaultMaxPlaybackRate;
}

int GetFrameSizeMs(const SdpAudioFormat& format) {
  const auto ptime = GetFormatParameter<int>(format, "ptime");
  if (ptime.has_value()) {
    // Pick the next highest supported frame length from
    // kOpusSupportedFrameLengths.
    for (const int supported_frame_length : kOpusSupportedFrameLengths) {
      if (supported_frame_length >= *ptime) {
        return supported_frame_length;
      }
    }
    // If none was found, return the largest supported frame length.
    return *(std::end(kOpusSupportedFrameLengths) - 1);
  }

  return AudioEncoderOpusConfig::kDefaultFrameSizeMs;
}

int CalculateDefaultBitrate(int max_playback_rate, size_t num_channels) {
  const int bitrate = [&] {
    if (max_playback_rate <= 8000) {
      return kOpusBitrateNbBps * rtc::dchecked_cast<int>(num_channels);
    } else if (max_playback_rate <= 16000) {
      return kOpusBitrateWbBps * rtc::dchecked_cast<int>(num_channels);
    } else {
      return kOpusBitrateFbBps * rtc::dchecked_cast<int>(num_channels);
    }
  }();
  RTC_DCHECK_GE(bitrate, AudioEncoderMultiChannelOpusConfig::kMinBitrateBps);
  return bitrate;
}

// Get the maxaveragebitrate parameter in string-form, so we can properly figure
// out how invalid it is and accurately log invalid values.
int CalculateBitrate(int max_playback_rate_hz,
                     size_t num_channels,
                     absl::optional<std::string> bitrate_param) {
  const int default_bitrate =
      CalculateDefaultBitrate(max_playback_rate_hz, num_channels);

  if (bitrate_param) {
    const auto bitrate = rtc::StringToNumber<int>(*bitrate_param);
    if (bitrate) {
      const int chosen_bitrate =
          std::max(AudioEncoderOpusConfig::kMinBitrateBps,
                   std::min(*bitrate, AudioEncoderOpusConfig::kMaxBitrateBps));
      if (bitrate != chosen_bitrate) {
        RTC_LOG(LS_WARNING) << "Invalid maxaveragebitrate " << *bitrate
                            << " clamped to " << chosen_bitrate;
      }
      return chosen_bitrate;
    }
    RTC_LOG(LS_WARNING) << "Invalid maxaveragebitrate \"" << *bitrate_param
                        << "\" replaced by default bitrate " << default_bitrate;
  }

  return default_bitrate;
}

}  // namespace

std::unique_ptr<AudioEncoder>
AudioEncoderMultiChannelOpusImpl::MakeAudioEncoder(
    const AudioEncoderMultiChannelOpusConfig& config,
    int payload_type) {
  if (!config.IsOk()) {
    return nullptr;
  }
  return std::make_unique<AudioEncoderMultiChannelOpusImpl>(config,
                                                            payload_type);
}

AudioEncoderMultiChannelOpusImpl::AudioEncoderMultiChannelOpusImpl(
    const AudioEncoderMultiChannelOpusConfig& config,
    int payload_type)
    : payload_type_(payload_type), inst_(nullptr) {
  RTC_DCHECK(0 <= payload_type && payload_type <= 127);

  RTC_CHECK(RecreateEncoderInstance(config));
}

AudioEncoderMultiChannelOpusImpl::~AudioEncoderMultiChannelOpusImpl() {
  RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
}

size_t AudioEncoderMultiChannelOpusImpl::SufficientOutputBufferSize() const {
  // Calculate the number of bytes we expect the encoder to produce,
  // then multiply by two to give a wide margin for error.
  const size_t bytes_per_millisecond =
      static_cast<size_t>(GetBitrateBps(config_) / (1000 * 8) + 1);
  const size_t approx_encoded_bytes =
      Num10msFramesPerPacket() * 10 * bytes_per_millisecond;
  return 2 * approx_encoded_bytes;
}

void AudioEncoderMultiChannelOpusImpl::Reset() {
  RTC_CHECK(RecreateEncoderInstance(config_));
}

absl::optional<std::pair<TimeDelta, TimeDelta>>
AudioEncoderMultiChannelOpusImpl::GetFrameLengthRange() const {
  return {{TimeDelta::Millis(config_.frame_size_ms),
           TimeDelta::Millis(config_.frame_size_ms)}};
}

// If the given config is OK, recreate the Opus encoder instance with those
// settings, save the config, and return true. Otherwise, do nothing and return
// false.
bool AudioEncoderMultiChannelOpusImpl::RecreateEncoderInstance(
    const AudioEncoderMultiChannelOpusConfig& config) {
  if (!config.IsOk())
    return false;
  config_ = config;
  if (inst_)
    RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
  input_buffer_.clear();
  input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame());
  RTC_CHECK_EQ(
      0, WebRtcOpus_MultistreamEncoderCreate(
             &inst_, config.num_channels,
             config.application ==
                     AudioEncoderMultiChannelOpusConfig::ApplicationMode::kVoip
                 ? 0
                 : 1,
             config.num_streams, config.coupled_streams,
             config.channel_mapping.data()));
  const int bitrate = GetBitrateBps(config);
  RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate));
  RTC_LOG(LS_VERBOSE) << "Set Opus bitrate to " << bitrate << " bps.";
  if (config.fec_enabled) {
    RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_));
    RTC_LOG(LS_VERBOSE) << "Opus enable FEC";
  } else {
    RTC_CHECK_EQ(0, WebRtcOpus_DisableFec(inst_));
    RTC_LOG(LS_VERBOSE) << "Opus disable FEC";
  }
  RTC_CHECK_EQ(
      0, WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz));
  RTC_LOG(LS_VERBOSE) << "Set Opus playback rate to "
                      << config.max_playback_rate_hz << " hz.";

  // Use the DEFAULT complexity.
  RTC_CHECK_EQ(
      0, WebRtcOpus_SetComplexity(inst_, AudioEncoderOpusConfig().complexity));
  RTC_LOG(LS_VERBOSE) << "Set Opus coding complexity to "
                      << AudioEncoderOpusConfig().complexity;

  if (config.dtx_enabled) {
    RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_));
    RTC_LOG(LS_VERBOSE) << "Opus enable DTX";
  } else {
    RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_));
    RTC_LOG(LS_VERBOSE) << "Opus disable DTX";
  }

  if (config.cbr_enabled) {
    RTC_CHECK_EQ(0, WebRtcOpus_EnableCbr(inst_));
    RTC_LOG(LS_VERBOSE) << "Opus enable CBR";
  } else {
    RTC_CHECK_EQ(0, WebRtcOpus_DisableCbr(inst_));
    RTC_LOG(LS_VERBOSE) << "Opus disable CBR";
  }
  num_channels_to_encode_ = NumChannels();
  next_frame_length_ms_ = config_.frame_size_ms;
  RTC_LOG(LS_VERBOSE) << "Set Opus frame length to " << config_.frame_size_ms
                      << " ms";
  return true;
}

absl::optional<AudioEncoderMultiChannelOpusConfig>
AudioEncoderMultiChannelOpusImpl::SdpToConfig(const SdpAudioFormat& format) {
  if (!absl::EqualsIgnoreCase(format.name, "multiopus") ||
      format.clockrate_hz != 48000) {
    return absl::nullopt;
  }

  AudioEncoderMultiChannelOpusConfig config;
  config.num_channels = format.num_channels;
  config.frame_size_ms = GetFrameSizeMs(format);
  config.max_playback_rate_hz = GetMaxPlaybackRate(format);
  config.fec_enabled = (GetFormatParameter(format, "useinbandfec") == "1");
  config.dtx_enabled = (GetFormatParameter(format, "usedtx") == "1");
  config.cbr_enabled = (GetFormatParameter(format, "cbr") == "1");
  config.bitrate_bps =
      CalculateBitrate(config.max_playback_rate_hz, config.num_channels,
                       GetFormatParameter(format, "maxaveragebitrate"));
  config.application =
      config.num_channels == 1
          ? AudioEncoderMultiChannelOpusConfig::ApplicationMode::kVoip
          : AudioEncoderMultiChannelOpusConfig::ApplicationMode::kAudio;

  config.supported_frame_lengths_ms.clear();
  std::copy(std::begin(kOpusSupportedFrameLengths),
            std::end(kOpusSupportedFrameLengths),
            std::back_inserter(config.supported_frame_lengths_ms));

  auto num_streams = GetFormatParameter<int>(format, "num_streams");
  if (!num_streams.has_value()) {
    return absl::nullopt;
  }
  config.num_streams = *num_streams;

  auto coupled_streams = GetFormatParameter<int>(format, "coupled_streams");
  if (!coupled_streams.has_value()) {
    return absl::nullopt;
  }
  config.coupled_streams = *coupled_streams;

  auto channel_mapping =
      GetFormatParameter<std::vector<unsigned char>>(format, "channel_mapping");
  if (!channel_mapping.has_value()) {
    return absl::nullopt;
  }
  config.channel_mapping = *channel_mapping;

  return config;
}

AudioCodecInfo AudioEncoderMultiChannelOpusImpl::QueryAudioEncoder(
    const AudioEncoderMultiChannelOpusConfig& config) {
  RTC_DCHECK(config.IsOk());
  AudioCodecInfo info(48000, config.num_channels, config.bitrate_bps,
                      AudioEncoderOpusConfig::kMinBitrateBps,
                      AudioEncoderOpusConfig::kMaxBitrateBps);
  info.allow_comfort_noise = false;
  info.supports_network_adaption = false;
  return info;
}

size_t AudioEncoderMultiChannelOpusImpl::Num10msFramesPerPacket() const {
  return static_cast<size_t>(rtc::CheckedDivExact(config_.frame_size_ms, 10));
}
size_t AudioEncoderMultiChannelOpusImpl::SamplesPer10msFrame() const {
  return rtc::CheckedDivExact(48000, 100) * config_.num_channels;
}
int AudioEncoderMultiChannelOpusImpl::SampleRateHz() const {
  return 48000;
}
size_t AudioEncoderMultiChannelOpusImpl::NumChannels() const {
  return config_.num_channels;
}
size_t AudioEncoderMultiChannelOpusImpl::Num10MsFramesInNextPacket() const {
  return Num10msFramesPerPacket();
}
size_t AudioEncoderMultiChannelOpusImpl::Max10MsFramesInAPacket() const {
  return Num10msFramesPerPacket();
}
int AudioEncoderMultiChannelOpusImpl::GetTargetBitrate() const {
  return GetBitrateBps(config_);
}

AudioEncoder::EncodedInfo AudioEncoderMultiChannelOpusImpl::EncodeImpl(
    uint32_t rtp_timestamp,
    rtc::ArrayView<const int16_t> audio,
    rtc::Buffer* encoded) {
  if (input_buffer_.empty())
    first_timestamp_in_buffer_ = rtp_timestamp;

  input_buffer_.insert(input_buffer_.end(), audio.cbegin(), audio.cend());
  if (input_buffer_.size() <
      (Num10msFramesPerPacket() * SamplesPer10msFrame())) {
    return EncodedInfo();
  }
  RTC_CHECK_EQ(input_buffer_.size(),
               Num10msFramesPerPacket() * SamplesPer10msFrame());

  const size_t max_encoded_bytes = SufficientOutputBufferSize();
  EncodedInfo info;
  info.encoded_bytes = encoded->AppendData(
      max_encoded_bytes, [&](rtc::ArrayView<uint8_t> encoded) {
        int status = WebRtcOpus_Encode(
            inst_, &input_buffer_[0],
            rtc::CheckedDivExact(input_buffer_.size(), config_.num_channels),
            rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded.data());

        RTC_CHECK_GE(status, 0);  // Fails only if fed invalid data.

        return static_cast<size_t>(status);
      });
  input_buffer_.clear();

  // Will use new packet size for next encoding.
  config_.frame_size_ms = next_frame_length_ms_;

  info.encoded_timestamp = first_timestamp_in_buffer_;
  info.payload_type = payload_type_;
  info.send_even_if_empty = true;  // Allows Opus to send empty packets.

  info.speech = true;
  info.encoder_type = CodecType::kOther;

  return info;
}

}  // namespace webrtc


text:
Submit your FML
Moderate the FMLs
New here? Join the FML community
Almost FML
Even more FMLs
FML News
FML - The follow-up
Submit an FML
Funniest FMLs of the Day Weirdest FMLs of the Day Most Commented FMLs of the Day
By Tytonic - 20/1/2020 05:00 - United States - Havertown
First dinner
Today, After my first dinner with my new girlfriend, I was using a toothpick when I fell, stabbing the roof of my mouth. She then laughed at me since there is so much blood. FML
I agree, your life sucks
You deserved it
By smelly situation - 20/1/2020 01:00
Something in the air
Today, I was fired due to complaints that my shuttle stunk of gas. The smell was because I've been farting so bad on the shuttle. I did try to air it out but I guess it wouldn't leave. FML
By Anonymous - 19/1/2020 20:00
Today I was walking around the mall and I saw my crush from high school. He came up to me and instead of talking to him I burped, and he just walked away. FML
By - 19/1/2020 18:00
Romantic gesture
Today, I learned that a spontaneous romantic gesture of arriving home early with flowers and wine is not welcome when your wife is busy having sex with your brother. FML
By swollenbutthole - 19/1/2020 14:00 - United States
Today, and since forever, I've always been deemed "boring" for never trying anything risky. So, I got frisky one night and decided to try anal. I got hemorrhoids. FML
By need not know - 19/1/2020 05:00
Still married
Today, while fixing my dad's phone, I saw Tinder installed. He's still married to my mum. FML
By Isidora - 19/1/2020 01:00 - Canada - Toronto
It is warm
Today, my boyfriend felt my butthole and asked if I was farting because it was warm. FML
By Penny - 18/1/2020 20:00
Today at work, I was discussing animated movies with a male senior who's got kids. I was trying to refer to Zootopia but couldn't remember the name. I went zoo zoo... filia..? Silence. Wasn't until I got home an hour later I realized what I said. FML
Strange flight
Today, I was on my way home on an airplane. The guy I had to sit next to was reading a book with naked girls in it. About 15 minutes into the flight, he had an erection and started to giggle. It was a 2 hour flight. FML
By ihmmil - 18/1/2020 14:00
Belly Finger
Today, my husband was trying to be sexy. He asked me if I wanted to sit on his "Belly Finger"! Major mood kill. FML
Very frustrating
Today my Assistant Manager decided to pull a prank on me by walking up behind me and screaming my name. I screamed in terror and then swung around and punched him full force dead center in the chest right in front of my supervisor, manager, and several other employees. FML
After shower
Today, my sister snuck into the bathroom while I was in the shower (the locks broke) and took my clothes and towels. I came out and quickly went to my room. As I went in, my sister was sitting on my bed with two friends watching TV. I instantly covered up, but they saw everything. FML
Everything is clean
Today, I went to the bank to deposit the cash I made waiting tables. While the teller was counting, I apologized for having so many small bills and she said "It's OK honey, I helped another one of your kind just the other day. You're lucky we take your dirty money." She thought I was a stripper. FML
Nice pic
Today, for the first time in my life, I sent a member pic to a girl I had been talking to for a few days on Snapchat. (she had asked me for it). She saw the pic, and blocked me. FML
By Whoisshe - 17/1/2020 01:00
Unknown number
Today, I gave my phone number to a guy at the movie theatre. I was excited to receive a text a few minutes later, sure enough when I unlocked my phone I had received a message from an unknown number. It was his girlfriend. FML
By Yoir mom - 16/1/2020 20:00 - United States - Port Richey
Very bad idea
Today, I realized I was late for work, so I rushed out of bed only to accidentally step onto my dog which then promptly bit my leg and now I'm in the ER. FML
I am clumsy!
Today my girlfriend was on top during sex. I went to slap her butt, missed and nailed myself in the balls. We had to stop. She wouldn't stop laughing. FML
By brown and sticky - 16/1/2020 14:00 - United States - Baltimore
Today, I got food poisoning. After leaving class 4 times to poop, I sharted in the school bus on the ride home. FML
Today, as I was trying to have some "self pleasure" time. Well, in the midst of going really wild, about to finish, my cat, WHO NEVER CUDDLES WITH ME, decides to come up and sit on my thigh. FML.
By startrekk - 16/1/2020 01:00
Today, at work, I was very hungry and I ate some of the staff burgers, although they seemed and smelled a bit off, I ignored it saying that nothing bad would happen. As I rushed back home to the toilet, I farted diarrhea everywhere. FML
Secret shower
Today, I tried to climb in the shower with my wife, except it was my mother-in-law, I just couldn't tell through the steam. Before I could leave, she tried to convince me to stay and that she'd keep it secret from her daughter if I did. At a loss for words right now. FML
By Oof - 15/1/2020 18:00
Keep calm please!
Today, while things were getting hot and heavy with my boyfriend, we were making out and our nose rings got stuck together... it took us 20 minutes to get them unhooked. I was the calm one in the situation while my boyfriend nearly cried like a baby.
By izzyizziz11 - 15/1/2020 14:00
Today, my best friend took me clubbing and this dude lifted up my skirt to see if I was a dude before he hit on me... FML
By John Doe - 15/1/2020 05:00
After feeling
Today, after I finished jerking off, I sneezed into the tissue with my semen. FML
By Anonymous - 15/1/2020 00:00 - United Kingdom - Stockport
Sexy morning
Today, my sister woke me up panicking saying our kitchen was on fire, and we had to leave. She practically dragged me out of bed and all the way to the front door. When we got outside, she suddenly kneed me in the nuts and went back inside, locking the door behind her. I was only in boxers. FML
By teebs - 14/1/2020 20:00 - United States - San Leandro
Long wait
Today, on my way for a vacation, my car started misfiring, so I called a tow truck. 40 minutes later the tow truck arrived. He then said that he had just gotten another priority call, so he was leaving and someone would be back in another hour to get us. FML
By - 14/1/2020 20:00 - Madagascar
Delicious coffee
Today, I caught my wife slipping penis enlargement pills into my coffee. FML
By DeanVendetta - 14/1/2020 14:00 - United States - Moss Point
Today, I decided to hide in a bush, so I can jump out and scare my boyfriend. Well after 10 minutes of waiting, he ran up to the bush and started peeing. All over me. FML
By Cam - 14/1/2020 05:00 - Sri Lanka - Colombo
Long secret
Today, I realized that my boyfriend is still scared of his ex. It's been 8 months and our relationship is still "secret." Why? Because he's scared that she will find out and tell his family about us. FML
By irulan - 14/1/2020 03:00 - United Kingdom - London
Today, I farted so loudly in bed and I woke up my husband. Startled, he thought that someone was entered in our room and fired a shot. FML
I fell for my tinder match after one fuck
Today, whilst babysitting my neighbour's five-year-old son, he called me a "fucking dumbass". Why? I called the jackal on The Lion Guard a coyote. Both...
See all the Nearly FMLs
Today, I learned that a spontaneous romantic gesture of arriving home early with flowers and wine is not welcome when your wife is busy having sex with...
Today, I was on my way home on an airplane. The guy I had to sit next to was reading a book with naked girls in it. About 15 minutes into the flight, he...
See all the Spicy FMLs
We love new friends!
Check out the app
The list of badges to find
Moderation ranking
FML around the world
Français (VDM)
English (FML)
© Beta&cie, All rights reserved
Download the app for Android Download the app for iOS
Moderate the FMLs Submit your FML
Random Spicy Almost FML The Top
FML News Photos Medics Videos Blog People FML - The follow-up FORUM
Have you just experienced an FML moment? Feel like sharing it with the other FML users? Your instinct was right, because it's good to laugh life off. Follow the instructions below, and if your story gets through the moderation process, it'll published in the next 24 hours.
File must not exceed 2 Mo
I own the content shared
Your story must start with "Today," and end with "FML". TXT language is forbidden and spelling mistakes hurt people's eyeballs, so the use of either would result in the direct dismissal of your FML. Don't use this space for discussions, advertising or spam, or for posting anything which isn't an FML. Furthermore, it's not possible to obtain badges by posting keywords, so stop believing things you've read on message boards. Don't try reposting old FMLs, we're not that daft.
Make me anonymous
I have read and accepted theTerms and conditions
Please read our guidelines for posting
Thank you, your FML was submitted it will appear in moderation soon !

redpajama_set_name: RedPajamaCommonCrawl


text:
The first Octoberfest — the festival, not the beer — took place in 1810; the beer on that occasion was almost certainly a Marzen. (Illustration courtesy of Great Lakes Brewing Co.)
Get To Know Marzen, The Obscure Beer Style That Gave Us Oktoberfest
Get To Know Marzen, The Obscure Beer Style That Gave Us OktoberfestHere's The Beer Style Behind Oktoberfest
Tom Acitelli October 1, 2015
Time was that brewers in Northern Europe, particularly in what became Germany, could not brew decent beer past March or so. Why? Because the warming weather would render most fermentation vessels welcoming hot tubs for airborne bacteria that had been just waiting for the colder temps to dissipate.
So brewers in the pre-refrigeration era would concoct their last beers of the winter in March and age them through the spring and summer. They would tap them in September or October, the months of aging invariably providing rounder, smoother brews.
Beers made on this timeline eventually came to be called Marzenbier or simply Marzen — as in the German for "March."
Marzen still makes regular appearances on European beer menus and tap runs. In the U.S., however, a seemingly irresistible term long ago supplanted it: Oktoberfest (a.k.a. Octoberfest). The first Octoberfest — the festival, not the beer — was in October 1810 to celebrate the marriage of the Bavarian crown prince. The beer on that occasion was almost certainly a Marzen. The beer and its month had met, and they have been entwined since, especially in recent decades in the U.S.
Be careful, though: In the ever-experimental American craft beer universe, not every Oktoberfest is a Marzen. The style was born of other attributes besides that timeline.
For one thing, Marzen beers are lagers — the generally thinner and crisper cousins to thicker, heavier-tasting ales. For another, these lagers usually include Munich malt, named for the Bavarian capital. The malt is amber in color and produces a particularly rich, sweet taste. Finally, Marzen should clock in toward the lower end of the alcohol spectrum — say, under 6.5 percent alcohol by volume, not an easy feat in modern American craft beer.
So, many American-made Oktoberfests are not Marzen beers because they're ales or they don't use Munich malts or they're too strong, or some combination of the three. Or they simply choose not to identify as a beer style many U.S. consumers might not recognize.
Americans get October — the month and the annual beer festival that still goes off every autumn in Munich. Marzen is a different story. Here are six such beers to familiarize yourself with that centuries-old style.
Serving suggestions: Slightly colder than room temperature and in a big stein. Why not?
A less potent lager made with Munich malts, Brooklyn Oktoberfest is a prototypical Marzen-style beer. (Photo courtesy of Brooklyn Brewery.)
Brooklyn Oktoberfest
Brooklyn Brewery, Brooklyn
This puppy checks all the Marzen boxes: It's a lager, it's 5.5 percent ABV and it uses Munich malts. Brooklyn Oktoberfest even drops at the right time of year: from August through October. It's sweet and rich, and not too heavy — a great, great interpretation of the style.
Left Hand Oktoberfest
Left Hand Brewing Co., Longmont, Colorado
Another Oktoberfest that does Marzen right. It has a toasted-bread aroma and a rich, warming finish. The only thing we'd quibble with is the alcohol content: Left Hand Oktoberfest clocks in at 6.6 percent ABV, a little strong for a traditional Marzen. The drinkability more than makes up for it.
A bit stronger than the typical Marzen, Great Lakes Oktoberfest is nevertheless almost sessionable in its lightness. (Photo courtesy of Great Lakes Brewing Co.)
Great Lakes Oktoberfest
Great Lakes Brewing Co., Cleveland, Ohio
From Ohio's oldest craft brewery comes a bready, dry iteration of Marzen. This one, too, is a little on the strong side — 6.5 percent — but almost sessionable in its lightness.
Westbrook Marzenbier
Westbrook Brewing Co., Mount Pleasant, South Carolina
Westbrook's Marzenbier is as straightforward as the style comes, with a nice grainy mouthfeel and a sweet finish. It's light on the stomach, too, and an even 6 percent ABV.
A bone-dry Marzen from America's oldest brewery. (Photo courtesy of D.G. Yuengling & Son, Inc.)
Yuengling Oktoberfest
D.G. Yuengling & Son, Pottsville, Pennsylvania
America's oldest brewery (founded when Andrew Jackson was president) makes a bone-dry Marzen through its Oktoberfest. This brew is as inoffensive as the style gets for initiates. We would like to have tasted more than a faint hint of soda-like caramel on the finish, but it'll do in a pinch, especially at just under 5.5 percent ABV.
Dogtoberfest Marzen
Flying Dog Brewery, Frederick, Maryland
This toasty offering was the most interesting of the lot. A little bit spicier and therefore busier than the other Marzen beers — cinnamon or brown sugar in there somewhere? — and also a little thicker texture-wise. And why not? Marzen has been around for centuries. Let American brewers have fun with it.
The Strange Tale Of Roggenbier, The Rye-Based Medi...
The State Of Craft Beer In 2016
Anheuser-Busch Is Trying To Slow The Flow Of Craft...
Fall Preview 2015: 15 Excellent Beers To Drink Thi...
As American As Cream Ale: Only Three Beer Styles W...
american craft beer
german beers


Nothing is more romantic than the sea breeze in your hair and sand between your toes when you say "I do." Nothing, that is, except looking equally dreamy.
TIP: Outfit the bridesmaids and groomsmen with sea-themed accessories, like broaches or shell boutonnieres.
Step 1: Have coordinating blazers for the grooms and wraps for the maids and have guests bring them for chilly evening weather.
FACT: The aptly named Long Beach, Washington, is the longest natural beach in the U.S., stretching 28 miles.
Step 2: Dress the bridesmaids in pretty, informal, printed sundresses. Strapless, A-line dresses are a popular choice.
Step 3: Wear lighter suits if you are the groom or a groomsman. White or light colored linen or khaki work for any beach locale. Skip the jacket if it's too hot.
Step 4: Look for a veil with small anchors sewn into the end to avoid snafus caused by beach breezes.
TIP: You can skip the veil altogether and put a large, tropical flower in your hair.
Step 5: Wear whimsical footwear, such as strappy sandals flip-flops with beaded shell embellishments. Even if you go barefoot at the ceremony, you'll probably want to don sandals for the reception.
Step 6: Choose a gown with understated elegance, minimal embellishment, and a slim silhouette in a light fabric such as cotton, chiffon, or organza to match the informal feel of the al fresco setting.


The Illinois Appellate Court recently addressed the issue of the creation of new records under FOIA. In Martinez v. Cook County State's Attorney's Office, Martinez submitted a FOIA request to the State's Attorney's Office (SAO), seeking "each instance in which information obtained using a cell site simulator… was used in a criminal prosecution…." The SAO denied the request, claiming that FOIA does not require a public body to release nonexistent records, and even if the records did exist, compliance would be unduly burdensome. The SAO contended there was no way of knowing if any cases exist or the identity of criminal cases where a cell site simulator was used to obtain evidence.
In response to the denial, Martinez requested that the SAO send an email to every attorney in the office, asking them to identify any cases in which such evidence was obtained. He also requested that the SAO conduct a server-wide search of emails. The SAO again responded with a denial, arguing that the request was unduly burdensome. The SAO offered to discuss narrowing the requests and Martinez subsequently narrowed his requests to only "terrorism and narcotics cases." The SAO again denied the narrowed request as nonexistent, unduly burdensome, and exempt under attorney-client privilege, attorney work product, and the deliberative process exemption.
Martinez then sued the SAO alleging violations of FOIA. The trial court ruled in favor of the SAO , and the Appellate Court affirmed. The Appellate Court found that the first request sought "instances," not actual records. The Court has previously held that the requested records must be reasonably identified as a record, and not a request for data, information, or statistics which an agency may not generally create. The Court found that the SAO's denial was proper as FOIA does not require a public body to create new records in response to a FOIA request. As for the second request, the Court noted that the request was presented as a question, and FOIA does not require the public body to answer questions. Further, the Court noted that the second request sought a search, not a public record. As such, the Court found that both denials were warranted.


text:
Art of the State
A Grimm tale
By Jessica Santina
The Baker and his Wife, played by Adam Machart and Megan Smith, hash it out in their kitchen for TMCC's production of Into the Woods.
Photo By AUDREY LOVE
Into the Woods will be performed Oct. 22, 23, 28, 29, 30 at 7:30 p.m. and Oct. 24, 31 at 2 p.m. Tickets are $17 general admission; $15 students; $10 TMCC students/seniors. Visit www.showtix4u.com or call 789-5671.
I'll never forget the children's lit class I took in graduate school, when first I discovered the horror of Grimms' fairy tales. Having been brought up, like many, on the stuff of Disney, I was shocked to learn that Cinderella's stepmother actually cut off pieces of her daughters' feet in order to make them fit into the golden slipper.
And did you know that, in The Little Mermaid, when our heroine finally gets her beautiful legs, she also gets the pain of forever walking on swords and feet that constantly bleed? Oh, and my personal favorite: In Snow White, the girl's jealous mother actually tries to eat her.
In an attempt to have some fun with these morbid lessons, Stephen Sondheim and James Lapine teamed up to write Into the Woods, which TMCC Performing Arts now faithfully presents under the direction of department chair Paul Aberasturi, a die-hard Sondheim devotee.
The convoluted plot involves one basic premise: A baker (Adam Machart) and his wife (Megan Smith) are unable to have the baby they desperately want. A witch (Jenny O) magically appears, explaining that there was, long ago, a curse placed on the baker's family that none in his line could have a child. She promises to lift the curse if the two will go on a scavenger hunt for a milky white cow, a blood-red cape, corn-yellow hair and a golden slipper. So off the two go into the woods to undo the curse.
Their quest takes them on a path that crosses many of the Grimms' most beloved characters, including a delightfully silly and stupid Little Red Riding Hood (Annie Evans); a desperate Cinderella on the run (Sabrina Kales); a down-on-his-luck Jack with magic beans (Kiet Cao); a pitiful, put-upon Rapunzel (Holly Laguna); and a couple of philandering Prince Charmings (Evan Harris and Andrew Collins). Happily ever after is attained—then lost—a giant shows up, chaos reigns, and then happily ever after is regained.
While the story remains true to many of the Grimms' tales, it turns them on their heads by giving the characters smart-ass retorts and story-awareness that makes the show quite a bit more adult than those original morality tales, and yet a lot less horrifying.
Of course, being a Sondheim show, the songs rely on flat, minor keys with tunes that defy memorability yet incorporate some truly funny lyrics. Even now, I struggle to remember any tunes but one. "Agony," sung by the Prince Charming duet, who lament their bad luck in romantic matters, is the funniest, most memorable, most enjoyable piece of the entire show, and both Collins, as Cinderella's prince, and Harris, as Rapunzel's, are always captivating.
While I'm not really a fan of Sondheim's music, that's no reflection on the students' performances, which are consistently strong. In particular, Smith, Kales and Cao have outstanding voices. And Annie Evans' Red Riding Hood is, aside from the princes, the most fun character to watch, due mostly to her big smile as she delivers her character's idiotic observations.
There are also plenty of laughs almost through to the end, at which point, things come to a halt when a few overly melancholy numbers, performed in the dark, had me—I am ashamed to admit—almost nodding off. Thank goodness for the rousing finale.
And praise must be paid to the production design. It seems like the members of this company are constantly outdoing themselves. From the tree-lined path to the stars that actually twinkle, and from Cinderella's ball gown to the Big Bad Wolf's … um … anatomy, all the details really do make you feel completely absorbed into the woods.
More Arts&Culture » Art of the State
Light come shining
"They say everything can be replaced …"
They couldn't drag Omar Pierce away.
Discovered country
A new museum geared toward children is projected to open in 2011.
Tune in, turn on
A local author has adventures in self-publishing.
Nothing like cat scratch fever first thing in the morning.


text:
Hans Koch (* 27. November 1930 in Groß Breese; † 4. Dezember 1979) war ein deutscher Politiker (CDU). Er war Mitglied des Präsidiums des Hauptvorstandes und Vorsitzender des Bezirksverbandes Schwerin der CDU.

Leben
Koch, Sohn eines Landwirts, war nach dem Besuch der Volksschule auf dem elterlichen Hof tätig. Später qualifizierte er sich zum Agraringenieur.

Nach dem Zweiten Weltkrieg wirkte er aktiv bei der Durchführung der Bodenreform sowie in der Volkskongressbewegung im damaligen Land Mecklenburg mit. Er trat 1950 in die CDU ein und bekleidete von 1953 bis 1956 die Funktion des Vorsitzenden des CDU-Kreisverbandes Perleberg. Von 1956 bis 1958 fungierte er als stellvertretender Vorsitzender und ab 1958 als Vorsitzender des Bezirksverbandes Schwerin der CDU. Gleichzeitig war er ab 1958 Abgeordneter des Bezirkstages Schwerin, stellvertretender Vorsitzender des Bezirksvorstandes der Gesellschaft für Deutsch-Sowjetische Freundschaft und Mitglied des Bezirksausschusses der Nationalen Front. Koch wurde auf dem 9. Parteitag im Oktober 1958 zum Nachfolgekandidaten und auf dem 10. Parteitag im Juni 1960 zum Mitglied des CDU-Hauptvorstandes gewählt. Am 25. Juni 1974 erfolgte seine Wahl zum Mitglied des Präsidiums des Hauptvorstandes der CDU.

Koch starb im Alter von 49 Jahren und wurde auf dem Waldfriedhof in Schwerin-Krebsförden bestattet.

Auszeichnungen
1959 Verdienstmedaille der DDR
 1963 Ernst-Moritz-Arndt-Medaille
 1964 Vaterländischer Verdienstorden in Bronze und später in Silber
 1973 Otto-Nuschke-Ehrenzeichen in Gold

Literatur
 Günther Buch: Namen und Daten. Biographien wichtiger Personen der DDR. Dietz, Berlin (West)/Bonn-Bad Godesberg 1973, ISBN 3-8012-0020-5, S. 148.
 Andreas Herbst (Hrsg.), Winfried Ranke, Jürgen Winkler: So funktionierte die DDR. Band 3: Lexikon der Funktionäre (= rororo-Handbuch. Bd. 6350). Rowohlt, Reinbek bei Hamburg 1994, ISBN 3-499-16350-0, S. 177–178.

Einzelnachweise

CDU-Mitglied (DDR)
Träger des Vaterländischen Verdienstordens in Silber
Deutscher
Geboren 1930
Gestorben 1979
Mann

redpajama_set_name: RedPajamaWikipedia


Say prayers over the internet, and link to your friends on Twitter or Facebook. This is the Church of Sweden's plan to raise the historically low turnout for upcoming church elections.
The campaign also includes the possibility to pray via mobile phones (limited to 160 characters), as well as cinema and television advertising.
A prayer sent by text message from a mobile phone will wing its way to the Church of Sweden's new prayer page. Alternatively, users can submit a prayer direct to the new page or subscribe to an RSS feed of all the latest religious utterances.
The campaign was launched by the Church of Sweden at a Tuesday morning press conference and judging by previous voter turnout they are faced with a challenge of biblical proportions.
Around 5.6 million Swedes are eligible to vote in the church elections to be held on September 20th, but turnout is historically low - with a paltry 12 percent registering their preference in the previous vote in 2005.
The church has allocated a budget of around 10 million kronor ($1.4 million) for the prayer and election advertising campaign, excluding press advertisements.
According to Marianne Ejdersten Launikari, head of communication at the Church of Sweden, the religious group is probably the first of its kind to advertise an online prayer service.


As there will be no full papers published in connection to the symposium, we would like to draw your attention to an up-coming special issue published by the MDPI Journal energies.
Special Issue "Hydrothermal Technology in Biomass Utilization & Conversion"
The special issue aims at collecting recent innovative research works in the field, from basic to applied research, as well as industrial applications at pilot and demonstration scale. The outcome will constitute a valuable set of references for those investing time and effort in research in the field of hydrothermal processes. The journal offers an impact factor of 2.676 and a rapid publication process.
The manuscript submission expired on March 15th, 2019.
For submissions, please use the link provided above. Questions regarding the special issue should be addressed solely to the guest editors. Their respective contact data can also be found on the referenced website.
We highly encourage you to present your newest findings and latest research results in the special issue as well during the symposium.