+sub loadBinCluster {
+ my $dbuser = shift;
+ my $dbpass = shift;
+
+ my $dsn;
+ my $dbh;
+ my $sth;
+ my $query;
+ my $recovery;
+ my $xlog_location;
+ my $apply_lag;
+ my $primaries = 0;
+
+ my @parts;
+ my $timeline;
+ my $location;
+ my $primary_location;
+
+ my $hostname;
+ my $port;
+ my $database;
+ my @tmp_cluster;
+ my @cluster;
+ my $node_id = 1;
+ $g_best_config = true;
+
+ foreach my $conninfo (@g_conninfos) {
+ $dsn = "DBI:Pg:$conninfo};";
+
+ eval {
+ $dbh = DBI->connect($dsn, $dbuser, $dbpass, {RaiseError => 1});
+ # Check to see if the server is a secondary, and also pull the current xlog
+ # location and the apply lag using pg_last_xact_replay_timestamp to get the
+ # last commit timestamp from the primary applied on the secondary.
+ # We will need to compare the current receive location to the primary xlog
+ # location, if they differ we can then use the apply_lag value; we'll have
+ # to post-process this.
+ # In 9.6+ we might want to pull the system identifier from pg_controldata view too
+ $query = "SELECT pg_is_in_recovery(),
+ CASE
+ WHEN pg_is_in_recovery() THEN pg_last_xlog_receive_location()
+ ELSE pg_current_xlog_location()
+ END,
+ COALESCE(extract(epoch from current_timestamp-pg_last_xact_replay_timestamp()),0)";
+ $sth = $dbh->prepare($query);
+ $sth->execute();
+ ($recovery, $xlog_location, $apply_lag) = $sth->fetchrow;
+ $sth->finish;
+
+ ($port) = $conninfo =~ m/port=(.+?)(\s|$)/g;
+ ($hostname) = $conninfo =~ m/host=(.+?)(\s|$)/g;
+ ($database) = $conninfo =~ m/dbname=(.+?)(\s|$)/g;
+ @parts = split('/', $xlog_location, 2);
+ $timeline = qtrim(trim($parts[0]));
+ $location = hex(qtrim(trim($parts[1])));
+
+ if ($g_debug) {
+ printLogLn($g_logfile, "DEBUG: Server: $hostname:$port " . ($recovery ? 'secondary' : 'primary') . " at $xlog_location ($timeline/$location)");
+ }
+
+ # For WAL replication we assume if we can contact a server then it is active,
+ # which isn't strictly true, but nodes that have fallen behind can be excluded
+ # via the max_ro_lag setting. We also substitute timeline+1 for the slony
+ # replication set.
+ if (!$recovery) {
+ $primaries++;
+ $primary_location = $xlog_location;
+ my @node=(1,'Primary',0,$timeline,"ACTIVE",($timeline+1),$conninfo,$database,$hostname,$port,1,$xlog_location,$apply_lag);
+ push(@tmp_cluster, \@node);
+ }
+ else {
+ $node_id++;
+ my @node=($node_id,"Secondary".($node_id-1),1,undef,"ACTIVE",($timeline+1),$conninfo,$database,$hostname,$port,$node_id,$xlog_location,$apply_lag);
+ push(@tmp_cluster, \@node);
+ }
+ };
+ if ($@) {
+ printLogLn($g_logfile, "ERROR: Could not connect to server with conninfo: $conninfo DETAIL: $@");
+ }
+ }
+
+ # Error if more than one primary discovered.
+ if ($primaries != 1) {
+ printLogLn($g_logfile, "ERROR: Invalid quantity of primaries: $primaries");
+ die "no primaries found";
+ }
+ # Do the post processing we mentioned above, once we know xlog locations differ
+ # then we can say the apply lag is correct, else it's just there has been no
+ # activity on the master. In the case the xlog locations differ but apply_lag
+ # is 0 then it means no WAL has been applied since srver start; cludge here
+ # and set lag to 1 week.
+ else {
+ foreach (@tmp_cluster) {
+ if (@$_[11] eq $primary_location) {
+ $apply_lag = 0;
+ }
+ else {
+ $apply_lag = @$_[12] if (@$_[12] > 0);
+ $apply_lag = 604800 if (@$_[12] = 0);
+ }
+ my @node=(@$_[0],@$_[1],@$_[2],@$_[3],@$_[4],@$_[5],@$_[6],@$_[7],@$_[8],@$_[9],@$_[10],$apply_lag);
+ push(@cluster, \@node);
+ }
+ }
+
+ return @cluster;
+}
+