int max_wal_senders = 0; /* the maximum number of concurrent walsenders */
int WalSndDelay = 200; /* max sleep time between some actions */
int replication_timeout = 0; /* maximum time to wait for the Ack from the standby */
+char *standby_fencing_command = NULL; /* command to shoot the standby in the head */
/*
* Buffer for WAL sending
static void XLogRead(char *buf, XLogRecPtr recptr, Size nbytes);
static bool XLogSend(bool *caughtup, bool *pending);
static void ProcessStreamMsgs(StringInfo inMsg);
+static void ExecuteStandbyFencingCommand(void);
static void RegisterWalSndWaiter(BackendId backendId, XLogRecPtr record,
Latch *latch);
{
Assert(MyWalSnd != NULL);
+ /*
+ * If replication was terminated for a reason other than the master
+ * server shutdown or emergency bailout (i.e., unexpected death of
+ * postmaster), we can expect this server can work standalone,
+ * so we call standby_fencing_command to shoot the standby server
+ * in the head if it's specified.
+ */
+ if (!ready_to_stop && PostmasterIsAlive(true))
+ ExecuteStandbyFencingCommand();
+
/* Wake up the backends that this walsender had been blocking */
MyWalSnd->rplMode = REPLICATION_MODE_ASYNC;
WakeupWalSndWaiters(GetOldestAckdPtr());
return true;
}
+/*
+ * Attempt to execute standby_fencing_command at the end of replication.
+ */
+static void
+ExecuteStandbyFencingCommand(void)
+{
+ char standbyFencingCmd[MAXPGPATH];
+ char *dp;
+ char *endp;
+ const char *sp;
+ int rc;
+
+ /* Do nothing if no command supplied */
+ if (standby_fencing_command[0] == '\0')
+ return;
+
+ /*
+ * construct the command to be executed
+ */
+ dp = standbyFencingCmd;
+ endp = standbyFencingCmd + MAXPGPATH - 1;
+ *endp = '\0';
+
+ for (sp = standby_fencing_command; *sp; sp++)
+ {
+ if (*sp == '%')
+ {
+ switch (sp[1])
+ {
+ case 'a':
+ {
+ /* %a: application_name */
+ const char *appname = application_name;
+
+ if (appname == NULL || *appname == '\0')
+ appname = _("[unknown]");
+
+ sp++;
+ strlcpy(dp, appname, endp - dp);
+ dp += strlen(dp);
+ break;
+ }
+ case '%':
+ /* convert %% to a single % */
+ sp++;
+ if (dp < endp)
+ *dp++ = *sp;
+ break;
+ default:
+ /* otherwise treat the % as not special */
+ if (dp < endp)
+ *dp++ = *sp;
+ break;
+ }
+ }
+ else
+ {
+ if (dp < endp)
+ *dp++ = *sp;
+ }
+ }
+ *dp = '\0';
+
+ ereport(DEBUG3,
+ (errmsg_internal("executing standby fencing command \"%s\"",
+ standbyFencingCmd)));
+
+ /*
+ * execute the constructed command
+ */
+ rc = system(standbyFencingCmd);
+ if (rc != 0)
+ {
+ /*
+ * No matter what code is returned, walsender can't stop exiting.
+ * We don't need to care about the return code of the command here.
+ */
+ ereport(WARNING,
+ (errmsg("standby fencing command failed with return code %d",
+ rc),
+ errdetail("The failed standby fencing command was: %s",
+ standbyFencingCmd)));
+ }
+}
+
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
WalSndSigHupHandler(SIGNAL_ARGS)
static const char *assign_canonical_path(const char *newval, bool doit, GucSource source);
static const char *assign_timezone_abbreviations(const char *newval, bool doit, GucSource source);
static const char *show_archive_command(void);
+static const char *show_standby_fencing_command(void);
static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source);
static bool assign_tcp_keepalives_interval(int newval, bool doit, GucSource source);
static bool assign_tcp_keepalives_count(int newval, bool doit, GucSource source);
},
{
+ {"standby_fencing_command", PGC_SIGHUP, WAL_REPLICATION,
+ gettext_noop("Sets the shell command that will be called to shoot the standby in the head."),
+ NULL
+ },
+ &standby_fencing_command,
+ "", NULL, show_standby_fencing_command
+ },
+
+ {
{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
gettext_noop("Sets the client's character set encoding."),
NULL,
return "(disabled)";
}
+static const char *
+show_standby_fencing_command(void)
+{
+ if (max_wal_senders > 0)
+ return standby_fencing_command;
+ else
+ return "(disabled)";
+}
+
static bool
assign_tcp_keepalives_idle(int newval, bool doit, GucSource source)
{