2010-01-15 10:19:10 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* walreceiver.c
|
|
|
|
*
|
2010-02-17 05:19:41 +01:00
|
|
|
* The WAL receiver process (walreceiver) is new as of Postgres 9.0. It
|
2010-01-15 10:19:10 +01:00
|
|
|
* is the process in the standby server that takes charge of receiving
|
|
|
|
* XLOG records from a primary server during streaming replication.
|
|
|
|
*
|
|
|
|
* When the startup process determines that it's time to start streaming,
|
|
|
|
* it instructs postmaster to start walreceiver. Walreceiver first connects
|
2010-06-09 02:54:39 +02:00
|
|
|
* to the primary server (it will be served by a walsender process
|
2010-01-15 10:19:10 +01:00
|
|
|
* in the primary server), and then keeps receiving XLOG records and
|
|
|
|
* writing them to the disk as long as the connection is alive. As XLOG
|
|
|
|
* records are received and flushed to disk, it updates the
|
2020-04-08 13:45:09 +02:00
|
|
|
* WalRcv->flushedUpto variable in shared memory, to inform the startup
|
2010-01-15 10:19:10 +01:00
|
|
|
* process of how far it can proceed with XLOG replay.
|
|
|
|
*
|
2020-03-27 20:04:52 +01:00
|
|
|
* A WAL receiver cannot directly load GUC parameters used when establishing
|
|
|
|
* its connection to the primary. Instead it relies on parameter values
|
|
|
|
* that are passed down by the startup process when streaming is requested.
|
|
|
|
* This applies, for example, to the replication slot and the connection
|
|
|
|
* string to be used for the connection with the primary.
|
|
|
|
*
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
* If the primary server ends streaming, but doesn't disconnect, walreceiver
|
|
|
|
* goes into "waiting" mode, and waits for the startup process to give new
|
|
|
|
* instructions. The startup process will treat that the same as
|
2016-10-20 17:24:37 +02:00
|
|
|
* disconnection, and will rescan the archive/pg_wal directory. But when the
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
* startup process wants to try streaming replication again, it will just
|
|
|
|
* nudge the existing walreceiver process that's waiting, instead of launching
|
|
|
|
* a new one.
|
|
|
|
*
|
2010-01-15 10:19:10 +01:00
|
|
|
* Normal termination is by SIGTERM, which instructs the walreceiver to
|
|
|
|
* exit(0). Emergency termination is by SIGQUIT; like any postmaster child
|
|
|
|
* process, the walreceiver will simply abort and exit on SIGQUIT. A close
|
|
|
|
* of the connection and a FATAL error are treated not as a crash but as
|
|
|
|
* normal operation.
|
|
|
|
*
|
2010-01-20 10:16:24 +01:00
|
|
|
* This file contains the server-facing parts of walreceiver. The libpq-
|
|
|
|
* specific parts are in the libpqwalreceiver module. It's loaded
|
|
|
|
* dynamically to avoid linking the server with libpq.
|
2010-01-15 10:19:10 +01:00
|
|
|
*
|
2020-01-01 18:21:45 +01:00
|
|
|
* Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group
|
2010-01-15 10:19:10 +01:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/replication/walreceiver.c
|
2010-01-15 10:19:10 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2016-01-07 20:21:19 +01:00
|
|
|
#include "access/htup_details.h"
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
#include "access/timeline.h"
|
2013-02-04 11:29:22 +01:00
|
|
|
#include "access/transam.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
#include "access/xlog_internal.h"
|
2020-03-31 08:33:04 +02:00
|
|
|
#include "access/xlogarchive.h"
|
2017-03-30 20:18:53 +02:00
|
|
|
#include "catalog/pg_authid.h"
|
2016-01-07 20:21:19 +01:00
|
|
|
#include "catalog/pg_type.h"
|
2018-03-31 00:51:22 +02:00
|
|
|
#include "common/ip.h"
|
2016-01-07 20:21:19 +01:00
|
|
|
#include "funcapi.h"
|
2012-11-07 17:59:12 +01:00
|
|
|
#include "libpq/pqformat.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
#include "libpq/pqsignal.h"
|
|
|
|
#include "miscadmin.h"
|
2016-10-04 16:50:13 +02:00
|
|
|
#include "pgstat.h"
|
2019-12-17 19:14:28 +01:00
|
|
|
#include "postmaster/interrupt.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
#include "replication/walreceiver.h"
|
2011-09-04 07:13:16 +02:00
|
|
|
#include "replication/walsender.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
#include "storage/ipc.h"
|
|
|
|
#include "storage/pmsignal.h"
|
2011-02-16 20:29:37 +01:00
|
|
|
#include "storage/procarray.h"
|
2019-11-25 22:08:53 +01:00
|
|
|
#include "storage/procsignal.h"
|
2020-03-10 10:22:52 +01:00
|
|
|
#include "utils/acl.h"
|
2016-01-07 20:21:19 +01:00
|
|
|
#include "utils/builtins.h"
|
2011-09-04 07:13:16 +02:00
|
|
|
#include "utils/guc.h"
|
2016-01-07 20:21:19 +01:00
|
|
|
#include "utils/pg_lsn.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
#include "utils/ps_status.h"
|
|
|
|
#include "utils/resowner.h"
|
2011-09-09 19:23:41 +02:00
|
|
|
#include "utils/timestamp.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2010-02-19 11:51:04 +01:00
|
|
|
|
2020-03-27 20:04:52 +01:00
|
|
|
/*
|
|
|
|
* GUC variables. (Other variables that affect walreceiver are in xlog.c
|
|
|
|
* because they're passed down from the startup process, for better
|
|
|
|
* synchronization.)
|
|
|
|
*/
|
2011-02-10 20:00:29 +01:00
|
|
|
int wal_receiver_status_interval;
|
2012-10-11 16:39:52 +02:00
|
|
|
int wal_receiver_timeout;
|
2011-02-16 20:29:37 +01:00
|
|
|
bool hot_standby_feedback;
|
2011-02-10 20:00:29 +01:00
|
|
|
|
2016-11-30 18:00:00 +01:00
|
|
|
/* libpqwalreceiver connection */
|
|
|
|
static WalReceiverConn *wrconn = NULL;
|
|
|
|
WalReceiverFunctionsType *WalReceiverFunctions = NULL;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
#define NAPTIME_PER_CYCLE 100 /* max sleep time between cycles (100ms) */
|
|
|
|
|
|
|
|
/*
|
2020-02-11 05:22:37 +01:00
|
|
|
* These variables are used similarly to openLogFile/SegNo,
|
2012-06-24 17:06:38 +02:00
|
|
|
* but for walreceiver to write the XLOG. recvFileTLI is the TimeLineID
|
2012-08-09 00:58:49 +02:00
|
|
|
* corresponding the filename of recvFile.
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
|
|
|
static int recvFile = -1;
|
2013-05-29 22:58:43 +02:00
|
|
|
static TimeLineID recvFileTLI = 0;
|
2012-06-24 17:06:38 +02:00
|
|
|
static XLogSegNo recvSegNo = 0;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2010-04-21 00:55:03 +02:00
|
|
|
/*
|
|
|
|
* LogstreamResult indicates the byte positions that we have already
|
|
|
|
* written/fsynced.
|
|
|
|
*/
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
XLogRecPtr Write; /* last byte + 1 written out in the standby */
|
|
|
|
XLogRecPtr Flush; /* last byte + 1 flushed in the standby */
|
2017-06-21 20:39:04 +02:00
|
|
|
} LogstreamResult;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2013-05-29 22:58:43 +02:00
|
|
|
static StringInfoData reply_message;
|
|
|
|
static StringInfoData incoming_message;
|
2011-02-10 20:00:29 +01:00
|
|
|
|
2010-04-21 00:55:03 +02:00
|
|
|
/* Prototypes for private functions */
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
static void WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last);
|
|
|
|
static void WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI);
|
2010-04-21 00:55:03 +02:00
|
|
|
static void WalRcvDie(int code, Datum arg);
|
|
|
|
static void XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len);
|
|
|
|
static void XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr);
|
2011-02-16 16:24:50 +01:00
|
|
|
static void XLogWalRcvFlush(bool dying);
|
2012-10-11 16:39:52 +02:00
|
|
|
static void XLogWalRcvSendReply(bool force, bool requestReply);
|
2013-02-04 11:29:22 +01:00
|
|
|
static void XLogWalRcvSendHSFeedback(bool immed);
|
2011-12-31 14:30:26 +01:00
|
|
|
static void ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime);
|
2010-04-21 00:55:03 +02:00
|
|
|
|
In walreceiver, don't try to do ereport() in a signal handler.
This is quite unsafe, even for the case of ereport(FATAL) where we won't
return control to the interrupted code, and despite this code's use of
a flag to restrict the areas where we'd try to do it. It's possible
for example that we interrupt malloc or free while that's holding a lock
that's meant to protect against cross-thread interference. Then, any
attempt to do malloc or free within ereport() will result in a deadlock,
preventing the walreceiver process from exiting in response to SIGTERM.
We hypothesize that this explains some hard-to-reproduce failures seen
in the buildfarm.
Hence, get rid of the immediate-exit code in WalRcvShutdownHandler,
as well as the logic associated with WalRcvImmediateInterruptOK.
Instead, we need to take care that potentially-blocking operations
in the walreceiver's data transmission logic (libpqwalreceiver.c)
will respond reasonably promptly to the process's latch becoming
set and then call ProcessWalRcvInterrupts. Much of the needed code
for that was already present in libpqwalreceiver.c. I refactored
things a bit so that all the uses of PQgetResult use latch-aware
waiting, but didn't need to do much more.
These changes should be enough to ensure that libpqwalreceiver.c
will respond promptly to SIGTERM whenever it's waiting to receive
data. In principle, it could block for a long time while waiting
to send data too, and this patch does nothing to guard against that.
I think that that hazard is mostly theoretical though: such blocking
should occur only if we fill the kernel's data transmission buffers,
and we don't generally send enough data to make that happen without
waiting for input. If we find out that the hazard isn't just
theoretical, we could fix it by using PQsetnonblocking, but that
would require more ticklish changes than I care to make now.
This is a bug fix, but it seems like too big a change to push into
the back branches without much more testing than there's time for
right now. Perhaps we'll back-patch once we have more confidence
in the change.
Patch by me; thanks to Thomas Munro for review.
Discussion: https://postgr.es/m/20190416070119.GK2673@paquier.xyz
2019-04-29 18:26:07 +02:00
|
|
|
/*
|
|
|
|
* Process any interrupts the walreceiver process may have received.
|
|
|
|
* This should be called any time the process's latch has become set.
|
|
|
|
*
|
|
|
|
* Currently, only SIGTERM is of interest. We can't just exit(1) within the
|
|
|
|
* SIGTERM signal handler, because the signal might arrive in the middle of
|
|
|
|
* some critical operation, like while we're holding a spinlock. Instead, the
|
|
|
|
* signal handler sets a flag variable as well as setting the process's latch.
|
|
|
|
* We must check the flag (by calling ProcessWalRcvInterrupts) anytime the
|
|
|
|
* latch has become set. Operations that could block for a long time, such as
|
|
|
|
* reading from a remote server, must pay attention to the latch too; see
|
|
|
|
* libpqrcv_PQgetResult for example.
|
|
|
|
*/
|
|
|
|
void
|
2010-01-15 10:19:10 +01:00
|
|
|
ProcessWalRcvInterrupts(void)
|
|
|
|
{
|
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Although walreceiver interrupt handling doesn't use the same scheme as
|
|
|
|
* regular backends, call CHECK_FOR_INTERRUPTS() to make sure we receive
|
2019-12-19 20:56:20 +01:00
|
|
|
* any incoming signals on Win32, and also to make sure we process any
|
|
|
|
* barrier events.
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
|
2020-11-12 05:25:23 +01:00
|
|
|
if (ShutdownRequestPending)
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
|
|
|
ereport(FATAL,
|
|
|
|
(errcode(ERRCODE_ADMIN_SHUTDOWN),
|
|
|
|
errmsg("terminating walreceiver process due to administrator command")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Main entry point for walreceiver process */
|
2010-01-20 10:16:24 +01:00
|
|
|
void
|
|
|
|
WalReceiverMain(void)
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
char conninfo[MAXCONNINFO];
|
2016-06-29 22:57:17 +02:00
|
|
|
char *tmp_conninfo;
|
2014-02-01 04:45:17 +01:00
|
|
|
char slotname[NAMEDATALEN];
|
2020-01-14 14:07:11 +01:00
|
|
|
bool is_temp_slot;
|
2010-02-26 03:01:40 +01:00
|
|
|
XLogRecPtr startpoint;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
TimeLineID startpointTLI;
|
|
|
|
TimeLineID primaryTLI;
|
|
|
|
bool first_stream;
|
2015-10-06 21:45:02 +02:00
|
|
|
WalRcvData *walrcv = WalRcv;
|
2012-10-11 16:39:52 +02:00
|
|
|
TimestampTz last_recv_timestamp;
|
2017-10-03 14:58:25 +02:00
|
|
|
TimestampTz now;
|
2012-10-11 16:39:52 +02:00
|
|
|
bool ping_sent;
|
2017-01-19 18:00:00 +01:00
|
|
|
char *err;
|
2018-03-31 00:51:22 +02:00
|
|
|
char *sender_host = NULL;
|
|
|
|
int sender_port = 0;
|
2010-01-20 10:16:24 +01:00
|
|
|
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* WalRcv should be set up already (if we are a backend, we inherit this
|
|
|
|
* by fork() or EXEC_BACKEND mechanism from the postmaster).
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
*/
|
|
|
|
Assert(walrcv != NULL);
|
|
|
|
|
2017-10-03 14:58:25 +02:00
|
|
|
now = GetCurrentTimestamp();
|
|
|
|
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
/*
|
|
|
|
* Mark walreceiver as running in shared memory.
|
|
|
|
*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Do this as early as possible, so that if we fail later on, we'll set
|
|
|
|
* state to STOPPED. If we die before this, the startup process will keep
|
|
|
|
* waiting for us to start up, until it times out.
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
*/
|
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
|
|
|
Assert(walrcv->pid == 0);
|
2010-02-26 03:01:40 +01:00
|
|
|
switch (walrcv->walRcvState)
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
{
|
|
|
|
case WALRCV_STOPPING:
|
|
|
|
/* If we've already been requested to stop, don't start up. */
|
|
|
|
walrcv->walRcvState = WALRCV_STOPPED;
|
2020-05-13 21:31:14 +02:00
|
|
|
/* fall through */
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
|
|
|
|
case WALRCV_STOPPED:
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
proc_exit(1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WALRCV_STARTING:
|
|
|
|
/* The usual case */
|
|
|
|
break;
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
case WALRCV_WAITING:
|
|
|
|
case WALRCV_STREAMING:
|
|
|
|
case WALRCV_RESTARTING:
|
|
|
|
default:
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
/* Shouldn't happen */
|
2017-10-03 14:58:25 +02:00
|
|
|
SpinLockRelease(&walrcv->mutex);
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
elog(PANIC, "walreceiver still running according to shared memory state");
|
|
|
|
}
|
|
|
|
/* Advertise our PID so that the startup process can kill us */
|
|
|
|
walrcv->pid = MyProcPid;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
walrcv->walRcvState = WALRCV_STREAMING;
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
|
|
|
|
/* Fetch information required to start streaming */
|
2016-07-01 19:53:46 +02:00
|
|
|
walrcv->ready_to_display = false;
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
|
2014-02-01 04:45:17 +01:00
|
|
|
strlcpy(slotname, (char *) walrcv->slotname, NAMEDATALEN);
|
2020-01-14 14:07:11 +01:00
|
|
|
is_temp_slot = walrcv->is_temp_slot;
|
2011-03-01 19:46:57 +01:00
|
|
|
startpoint = walrcv->receiveStart;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
startpointTLI = walrcv->receiveStartTLI;
|
2011-12-31 14:30:26 +01:00
|
|
|
|
2020-03-27 20:04:52 +01:00
|
|
|
/*
|
|
|
|
* At most one of is_temp_slot and slotname can be set; otherwise,
|
|
|
|
* RequestXLogStreaming messed up.
|
|
|
|
*/
|
|
|
|
Assert(!is_temp_slot || (slotname[0] == '\0'));
|
|
|
|
|
2011-12-31 14:30:26 +01:00
|
|
|
/* Initialise to a sanish value */
|
2017-10-03 14:58:25 +02:00
|
|
|
walrcv->lastMsgSendTime =
|
|
|
|
walrcv->lastMsgReceiptTime = walrcv->latestWalEndTime = now;
|
2011-12-31 14:30:26 +01:00
|
|
|
|
2017-10-03 20:00:56 +02:00
|
|
|
/* Report the latch to use to awaken this process */
|
|
|
|
walrcv->latch = &MyProc->procLatch;
|
|
|
|
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
SpinLockRelease(&walrcv->mutex);
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2020-04-08 13:45:09 +02:00
|
|
|
pg_atomic_init_u64(&WalRcv->writtenUpto, 0);
|
|
|
|
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
/* Arrange to clean up at walreceiver exit */
|
|
|
|
on_shmem_exit(WalRcvDie, 0);
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
/* Properly accept or ignore signals the postmaster might send us */
|
2020-11-12 05:25:23 +01:00
|
|
|
pqsignal(SIGHUP, SignalHandlerForConfigReload); /* set flag to read config
|
|
|
|
* file */
|
2010-01-15 10:19:10 +01:00
|
|
|
pqsignal(SIGINT, SIG_IGN);
|
2020-11-12 05:25:23 +01:00
|
|
|
pqsignal(SIGTERM, SignalHandlerForShutdownRequest); /* request shutdown */
|
Centralize setup of SIGQUIT handling for postmaster child processes.
We decided that the policy established in commit 7634bd4f6 for
the bgwriter, checkpointer, walwriter, and walreceiver processes,
namely that they should accept SIGQUIT at all times, really ought
to apply uniformly to all postmaster children. Therefore, get
rid of the duplicative and inconsistent per-process code for
establishing that signal handler and removing SIGQUIT from BlockSig.
Instead, make InitPostmasterChild do it.
The handler set up by InitPostmasterChild is SignalHandlerForCrashExit,
which just summarily does _exit(2). In interactive backends, we
almost immediately replace that with quickdie, since we would prefer
to try to tell the client that we're dying. However, this patch is
changing the behavior of autovacuum (both launcher and workers), as
well as walsenders. Those processes formerly also used quickdie,
but AFAICS that was just mindless copy-and-paste: they don't have
any interactive client that's likely to benefit from being told this.
The stats collector continues to be an outlier, in that it thinks
SIGQUIT means normal exit. That should probably be changed for
consistency, but there's another patch set where that's being
dealt with, so I didn't do so here.
Discussion: https://postgr.es/m/644875.1599933441@sss.pgh.pa.us
2020-09-16 22:04:36 +02:00
|
|
|
/* SIGQUIT handler was already set up by InitPostmasterChild */
|
2010-01-15 10:19:10 +01:00
|
|
|
pqsignal(SIGALRM, SIG_IGN);
|
|
|
|
pqsignal(SIGPIPE, SIG_IGN);
|
2019-11-25 22:08:53 +01:00
|
|
|
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
|
2010-01-15 10:19:10 +01:00
|
|
|
pqsignal(SIGUSR2, SIG_IGN);
|
|
|
|
|
|
|
|
/* Reset some signals that are accepted by postmaster but not here */
|
|
|
|
pqsignal(SIGCHLD, SIG_DFL);
|
|
|
|
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
/* Load the libpq-specific functions */
|
|
|
|
load_file("libpqwalreceiver", false);
|
2016-11-30 18:00:00 +01:00
|
|
|
if (WalReceiverFunctions == NULL)
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
elog(ERROR, "libpqwalreceiver didn't initialize correctly");
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/* Unblock signals (they were blocked when the postmaster forked us) */
|
|
|
|
PG_SETMASK(&UnBlockSig);
|
|
|
|
|
2010-01-20 10:16:24 +01:00
|
|
|
/* Establish the connection to the primary for XLOG streaming */
|
2019-02-08 08:17:21 +01:00
|
|
|
wrconn = walrcv_connect(conninfo, false, cluster_name[0] ? cluster_name : "walreceiver", &err);
|
2017-01-19 18:00:00 +01:00
|
|
|
if (!wrconn)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errmsg("could not connect to the primary server: %s", err)));
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2016-06-29 22:57:17 +02:00
|
|
|
/*
|
|
|
|
* Save user-visible connection string. This clobbers the original
|
2018-03-31 00:51:22 +02:00
|
|
|
* conninfo, for security. Also save host and port of the sender server
|
|
|
|
* this walreceiver is connected to.
|
2016-06-29 22:57:17 +02:00
|
|
|
*/
|
2016-11-30 18:00:00 +01:00
|
|
|
tmp_conninfo = walrcv_get_conninfo(wrconn);
|
2018-03-31 00:51:22 +02:00
|
|
|
walrcv_get_senderinfo(wrconn, &sender_host, &sender_port);
|
2016-06-29 22:57:17 +02:00
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
|
|
|
memset(walrcv->conninfo, 0, MAXCONNINFO);
|
|
|
|
if (tmp_conninfo)
|
|
|
|
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
|
2018-03-31 00:51:22 +02:00
|
|
|
|
|
|
|
memset(walrcv->sender_host, 0, NI_MAXHOST);
|
|
|
|
if (sender_host)
|
|
|
|
strlcpy((char *) walrcv->sender_host, sender_host, NI_MAXHOST);
|
|
|
|
|
|
|
|
walrcv->sender_port = sender_port;
|
2016-06-29 22:57:17 +02:00
|
|
|
walrcv->ready_to_display = true;
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
|
2017-10-03 14:58:25 +02:00
|
|
|
if (tmp_conninfo)
|
|
|
|
pfree(tmp_conninfo);
|
|
|
|
|
2018-03-31 00:51:22 +02:00
|
|
|
if (sender_host)
|
|
|
|
pfree(sender_host);
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
first_stream = true;
|
2010-01-15 10:19:10 +01:00
|
|
|
for (;;)
|
|
|
|
{
|
2016-11-30 18:00:00 +01:00
|
|
|
char *primary_sysid;
|
|
|
|
char standby_sysid[32];
|
2017-01-19 18:00:00 +01:00
|
|
|
WalRcvStreamOptions options;
|
2016-11-30 18:00:00 +01:00
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/*
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
* Check that we're connected to a valid server using the
|
2017-01-19 18:00:00 +01:00
|
|
|
* IDENTIFY_SYSTEM replication command.
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
2019-03-15 10:16:26 +01:00
|
|
|
primary_sysid = walrcv_identify_system(wrconn, &primaryTLI);
|
2016-11-30 18:00:00 +01:00
|
|
|
|
|
|
|
snprintf(standby_sysid, sizeof(standby_sysid), UINT64_FORMAT,
|
|
|
|
GetSystemIdentifier());
|
|
|
|
if (strcmp(primary_sysid, standby_sysid) != 0)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errmsg("database system identifier differs between the primary and standby"),
|
|
|
|
errdetail("The primary's identifier is %s, the standby's identifier is %s.",
|
|
|
|
primary_sysid, standby_sysid)));
|
|
|
|
}
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
/*
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
* Confirm that the current timeline of the primary is the same or
|
|
|
|
* ahead of ours.
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
if (primaryTLI < startpointTLI)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errmsg("highest timeline %u of the primary is behind recovery timeline %u",
|
|
|
|
primaryTLI, startpointTLI)));
|
2010-01-15 10:19:10 +01:00
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
/*
|
|
|
|
* Get any missing history files. We do this always, even when we're
|
2013-05-29 22:58:43 +02:00
|
|
|
* not interested in that timeline, so that if we're promoted to
|
2020-06-14 23:05:18 +02:00
|
|
|
* become the primary later on, we don't select the same timeline that
|
|
|
|
* was already used in the current primary. This isn't bullet-proof -
|
2013-05-29 22:58:43 +02:00
|
|
|
* you'll need some external software to manage your cluster if you
|
|
|
|
* need to ensure that a unique timeline id is chosen in every case,
|
|
|
|
* but let's avoid the confusion of timeline id collisions where we
|
|
|
|
* can.
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
*/
|
2013-01-03 09:41:58 +01:00
|
|
|
WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2020-01-14 14:07:11 +01:00
|
|
|
/*
|
2020-03-27 20:04:52 +01:00
|
|
|
* Create temporary replication slot if requested, and update slot
|
|
|
|
* name in shared memory. (Note the slot name cannot already be set
|
|
|
|
* in this case.)
|
2020-01-14 14:07:11 +01:00
|
|
|
*/
|
2020-03-27 20:04:52 +01:00
|
|
|
if (is_temp_slot)
|
2020-01-14 14:07:11 +01:00
|
|
|
{
|
2020-03-27 20:04:52 +01:00
|
|
|
snprintf(slotname, sizeof(slotname),
|
|
|
|
"pg_walreceiver_%lld",
|
|
|
|
(long long int) walrcv_get_backend_pid(wrconn));
|
|
|
|
|
|
|
|
walrcv_create_slot(wrconn, slotname, true, 0, NULL);
|
|
|
|
|
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
|
|
|
strlcpy(walrcv->slotname, slotname, NAMEDATALEN);
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
2020-01-14 14:07:11 +01:00
|
|
|
}
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
/*
|
|
|
|
* Start streaming.
|
|
|
|
*
|
|
|
|
* We'll try to start at the requested starting point and timeline,
|
|
|
|
* even if it's different from the server's latest timeline. In case
|
|
|
|
* we've already reached the end of the old timeline, the server will
|
|
|
|
* finish the streaming immediately, and we will go back to await
|
|
|
|
* orders from the startup process. If recovery_target_timeline is
|
2016-10-20 17:24:37 +02:00
|
|
|
* 'latest', the startup process will scan pg_wal and find the new
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
* history file, bump recovery target timeline, and ask us to restart
|
|
|
|
* on the new timeline.
|
|
|
|
*/
|
2017-01-19 18:00:00 +01:00
|
|
|
options.logical = false;
|
|
|
|
options.startpoint = startpoint;
|
|
|
|
options.slotname = slotname[0] != '\0' ? slotname : NULL;
|
|
|
|
options.proto.physical.startpointTLI = startpointTLI;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
ThisTimeLineID = startpointTLI;
|
2017-01-19 18:00:00 +01:00
|
|
|
if (walrcv_startstreaming(wrconn, &options))
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
if (first_stream)
|
|
|
|
ereport(LOG,
|
|
|
|
(errmsg("started streaming WAL from primary at %X/%X on timeline %u",
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(uint32) (startpoint >> 32), (uint32) startpoint,
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
startpointTLI)));
|
|
|
|
else
|
|
|
|
ereport(LOG,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errmsg("restarted WAL streaming at %X/%X on timeline %u",
|
|
|
|
(uint32) (startpoint >> 32), (uint32) startpoint,
|
|
|
|
startpointTLI)));
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
first_stream = false;
|
|
|
|
|
|
|
|
/* Initialize LogstreamResult and buffers for processing messages */
|
Follow TLI of last replayed record, not recovery target TLI, in walsenders.
Most of the time, the last replayed record comes from the recovery target
timeline, but there is a corner case where it makes a difference. When
the startup process scans for a new timeline, and decides to change recovery
target timeline, there is a window where the recovery target TLI has already
been bumped, but there are no WAL segments from the new timeline in pg_xlog
yet. For example, if we have just replayed up to point 0/30002D8, on
timeline 1, there is a WAL file called 000000010000000000000003 in pg_xlog
that contains the WAL up to that point. When recovery switches recovery
target timeline to 2, a walsender can immediately try to read WAL from
0/30002D8, from timeline 2, so it will try to open WAL file
000000020000000000000003. However, that doesn't exist yet - the startup
process hasn't copied that file from the archive yet nor has the walreceiver
streamed it yet, so walsender fails with error "requested WAL segment
000000020000000000000003 has already been removed". That's harmless, in that
the standby will try to reconnect later and by that time the segment is
already created, but error messages that should be ignored are not good.
To fix that, have walsender track the TLI of the last replayed record,
instead of the recovery target timeline. That way walsender will not try to
read anything from timeline 2, until the WAL segment has been created and at
least one record has been replayed from it. The recovery target timeline is
now xlog.c's internal affair, it doesn't need to be exposed in shared memory
anymore.
This fixes the error reported by Thom Brown. depesz the same error message,
but I'm not sure if this fixes his scenario.
2012-12-20 13:23:31 +01:00
|
|
|
LogstreamResult.Write = LogstreamResult.Flush = GetXLogReplayRecPtr(NULL);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
initStringInfo(&reply_message);
|
|
|
|
initStringInfo(&incoming_message);
|
|
|
|
|
|
|
|
/* Initialize the last recv timestamp */
|
2012-10-11 16:39:52 +02:00
|
|
|
last_recv_timestamp = GetCurrentTimestamp();
|
|
|
|
ping_sent = false;
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
/* Loop until end-of-streaming or error */
|
2016-03-30 03:16:12 +02:00
|
|
|
for (;;)
|
2012-10-11 16:39:52 +02:00
|
|
|
{
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
char *buf;
|
|
|
|
int len;
|
2016-03-30 03:16:12 +02:00
|
|
|
bool endofwal = false;
|
2016-04-14 19:49:37 +02:00
|
|
|
pgsocket wait_fd = PGINVALID_SOCKET;
|
2016-03-30 03:16:12 +02:00
|
|
|
int rc;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Exit walreceiver if we're not in recovery. This should not
|
|
|
|
* happen, but cross-check the status here.
|
|
|
|
*/
|
|
|
|
if (!RecoveryInProgress())
|
|
|
|
ereport(FATAL,
|
|
|
|
(errmsg("cannot continue WAL streaming, recovery has already ended")));
|
|
|
|
|
|
|
|
/* Process any requests or signals received recently */
|
|
|
|
ProcessWalRcvInterrupts();
|
|
|
|
|
2020-11-12 05:25:23 +01:00
|
|
|
if (ConfigReloadPending)
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
{
|
2020-11-12 05:25:23 +01:00
|
|
|
ConfigReloadPending = false;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
ProcessConfigFile(PGC_SIGHUP);
|
2013-02-04 11:29:22 +01:00
|
|
|
XLogWalRcvSendHSFeedback(true);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
2016-03-30 03:16:12 +02:00
|
|
|
/* See if we can read data immediately */
|
2016-11-30 18:00:00 +01:00
|
|
|
len = walrcv_receive(wrconn, &buf, &wait_fd);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
if (len != 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Process the received data, and any subsequent data we
|
|
|
|
* can read without blocking.
|
|
|
|
*/
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (len > 0)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
/*
|
2020-06-14 23:05:18 +02:00
|
|
|
* Something was received from primary, so reset
|
2013-05-29 22:58:43 +02:00
|
|
|
* timeout
|
|
|
|
*/
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
last_recv_timestamp = GetCurrentTimestamp();
|
|
|
|
ping_sent = false;
|
|
|
|
XLogWalRcvProcessMsg(buf[0], &buf[1], len - 1);
|
|
|
|
}
|
|
|
|
else if (len == 0)
|
|
|
|
break;
|
|
|
|
else if (len < 0)
|
|
|
|
{
|
|
|
|
ereport(LOG,
|
|
|
|
(errmsg("replication terminated by primary server"),
|
2013-07-28 12:59:09 +02:00
|
|
|
errdetail("End of WAL reached on timeline %u at %X/%X.",
|
2013-01-17 22:12:30 +01:00
|
|
|
startpointTLI,
|
|
|
|
(uint32) (LogstreamResult.Write >> 32), (uint32) LogstreamResult.Write)));
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
endofwal = true;
|
|
|
|
break;
|
|
|
|
}
|
2016-11-30 18:00:00 +01:00
|
|
|
len = walrcv_receive(wrconn, &buf, &wait_fd);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
2020-06-14 23:05:18 +02:00
|
|
|
/* Let the primary know that we received some data. */
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
XLogWalRcvSendReply(false, false);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we've written some records, flush them to disk and
|
|
|
|
* let the startup process and primary server know about
|
|
|
|
* them.
|
|
|
|
*/
|
|
|
|
XLogWalRcvFlush(false);
|
|
|
|
}
|
2016-03-30 03:16:12 +02:00
|
|
|
|
|
|
|
/* Check if we need to exit the streaming loop. */
|
|
|
|
if (endofwal)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ideally we would reuse a WaitEventSet object repeatedly
|
|
|
|
* here to avoid the overheads of WaitLatchOrSocket on epoll
|
|
|
|
* systems, but we can't be sure that libpq (or any other
|
|
|
|
* walreceiver implementation) has the same socket (even if
|
|
|
|
* the fd is the same number, it may have been closed and
|
|
|
|
* reopened since the last time). In future, if there is a
|
|
|
|
* function for removing sockets from WaitEventSet, then we
|
|
|
|
* could add and remove just the socket each time, potentially
|
|
|
|
* avoiding some system calls.
|
|
|
|
*/
|
|
|
|
Assert(wait_fd != PGINVALID_SOCKET);
|
2020-11-12 05:25:23 +01:00
|
|
|
rc = WaitLatchOrSocket(MyLatch,
|
Add WL_EXIT_ON_PM_DEATH pseudo-event.
Users of the WaitEventSet and WaitLatch() APIs can now choose between
asking for WL_POSTMASTER_DEATH and then handling it explicitly, or asking
for WL_EXIT_ON_PM_DEATH to trigger immediate exit on postmaster death.
This reduces code duplication, since almost all callers want the latter.
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Assert that callers of WaitLatchXXX() under the postmaster remember to
ask for either WL_POSTMASTER_DEATH or WL_EXIT_ON_PM_DEATH, to prevent
future bugs.
The only process that doesn't handle postmaster death is syslogger. It
waits until all backends holding the write end of the syslog pipe
(including the postmaster) have closed it by exiting, to be sure to
capture any parting messages. By using the WaitEventSet API directly
it avoids the new assertion, and as a by-product it may be slightly
more efficient on platforms that have epoll().
Author: Thomas Munro
Reviewed-by: Kyotaro Horiguchi, Heikki Linnakangas, Tom Lane
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
2018-11-23 08:16:41 +01:00
|
|
|
WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
|
2016-03-30 03:16:12 +02:00
|
|
|
WL_TIMEOUT | WL_LATCH_SET,
|
|
|
|
wait_fd,
|
2016-10-04 16:50:13 +02:00
|
|
|
NAPTIME_PER_CYCLE,
|
|
|
|
WAIT_EVENT_WAL_RECEIVER_MAIN);
|
2016-03-30 03:16:12 +02:00
|
|
|
if (rc & WL_LATCH_SET)
|
|
|
|
{
|
2020-11-12 05:25:23 +01:00
|
|
|
ResetLatch(MyLatch);
|
In walreceiver, don't try to do ereport() in a signal handler.
This is quite unsafe, even for the case of ereport(FATAL) where we won't
return control to the interrupted code, and despite this code's use of
a flag to restrict the areas where we'd try to do it. It's possible
for example that we interrupt malloc or free while that's holding a lock
that's meant to protect against cross-thread interference. Then, any
attempt to do malloc or free within ereport() will result in a deadlock,
preventing the walreceiver process from exiting in response to SIGTERM.
We hypothesize that this explains some hard-to-reproduce failures seen
in the buildfarm.
Hence, get rid of the immediate-exit code in WalRcvShutdownHandler,
as well as the logic associated with WalRcvImmediateInterruptOK.
Instead, we need to take care that potentially-blocking operations
in the walreceiver's data transmission logic (libpqwalreceiver.c)
will respond reasonably promptly to the process's latch becoming
set and then call ProcessWalRcvInterrupts. Much of the needed code
for that was already present in libpqwalreceiver.c. I refactored
things a bit so that all the uses of PQgetResult use latch-aware
waiting, but didn't need to do much more.
These changes should be enough to ensure that libpqwalreceiver.c
will respond promptly to SIGTERM whenever it's waiting to receive
data. In principle, it could block for a long time while waiting
to send data too, and this patch does nothing to guard against that.
I think that that hazard is mostly theoretical though: such blocking
should occur only if we fill the kernel's data transmission buffers,
and we don't generally send enough data to make that happen without
waiting for input. If we find out that the hazard isn't just
theoretical, we could fix it by using PQsetnonblocking, but that
would require more ticklish changes than I care to make now.
This is a bug fix, but it seems like too big a change to push into
the back branches without much more testing than there's time for
right now. Perhaps we'll back-patch once we have more confidence
in the change.
Patch by me; thanks to Thomas Munro for review.
Discussion: https://postgr.es/m/20190416070119.GK2673@paquier.xyz
2019-04-29 18:26:07 +02:00
|
|
|
ProcessWalRcvInterrupts();
|
|
|
|
|
2016-03-30 03:16:12 +02:00
|
|
|
if (walrcv->force_reply)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The recovery process has asked us to send apply
|
|
|
|
* feedback now. Make sure the flag is really set to
|
2016-06-10 00:02:36 +02:00
|
|
|
* false in shared memory before sending the reply, so
|
|
|
|
* we don't miss a new request for a reply.
|
2016-03-30 03:16:12 +02:00
|
|
|
*/
|
|
|
|
walrcv->force_reply = false;
|
|
|
|
pg_memory_barrier();
|
|
|
|
XLogWalRcvSendReply(true, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rc & WL_TIMEOUT)
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We didn't receive anything new. If we haven't heard
|
|
|
|
* anything from the server for more than
|
2013-05-29 22:58:43 +02:00
|
|
|
* wal_receiver_timeout / 2, ping the server. Also, if
|
|
|
|
* it's been longer than wal_receiver_status_interval
|
|
|
|
* since the last update we sent, send a status update to
|
2020-06-14 23:05:18 +02:00
|
|
|
* the primary anyway, to report any progress in applying
|
2013-05-29 22:58:43 +02:00
|
|
|
* WAL.
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
*/
|
2013-05-29 22:58:43 +02:00
|
|
|
bool requestReply = false;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if time since last receive from standby has
|
|
|
|
* reached the configured limit.
|
|
|
|
*/
|
|
|
|
if (wal_receiver_timeout > 0)
|
|
|
|
{
|
|
|
|
TimestampTz now = GetCurrentTimestamp();
|
|
|
|
TimestampTz timeout;
|
|
|
|
|
|
|
|
timeout =
|
|
|
|
TimestampTzPlusMilliseconds(last_recv_timestamp,
|
|
|
|
wal_receiver_timeout);
|
|
|
|
|
|
|
|
if (now >= timeout)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errmsg("terminating walreceiver due to timeout")));
|
|
|
|
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* We didn't receive anything new, for half of
|
|
|
|
* receiver replication timeout. Ping the server.
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
*/
|
|
|
|
if (!ping_sent)
|
|
|
|
{
|
|
|
|
timeout = TimestampTzPlusMilliseconds(last_recv_timestamp,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(wal_receiver_timeout / 2));
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
if (now >= timeout)
|
|
|
|
{
|
|
|
|
requestReply = true;
|
|
|
|
ping_sent = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XLogWalRcvSendReply(requestReply, requestReply);
|
2013-02-04 11:29:22 +01:00
|
|
|
XLogWalRcvSendHSFeedback(false);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
}
|
|
|
|
}
|
2011-03-25 16:23:39 +01:00
|
|
|
|
2010-01-20 10:16:24 +01:00
|
|
|
/*
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
* The backend finished streaming. Exit streaming COPY-mode from
|
|
|
|
* our side, too.
|
2010-01-20 10:16:24 +01:00
|
|
|
*/
|
2016-11-30 18:00:00 +01:00
|
|
|
walrcv_endstreaming(wrconn, &primaryTLI);
|
2013-01-18 10:48:29 +01:00
|
|
|
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* If the server had switched to a new timeline that we didn't
|
|
|
|
* know about when we began streaming, fetch its timeline history
|
|
|
|
* file now.
|
2013-01-18 10:48:29 +01:00
|
|
|
*/
|
|
|
|
WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ereport(LOG,
|
|
|
|
(errmsg("primary server contains no more WAL on requested timeline %u",
|
|
|
|
startpointTLI)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End of WAL reached on the requested timeline. Close the last
|
|
|
|
* segment, and await for new orders from the startup process.
|
|
|
|
*/
|
|
|
|
if (recvFile >= 0)
|
|
|
|
{
|
2012-08-09 00:58:49 +02:00
|
|
|
char xlogfname[MAXFNAMELEN];
|
|
|
|
|
2011-02-16 16:24:50 +01:00
|
|
|
XLogWalRcvFlush(false);
|
2019-12-03 07:06:04 +01:00
|
|
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
if (close(recvFile) != 0)
|
|
|
|
ereport(PANIC,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not close log segment %s: %m",
|
2019-12-03 07:06:04 +01:00
|
|
|
xlogfname)));
|
2012-08-09 00:58:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create .done file forcibly to prevent the streamed segment from
|
|
|
|
* being archived later.
|
|
|
|
*/
|
2015-05-15 17:55:24 +02:00
|
|
|
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
|
|
|
|
XLogArchiveForceDone(xlogfname);
|
|
|
|
else
|
|
|
|
XLogArchiveNotify(xlogfname);
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
recvFile = -1;
|
|
|
|
|
|
|
|
elog(DEBUG1, "walreceiver ended streaming and awaits new instructions");
|
|
|
|
WalRcvWaitForStartPosition(&startpoint, &startpointTLI);
|
|
|
|
}
|
|
|
|
/* not reached */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for startup process to set receiveStart and receiveStartTLI.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
|
|
|
|
{
|
2015-10-06 21:45:02 +02:00
|
|
|
WalRcvData *walrcv = WalRcv;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
int state;
|
|
|
|
|
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
|
|
|
state = walrcv->walRcvState;
|
|
|
|
if (state != WALRCV_STREAMING)
|
|
|
|
{
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
if (state == WALRCV_STOPPING)
|
|
|
|
proc_exit(0);
|
2011-02-10 20:00:29 +01:00
|
|
|
else
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
elog(FATAL, "unexpected walreceiver state");
|
|
|
|
}
|
|
|
|
walrcv->walRcvState = WALRCV_WAITING;
|
|
|
|
walrcv->receiveStart = InvalidXLogRecPtr;
|
|
|
|
walrcv->receiveStartTLI = 0;
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
|
2020-03-11 16:36:40 +01:00
|
|
|
set_ps_display("idle");
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* nudge startup process to notice that we've stopped streaming and are
|
|
|
|
* now waiting for instructions.
|
|
|
|
*/
|
|
|
|
WakeupRecovery();
|
|
|
|
for (;;)
|
|
|
|
{
|
2020-11-12 05:25:23 +01:00
|
|
|
ResetLatch(MyLatch);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
|
|
|
|
ProcessWalRcvInterrupts();
|
|
|
|
|
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
|
|
|
Assert(walrcv->walRcvState == WALRCV_RESTARTING ||
|
|
|
|
walrcv->walRcvState == WALRCV_WAITING ||
|
|
|
|
walrcv->walRcvState == WALRCV_STOPPING);
|
|
|
|
if (walrcv->walRcvState == WALRCV_RESTARTING)
|
|
|
|
{
|
2020-03-27 23:43:41 +01:00
|
|
|
/*
|
|
|
|
* No need to handle changes in primary_conninfo or
|
|
|
|
* primary_slotname here. Startup process will signal us to
|
|
|
|
* terminate in case those change.
|
|
|
|
*/
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
*startpoint = walrcv->receiveStart;
|
|
|
|
*startpointTLI = walrcv->receiveStartTLI;
|
|
|
|
walrcv->walRcvState = WALRCV_STREAMING;
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (walrcv->walRcvState == WALRCV_STOPPING)
|
2011-02-10 20:00:29 +01:00
|
|
|
{
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* We should've received SIGTERM if the startup process wants us
|
|
|
|
* to die, but might as well check it here too.
|
2012-10-11 16:39:52 +02:00
|
|
|
*/
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
2012-10-11 16:39:52 +02:00
|
|
|
|
2020-11-12 05:25:23 +01:00
|
|
|
(void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
|
Add WL_EXIT_ON_PM_DEATH pseudo-event.
Users of the WaitEventSet and WaitLatch() APIs can now choose between
asking for WL_POSTMASTER_DEATH and then handling it explicitly, or asking
for WL_EXIT_ON_PM_DEATH to trigger immediate exit on postmaster death.
This reduces code duplication, since almost all callers want the latter.
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Assert that callers of WaitLatchXXX() under the postmaster remember to
ask for either WL_POSTMASTER_DEATH or WL_EXIT_ON_PM_DEATH, to prevent
future bugs.
The only process that doesn't handle postmaster death is syslogger. It
waits until all backends holding the write end of the syslog pipe
(including the postmaster) have closed it by exiting, to be sure to
capture any parting messages. By using the WaitEventSet API directly
it avoids the new assertion, and as a by-product it may be slightly
more efficient on platforms that have epoll().
Author: Thomas Munro
Reviewed-by: Kyotaro Horiguchi, Heikki Linnakangas, Tom Lane
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
2018-11-23 08:16:41 +01:00
|
|
|
WAIT_EVENT_WAL_RECEIVER_WAIT_START);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (update_process_title)
|
|
|
|
{
|
|
|
|
char activitymsg[50];
|
2012-10-11 16:39:52 +02:00
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
snprintf(activitymsg, sizeof(activitymsg), "restarting at %X/%X",
|
|
|
|
(uint32) (*startpoint >> 32),
|
|
|
|
(uint32) *startpoint);
|
2020-03-11 16:36:40 +01:00
|
|
|
set_ps_display(activitymsg);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
}
|
|
|
|
}
|
2012-10-11 16:39:52 +02:00
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
/*
|
|
|
|
* Fetch any missing timeline history files between 'first' and 'last'
|
|
|
|
* (inclusive) from the server.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
TimeLineID tli;
|
2012-10-11 16:39:52 +02:00
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
for (tli = first; tli <= last; tli++)
|
|
|
|
{
|
2013-01-03 09:41:58 +01:00
|
|
|
/* there's no history file for timeline 1 */
|
|
|
|
if (tli != 1 && !existsTimeLineHistory(tli))
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
{
|
|
|
|
char *fname;
|
|
|
|
char *content;
|
|
|
|
int len;
|
|
|
|
char expectedfname[MAXFNAMELEN];
|
2012-10-11 16:39:52 +02:00
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
ereport(LOG,
|
|
|
|
(errmsg("fetching timeline history file for timeline %u from primary server",
|
|
|
|
tli)));
|
|
|
|
|
2016-11-30 18:00:00 +01:00
|
|
|
walrcv_readtimelinehistoryfile(wrconn, tli, &fname, &content, &len);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
|
|
|
|
/*
|
2020-06-14 23:05:18 +02:00
|
|
|
* Check that the filename on the primary matches what we
|
2013-05-29 22:58:43 +02:00
|
|
|
* calculated ourselves. This is just a sanity check, it should
|
|
|
|
* always match.
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
*/
|
|
|
|
TLHistoryFileName(expectedfname, tli);
|
|
|
|
if (strcmp(fname, expectedfname) != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
2013-05-31 02:56:58 +02:00
|
|
|
errmsg_internal("primary reported unexpected file name for timeline history file of timeline %u",
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
tli)));
|
|
|
|
|
|
|
|
/*
|
2016-10-20 17:24:37 +02:00
|
|
|
* Write the file to pg_wal.
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
*/
|
|
|
|
writeTimeLineHistoryFile(tli, content, len);
|
|
|
|
|
2020-09-29 09:21:46 +02:00
|
|
|
/*
|
|
|
|
* Mark the streamed history file as ready for archiving
|
|
|
|
* if archive_mode is always.
|
|
|
|
*/
|
|
|
|
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
|
|
|
|
XLogArchiveForceDone(fname);
|
|
|
|
else
|
|
|
|
XLogArchiveNotify(fname);
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
pfree(fname);
|
|
|
|
pfree(content);
|
2011-02-10 20:00:29 +01:00
|
|
|
}
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
* Mark us as STOPPED in shared memory at exit.
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
|
|
|
static void
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
WalRcvDie(int code, Datum arg)
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
2015-10-06 21:45:02 +02:00
|
|
|
WalRcvData *walrcv = WalRcv;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2011-01-17 11:22:24 +01:00
|
|
|
/* Ensure that all WAL records received are flushed to disk */
|
2011-02-16 16:24:50 +01:00
|
|
|
XLogWalRcvFlush(true);
|
2011-01-17 11:22:24 +01:00
|
|
|
|
2017-10-03 20:00:56 +02:00
|
|
|
/* Mark ourselves inactive in shared memory */
|
2010-01-15 10:19:10 +01:00
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
Assert(walrcv->walRcvState == WALRCV_STREAMING ||
|
|
|
|
walrcv->walRcvState == WALRCV_RESTARTING ||
|
|
|
|
walrcv->walRcvState == WALRCV_STARTING ||
|
|
|
|
walrcv->walRcvState == WALRCV_WAITING ||
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
walrcv->walRcvState == WALRCV_STOPPING);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
Assert(walrcv->pid == MyProcPid);
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
walrcv->walRcvState = WALRCV_STOPPED;
|
2010-01-15 10:19:10 +01:00
|
|
|
walrcv->pid = 0;
|
2016-07-01 19:53:46 +02:00
|
|
|
walrcv->ready_to_display = false;
|
2017-10-03 20:00:56 +02:00
|
|
|
walrcv->latch = NULL;
|
2010-01-15 10:19:10 +01:00
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
|
Make standby server continuously retry restoring the next WAL segment with
restore_command, if the connection to the primary server is lost. This
ensures that the standby can recover automatically, if the connection is
lost for a long time and standby falls behind so much that the required
WAL segments have been archived and deleted in the master.
This also makes standby_mode useful without streaming replication; the
server will keep retrying restore_command every few seconds until the
trigger file is found. That's the same basic functionality pg_standby
offers, but without the bells and whistles.
To implement that, refactor the ReadRecord/FetchRecord functions. The
FetchRecord() function introduced in the original streaming replication
patch is removed, and all the retry logic is now in a new function called
XLogReadPage(). XLogReadPage() is now responsible for executing
restore_command, launching walreceiver, and waiting for new WAL to arrive
from primary, as required.
This also changes the life cycle of walreceiver. When launched, it now only
tries to connect to the master once, and exits if the connection fails, or
is lost during streaming for any reason. The startup process detects the
death, and re-launches walreceiver if necessary.
2010-01-27 16:27:51 +01:00
|
|
|
/* Terminate the connection gracefully. */
|
2016-11-30 18:00:00 +01:00
|
|
|
if (wrconn != NULL)
|
|
|
|
walrcv_disconnect(wrconn);
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
|
|
|
|
/* Wake up the startup process to notice promptly that we're gone */
|
|
|
|
WakeupRecovery();
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
|
2010-02-03 10:47:19 +01:00
|
|
|
/*
|
|
|
|
* Accept the message from XLOG stream, and process it.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len)
|
|
|
|
{
|
2012-11-07 17:59:12 +01:00
|
|
|
int hdrlen;
|
|
|
|
XLogRecPtr dataStart;
|
|
|
|
XLogRecPtr walEnd;
|
2013-05-29 22:58:43 +02:00
|
|
|
TimestampTz sendTime;
|
2012-11-07 17:59:12 +01:00
|
|
|
bool replyRequested;
|
|
|
|
|
|
|
|
resetStringInfo(&incoming_message);
|
|
|
|
|
2010-02-03 10:47:19 +01:00
|
|
|
switch (type)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
case 'w': /* WAL records */
|
|
|
|
{
|
2012-11-07 17:59:12 +01:00
|
|
|
/* copy message to StringInfo */
|
|
|
|
hdrlen = sizeof(int64) + sizeof(int64) + sizeof(int64);
|
|
|
|
if (len < hdrlen)
|
2010-02-26 03:01:40 +01:00
|
|
|
ereport(ERROR,
|
2010-04-21 00:55:03 +02:00
|
|
|
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
|
|
|
errmsg_internal("invalid WAL message received from primary")));
|
2012-11-07 17:59:12 +01:00
|
|
|
appendBinaryStringInfo(&incoming_message, buf, hdrlen);
|
|
|
|
|
|
|
|
/* read the fields */
|
|
|
|
dataStart = pq_getmsgint64(&incoming_message);
|
|
|
|
walEnd = pq_getmsgint64(&incoming_message);
|
2017-02-23 21:57:08 +01:00
|
|
|
sendTime = pq_getmsgint64(&incoming_message);
|
2012-11-07 17:59:12 +01:00
|
|
|
ProcessWalSndrMessage(walEnd, sendTime);
|
|
|
|
|
|
|
|
buf += hdrlen;
|
|
|
|
len -= hdrlen;
|
|
|
|
XLogWalRcvWrite(buf, len, dataStart);
|
2010-02-26 03:01:40 +01:00
|
|
|
break;
|
|
|
|
}
|
2011-12-31 14:30:26 +01:00
|
|
|
case 'k': /* Keepalive */
|
|
|
|
{
|
2012-11-07 17:59:12 +01:00
|
|
|
/* copy message to StringInfo */
|
|
|
|
hdrlen = sizeof(int64) + sizeof(int64) + sizeof(char);
|
|
|
|
if (len != hdrlen)
|
2011-12-31 14:30:26 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
|
|
|
errmsg_internal("invalid keepalive message received from primary")));
|
2012-11-07 17:59:12 +01:00
|
|
|
appendBinaryStringInfo(&incoming_message, buf, hdrlen);
|
2011-12-31 14:30:26 +01:00
|
|
|
|
2012-11-07 17:59:12 +01:00
|
|
|
/* read the fields */
|
|
|
|
walEnd = pq_getmsgint64(&incoming_message);
|
2017-02-23 21:57:08 +01:00
|
|
|
sendTime = pq_getmsgint64(&incoming_message);
|
2012-11-07 17:59:12 +01:00
|
|
|
replyRequested = pq_getmsgbyte(&incoming_message);
|
|
|
|
|
|
|
|
ProcessWalSndrMessage(walEnd, sendTime);
|
2012-10-11 16:39:52 +02:00
|
|
|
|
|
|
|
/* If the primary requested a reply, send one immediately */
|
2012-11-07 17:59:12 +01:00
|
|
|
if (replyRequested)
|
2012-10-11 16:39:52 +02:00
|
|
|
XLogWalRcvSendReply(true, false);
|
2011-12-31 14:30:26 +01:00
|
|
|
break;
|
|
|
|
}
|
2010-02-03 10:47:19 +01:00
|
|
|
default:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
2010-04-21 00:55:03 +02:00
|
|
|
errmsg_internal("invalid replication message type %d",
|
|
|
|
type)));
|
2010-02-03 10:47:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/*
|
|
|
|
* Write XLOG data to disk.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
int startoff;
|
|
|
|
int byteswritten;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
while (nbytes > 0)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
int segbytes;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo, wal_segment_size))
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
bool use_existent;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* fsync() and close current file before we switch to next one. We
|
|
|
|
* would otherwise have to reopen this file to fsync it later
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
|
|
|
if (recvFile >= 0)
|
|
|
|
{
|
2012-08-09 00:58:49 +02:00
|
|
|
char xlogfname[MAXFNAMELEN];
|
|
|
|
|
2011-02-16 16:24:50 +01:00
|
|
|
XLogWalRcvFlush(false);
|
2010-02-19 11:51:04 +01:00
|
|
|
|
2019-12-03 07:06:04 +01:00
|
|
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/*
|
2010-02-19 11:51:04 +01:00
|
|
|
* XLOG segment files will be re-read by recovery in startup
|
|
|
|
* process soon, so we don't advise the OS to release cache
|
|
|
|
* pages associated with the file like XLogFileClose() does.
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
|
|
|
if (close(recvFile) != 0)
|
|
|
|
ereport(PANIC,
|
|
|
|
(errcode_for_file_access(),
|
2012-06-24 17:06:38 +02:00
|
|
|
errmsg("could not close log segment %s: %m",
|
2019-12-03 07:06:04 +01:00
|
|
|
xlogfname)));
|
2012-08-09 00:58:49 +02:00
|
|
|
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Create .done file forcibly to prevent the streamed segment
|
|
|
|
* from being archived later.
|
2012-08-09 00:58:49 +02:00
|
|
|
*/
|
2015-05-15 17:55:24 +02:00
|
|
|
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
|
|
|
|
XLogArchiveForceDone(xlogfname);
|
|
|
|
else
|
|
|
|
XLogArchiveNotify(xlogfname);
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
recvFile = -1;
|
|
|
|
|
|
|
|
/* Create/use new log file */
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
XLByteToSeg(recptr, recvSegNo, wal_segment_size);
|
2010-01-15 10:19:10 +01:00
|
|
|
use_existent = true;
|
2012-06-24 17:06:38 +02:00
|
|
|
recvFile = XLogFileInit(recvSegNo, &use_existent, true);
|
|
|
|
recvFileTLI = ThisTimeLineID;
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the start offset of the received logs */
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
startoff = XLogSegmentOffset(recptr, wal_segment_size);
|
2010-01-15 10:19:10 +01:00
|
|
|
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
if (startoff + nbytes > wal_segment_size)
|
|
|
|
segbytes = wal_segment_size - startoff;
|
2010-01-15 10:19:10 +01:00
|
|
|
else
|
|
|
|
segbytes = nbytes;
|
|
|
|
|
|
|
|
/* OK to write the logs */
|
|
|
|
errno = 0;
|
|
|
|
|
2020-02-11 05:22:37 +01:00
|
|
|
byteswritten = pg_pwrite(recvFile, buf, segbytes, (off_t) startoff);
|
2010-01-15 10:19:10 +01:00
|
|
|
if (byteswritten <= 0)
|
|
|
|
{
|
2019-12-03 07:06:04 +01:00
|
|
|
char xlogfname[MAXFNAMELEN];
|
|
|
|
int save_errno;
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/* if write didn't set errno, assume no disk space */
|
|
|
|
if (errno == 0)
|
|
|
|
errno = ENOSPC;
|
2019-12-03 07:06:04 +01:00
|
|
|
|
|
|
|
save_errno = errno;
|
|
|
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
|
|
|
|
errno = save_errno;
|
2010-01-15 10:19:10 +01:00
|
|
|
ereport(PANIC,
|
|
|
|
(errcode_for_file_access(),
|
2012-06-24 17:06:38 +02:00
|
|
|
errmsg("could not write to log segment %s "
|
2010-01-15 10:19:10 +01:00
|
|
|
"at offset %u, length %lu: %m",
|
2020-02-11 05:22:37 +01:00
|
|
|
xlogfname, startoff, (unsigned long) segbytes)));
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Update state for write */
|
2012-12-28 17:06:15 +01:00
|
|
|
recptr += byteswritten;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
nbytes -= byteswritten;
|
|
|
|
buf += byteswritten;
|
|
|
|
|
2010-02-26 03:01:40 +01:00
|
|
|
LogstreamResult.Write = recptr;
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
2020-04-08 13:45:09 +02:00
|
|
|
|
|
|
|
/* Update shared-memory status */
|
|
|
|
pg_atomic_write_u64(&WalRcv->writtenUpto, LogstreamResult.Write);
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
|
2011-02-16 16:24:50 +01:00
|
|
|
/*
|
|
|
|
* Flush the log to disk.
|
|
|
|
*
|
|
|
|
* If we're in the midst of dying, it's unwise to do anything that might throw
|
|
|
|
* an error, so we skip sending a reply in that case.
|
|
|
|
*/
|
2010-01-15 10:19:10 +01:00
|
|
|
static void
|
2011-02-16 16:24:50 +01:00
|
|
|
XLogWalRcvFlush(bool dying)
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
2012-12-28 17:06:15 +01:00
|
|
|
if (LogstreamResult.Flush < LogstreamResult.Write)
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
2015-10-06 21:45:02 +02:00
|
|
|
WalRcvData *walrcv = WalRcv;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
2012-06-24 17:06:38 +02:00
|
|
|
issue_xlog_fsync(recvFile, recvSegNo);
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
LogstreamResult.Flush = LogstreamResult.Write;
|
|
|
|
|
|
|
|
/* Update shared-memory status */
|
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
2020-04-08 13:45:09 +02:00
|
|
|
if (walrcv->flushedUpto < LogstreamResult.Flush)
|
2011-03-01 19:46:57 +01:00
|
|
|
{
|
2020-04-08 13:45:09 +02:00
|
|
|
walrcv->latestChunkStart = walrcv->flushedUpto;
|
|
|
|
walrcv->flushedUpto = LogstreamResult.Flush;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
walrcv->receivedTLI = ThisTimeLineID;
|
2011-03-01 19:46:57 +01:00
|
|
|
}
|
2010-01-15 10:19:10 +01:00
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
|
2011-07-19 04:40:03 +02:00
|
|
|
/* Signal the startup process and walsender that new WAL has arrived */
|
2010-09-15 12:35:05 +02:00
|
|
|
WakeupRecovery();
|
2011-07-19 04:40:03 +02:00
|
|
|
if (AllowCascadeReplication())
|
|
|
|
WalSndWakeup();
|
2010-09-15 12:35:05 +02:00
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/* Report XLOG streaming progress in PS display */
|
2010-06-07 17:49:30 +02:00
|
|
|
if (update_process_title)
|
|
|
|
{
|
|
|
|
char activitymsg[50];
|
|
|
|
|
|
|
|
snprintf(activitymsg, sizeof(activitymsg), "streaming %X/%X",
|
2012-06-24 17:51:37 +02:00
|
|
|
(uint32) (LogstreamResult.Write >> 32),
|
|
|
|
(uint32) LogstreamResult.Write);
|
2020-03-11 16:36:40 +01:00
|
|
|
set_ps_display(activitymsg);
|
2010-06-07 17:49:30 +02:00
|
|
|
}
|
2011-02-10 20:00:29 +01:00
|
|
|
|
2020-06-14 23:05:18 +02:00
|
|
|
/* Also let the primary know that we made some progress */
|
2011-02-16 16:24:50 +01:00
|
|
|
if (!dying)
|
2014-01-16 22:05:02 +01:00
|
|
|
{
|
2012-10-11 16:39:52 +02:00
|
|
|
XLogWalRcvSendReply(false, false);
|
2014-01-16 22:05:02 +01:00
|
|
|
XLogWalRcvSendHSFeedback(false);
|
|
|
|
}
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
}
|
2011-02-10 20:00:29 +01:00
|
|
|
|
|
|
|
/*
|
2017-05-12 19:51:27 +02:00
|
|
|
* Send reply message to primary, indicating our current WAL locations, oldest
|
2012-10-11 16:39:52 +02:00
|
|
|
* xmin and the current time.
|
|
|
|
*
|
|
|
|
* If 'force' is not set, the message is only sent if enough time has
|
2012-10-15 12:01:31 +02:00
|
|
|
* passed since last status update to reach wal_receiver_status_interval.
|
2012-10-11 16:39:52 +02:00
|
|
|
* If wal_receiver_status_interval is disabled altogether and 'force' is
|
|
|
|
* false, this is a no-op.
|
|
|
|
*
|
|
|
|
* If 'requestReply' is true, requests the server to reply immediately upon
|
2019-10-30 02:03:00 +01:00
|
|
|
* receiving this message. This is used for heartbeats, when approaching
|
2012-10-11 16:39:52 +02:00
|
|
|
* wal_receiver_timeout.
|
2011-02-10 20:00:29 +01:00
|
|
|
*/
|
|
|
|
static void
|
2012-10-11 16:39:52 +02:00
|
|
|
XLogWalRcvSendReply(bool force, bool requestReply)
|
2011-02-10 20:00:29 +01:00
|
|
|
{
|
2012-11-07 17:59:12 +01:00
|
|
|
static XLogRecPtr writePtr = 0;
|
|
|
|
static XLogRecPtr flushPtr = 0;
|
|
|
|
XLogRecPtr applyPtr;
|
|
|
|
static TimestampTz sendTime = 0;
|
2011-04-10 17:42:00 +02:00
|
|
|
TimestampTz now;
|
2011-02-10 20:00:29 +01:00
|
|
|
|
|
|
|
/*
|
2020-06-14 23:05:18 +02:00
|
|
|
* If the user doesn't want status to be reported to the primary, be sure
|
2011-02-10 20:00:29 +01:00
|
|
|
* to exit before doing anything at all.
|
|
|
|
*/
|
2012-10-11 16:39:52 +02:00
|
|
|
if (!force && wal_receiver_status_interval <= 0)
|
2011-02-10 20:00:29 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Get current timestamp. */
|
|
|
|
now = GetCurrentTimestamp();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can compare the write and flush positions to the last message we
|
|
|
|
* sent without taking any lock, but the apply position requires a spin
|
|
|
|
* lock, so we don't check that unless something else has changed or 10
|
2017-05-12 19:51:27 +02:00
|
|
|
* seconds have passed. This means that the apply WAL location will
|
2020-06-14 23:05:18 +02:00
|
|
|
* appear, from the primary's point of view, to lag slightly, but since
|
2011-02-10 20:00:29 +01:00
|
|
|
* this is only for reporting purposes and only on idle systems, that's
|
|
|
|
* probably OK.
|
|
|
|
*/
|
2012-10-11 16:39:52 +02:00
|
|
|
if (!force
|
2012-12-28 17:06:15 +01:00
|
|
|
&& writePtr == LogstreamResult.Write
|
|
|
|
&& flushPtr == LogstreamResult.Flush
|
2012-11-07 17:59:12 +01:00
|
|
|
&& !TimestampDifferenceExceeds(sendTime, now,
|
2011-04-10 17:42:00 +02:00
|
|
|
wal_receiver_status_interval * 1000))
|
2011-02-10 20:00:29 +01:00
|
|
|
return;
|
2012-11-07 17:59:12 +01:00
|
|
|
sendTime = now;
|
2011-02-10 20:00:29 +01:00
|
|
|
|
2011-02-16 20:29:37 +01:00
|
|
|
/* Construct a new message */
|
2012-11-07 17:59:12 +01:00
|
|
|
writePtr = LogstreamResult.Write;
|
|
|
|
flushPtr = LogstreamResult.Flush;
|
Follow TLI of last replayed record, not recovery target TLI, in walsenders.
Most of the time, the last replayed record comes from the recovery target
timeline, but there is a corner case where it makes a difference. When
the startup process scans for a new timeline, and decides to change recovery
target timeline, there is a window where the recovery target TLI has already
been bumped, but there are no WAL segments from the new timeline in pg_xlog
yet. For example, if we have just replayed up to point 0/30002D8, on
timeline 1, there is a WAL file called 000000010000000000000003 in pg_xlog
that contains the WAL up to that point. When recovery switches recovery
target timeline to 2, a walsender can immediately try to read WAL from
0/30002D8, from timeline 2, so it will try to open WAL file
000000020000000000000003. However, that doesn't exist yet - the startup
process hasn't copied that file from the archive yet nor has the walreceiver
streamed it yet, so walsender fails with error "requested WAL segment
000000020000000000000003 has already been removed". That's harmless, in that
the standby will try to reconnect later and by that time the segment is
already created, but error messages that should be ignored are not good.
To fix that, have walsender track the TLI of the last replayed record,
instead of the recovery target timeline. That way walsender will not try to
read anything from timeline 2, until the WAL segment has been created and at
least one record has been replayed from it. The recovery target timeline is
now xlog.c's internal affair, it doesn't need to be exposed in shared memory
anymore.
This fixes the error reported by Thom Brown. depesz the same error message,
but I'm not sure if this fixes his scenario.
2012-12-20 13:23:31 +01:00
|
|
|
applyPtr = GetXLogReplayRecPtr(NULL);
|
2012-11-07 17:59:12 +01:00
|
|
|
|
|
|
|
resetStringInfo(&reply_message);
|
|
|
|
pq_sendbyte(&reply_message, 'r');
|
|
|
|
pq_sendint64(&reply_message, writePtr);
|
|
|
|
pq_sendint64(&reply_message, flushPtr);
|
|
|
|
pq_sendint64(&reply_message, applyPtr);
|
2017-02-23 21:57:08 +01:00
|
|
|
pq_sendint64(&reply_message, GetCurrentTimestamp());
|
2012-11-07 17:59:12 +01:00
|
|
|
pq_sendbyte(&reply_message, requestReply ? 1 : 0);
|
|
|
|
|
|
|
|
/* Send it */
|
|
|
|
elog(DEBUG2, "sending write %X/%X flush %X/%X apply %X/%X%s",
|
|
|
|
(uint32) (writePtr >> 32), (uint32) writePtr,
|
|
|
|
(uint32) (flushPtr >> 32), (uint32) flushPtr,
|
|
|
|
(uint32) (applyPtr >> 32), (uint32) applyPtr,
|
|
|
|
requestReply ? " (reply requested)" : "");
|
|
|
|
|
2016-11-30 18:00:00 +01:00
|
|
|
walrcv_send(wrconn, reply_message.data, reply_message.len);
|
2011-02-10 20:00:29 +01:00
|
|
|
}
|
2011-02-18 12:31:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Send hot standby feedback message to primary, plus the current time,
|
|
|
|
* in case they don't have a watch.
|
2013-02-04 11:29:22 +01:00
|
|
|
*
|
|
|
|
* If the user disables feedback, send one final message to tell sender
|
2017-01-26 19:14:02 +01:00
|
|
|
* to forget about the xmin on this standby. We also send this message
|
|
|
|
* on first connect because a previous connection might have set xmin
|
|
|
|
* on a replication slot. (If we're not using a slot it's harmless to
|
|
|
|
* send a feedback message explicitly setting InvalidTransactionId).
|
2011-02-18 12:31:49 +01:00
|
|
|
*/
|
|
|
|
static void
|
2013-02-04 11:29:22 +01:00
|
|
|
XLogWalRcvSendHSFeedback(bool immed)
|
2011-02-18 12:31:49 +01:00
|
|
|
{
|
2011-04-10 17:42:00 +02:00
|
|
|
TimestampTz now;
|
2019-03-27 22:34:43 +01:00
|
|
|
FullTransactionId nextFullXid;
|
2011-04-10 17:42:00 +02:00
|
|
|
TransactionId nextXid;
|
2017-05-17 22:31:56 +02:00
|
|
|
uint32 xmin_epoch,
|
|
|
|
catalog_xmin_epoch;
|
|
|
|
TransactionId xmin,
|
|
|
|
catalog_xmin;
|
2012-11-07 17:59:12 +01:00
|
|
|
static TimestampTz sendTime = 0;
|
2017-05-17 22:31:56 +02:00
|
|
|
|
2017-01-26 19:14:02 +01:00
|
|
|
/* initially true so we always send at least one feedback message */
|
2020-06-14 23:05:18 +02:00
|
|
|
static bool primary_has_standby_xmin = true;
|
2011-02-18 12:31:49 +01:00
|
|
|
|
|
|
|
/*
|
2020-06-14 23:05:18 +02:00
|
|
|
* If the user doesn't want status to be reported to the primary, be sure
|
2011-02-18 12:31:49 +01:00
|
|
|
* to exit before doing anything at all.
|
|
|
|
*/
|
2013-02-04 11:29:22 +01:00
|
|
|
if ((wal_receiver_status_interval <= 0 || !hot_standby_feedback) &&
|
2020-06-14 23:05:18 +02:00
|
|
|
!primary_has_standby_xmin)
|
2011-02-18 12:31:49 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Get current timestamp. */
|
|
|
|
now = GetCurrentTimestamp();
|
|
|
|
|
2013-02-04 11:29:22 +01:00
|
|
|
if (!immed)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Send feedback at most once per wal_receiver_status_interval.
|
|
|
|
*/
|
|
|
|
if (!TimestampDifferenceExceeds(sendTime, now,
|
2013-05-29 22:58:43 +02:00
|
|
|
wal_receiver_status_interval * 1000))
|
2013-02-04 11:29:22 +01:00
|
|
|
return;
|
|
|
|
sendTime = now;
|
|
|
|
}
|
2011-02-18 12:31:49 +01:00
|
|
|
|
|
|
|
/*
|
2017-01-26 19:14:02 +01:00
|
|
|
* If Hot Standby is not yet accepting connections there is nothing to
|
|
|
|
* send. Check this after the interval has expired to reduce number of
|
|
|
|
* calls.
|
|
|
|
*
|
|
|
|
* Bailing out here also ensures that we don't send feedback until we've
|
2020-06-14 23:05:18 +02:00
|
|
|
* read our own replication slot state, so we don't tell the primary to
|
2017-05-17 22:31:56 +02:00
|
|
|
* discard needed xmin or catalog_xmin from any slots that may exist on
|
|
|
|
* this replica.
|
2011-02-18 12:31:49 +01:00
|
|
|
*/
|
|
|
|
if (!HotStandbyActive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
* Make the expensive call to get the oldest xmin once we are certain
|
|
|
|
* everything else has been checked.
|
2011-02-18 12:31:49 +01:00
|
|
|
*/
|
2013-02-04 11:29:22 +01:00
|
|
|
if (hot_standby_feedback)
|
2017-03-25 15:07:27 +01:00
|
|
|
{
|
snapshot scalability: Don't compute global horizons while building snapshots.
To make GetSnapshotData() more scalable, it cannot not look at at each proc's
xmin: While snapshot contents do not need to change whenever a read-only
transaction commits or a snapshot is released, a proc's xmin is modified in
those cases. The frequency of xmin modifications leads to, particularly on
higher core count systems, many cache misses inside GetSnapshotData(), despite
the data underlying a snapshot not changing. That is the most
significant source of GetSnapshotData() scaling poorly on larger systems.
Without accessing xmins, GetSnapshotData() cannot calculate accurate horizons /
thresholds as it has so far. But we don't really have to: The horizons don't
actually change that much between GetSnapshotData() calls. Nor are the horizons
actually used every time a snapshot is built.
The trick this commit introduces is to delay computation of accurate horizons
until there use and using horizon boundaries to determine whether accurate
horizons need to be computed.
The use of RecentGlobal[Data]Xmin to decide whether a row version could be
removed has been replaces with new GlobalVisTest* functions. These use two
thresholds to determine whether a row can be pruned:
1) definitely_needed, indicating that rows deleted by XIDs >= definitely_needed
are definitely still visible.
2) maybe_needed, indicating that rows deleted by XIDs < maybe_needed can
definitely be removed
GetSnapshotData() updates definitely_needed to be the xmin of the computed
snapshot.
When testing whether a row can be removed (with GlobalVisTestIsRemovableXid())
and the tested XID falls in between the two (i.e. XID >= maybe_needed && XID <
definitely_needed) the boundaries can be recomputed to be more accurate. As it
is not cheap to compute accurate boundaries, we limit the number of times that
happens in short succession. As the boundaries used by
GlobalVisTestIsRemovableXid() are never reset (with maybe_needed updated by
GetSnapshotData()), it is likely that further test can benefit from an earlier
computation of accurate horizons.
To avoid regressing performance when old_snapshot_threshold is set (as that
requires an accurate horizon to be computed), heap_page_prune_opt() doesn't
unconditionally call TransactionIdLimitedForOldSnapshots() anymore. Both the
computation of the limited horizon, and the triggering of errors (with
SetOldSnapshotThresholdTimestamp()) is now only done when necessary to remove
tuples.
This commit just removes the accesses to PGXACT->xmin from
GetSnapshotData(), but other members of PGXACT residing in the same
cache line are accessed. Therefore this in itself does not result in a
significant improvement. Subsequent commits will take advantage of the
fact that GetSnapshotData() now does not need to access xmins anymore.
Note: This contains a workaround in heap_page_prune_opt() to keep the
snapshot_too_old tests working. While that workaround is ugly, the tests
currently are not meaningful, and it seems best to address them separately.
Author: Andres Freund <andres@anarazel.de>
Reviewed-By: Robert Haas <robertmhaas@gmail.com>
Reviewed-By: Thomas Munro <thomas.munro@gmail.com>
Reviewed-By: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/20200301083601.ews6hz5dduc3w2se@alap3.anarazel.de
2020-08-13 01:03:49 +02:00
|
|
|
GetReplicationHorizons(&xmin, &catalog_xmin);
|
2017-03-25 15:07:27 +01:00
|
|
|
}
|
2013-02-04 11:29:22 +01:00
|
|
|
else
|
2017-03-25 15:07:27 +01:00
|
|
|
{
|
2013-02-04 11:29:22 +01:00
|
|
|
xmin = InvalidTransactionId;
|
2017-03-25 15:07:27 +01:00
|
|
|
catalog_xmin = InvalidTransactionId;
|
|
|
|
}
|
2011-02-18 12:31:49 +01:00
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
* Get epoch and adjust if nextXid and oldestXmin are different sides of
|
|
|
|
* the epoch boundary.
|
2011-02-18 12:31:49 +01:00
|
|
|
*/
|
2019-03-27 22:34:43 +01:00
|
|
|
nextFullXid = ReadNextFullTransactionId();
|
|
|
|
nextXid = XidFromFullTransactionId(nextFullXid);
|
|
|
|
xmin_epoch = EpochFromFullTransactionId(nextFullXid);
|
2017-03-25 15:07:27 +01:00
|
|
|
catalog_xmin_epoch = xmin_epoch;
|
2011-02-18 12:31:49 +01:00
|
|
|
if (nextXid < xmin)
|
2017-05-17 22:31:56 +02:00
|
|
|
xmin_epoch--;
|
2017-03-25 15:07:27 +01:00
|
|
|
if (nextXid < catalog_xmin)
|
2017-05-17 22:31:56 +02:00
|
|
|
catalog_xmin_epoch--;
|
2011-02-18 12:31:49 +01:00
|
|
|
|
2017-03-25 15:07:27 +01:00
|
|
|
elog(DEBUG2, "sending hot standby feedback xmin %u epoch %u catalog_xmin %u catalog_xmin_epoch %u",
|
|
|
|
xmin, xmin_epoch, catalog_xmin, catalog_xmin_epoch);
|
2012-11-07 17:59:12 +01:00
|
|
|
|
2013-12-13 18:58:48 +01:00
|
|
|
/* Construct the message and send it. */
|
2012-11-07 17:59:12 +01:00
|
|
|
resetStringInfo(&reply_message);
|
|
|
|
pq_sendbyte(&reply_message, 'h');
|
2017-02-23 21:57:08 +01:00
|
|
|
pq_sendint64(&reply_message, GetCurrentTimestamp());
|
2017-10-12 06:00:46 +02:00
|
|
|
pq_sendint32(&reply_message, xmin);
|
|
|
|
pq_sendint32(&reply_message, xmin_epoch);
|
|
|
|
pq_sendint32(&reply_message, catalog_xmin);
|
|
|
|
pq_sendint32(&reply_message, catalog_xmin_epoch);
|
2016-11-30 18:00:00 +01:00
|
|
|
walrcv_send(wrconn, reply_message.data, reply_message.len);
|
2017-03-25 15:07:27 +01:00
|
|
|
if (TransactionIdIsValid(xmin) || TransactionIdIsValid(catalog_xmin))
|
2020-06-14 23:05:18 +02:00
|
|
|
primary_has_standby_xmin = true;
|
2013-02-04 11:29:22 +01:00
|
|
|
else
|
2020-06-14 23:05:18 +02:00
|
|
|
primary_has_standby_xmin = false;
|
2011-02-18 12:31:49 +01:00
|
|
|
}
|
2011-12-31 14:30:26 +01:00
|
|
|
|
|
|
|
/*
|
2012-11-07 17:59:12 +01:00
|
|
|
* Update shared memory status upon receiving a message from primary.
|
|
|
|
*
|
|
|
|
* 'walEnd' and 'sendTime' are the end-of-WAL and timestamp of the latest
|
|
|
|
* message, reported by primary.
|
2011-12-31 14:30:26 +01:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime)
|
|
|
|
{
|
2015-10-06 21:45:02 +02:00
|
|
|
WalRcvData *walrcv = WalRcv;
|
2011-12-31 14:30:26 +01:00
|
|
|
|
|
|
|
TimestampTz lastMsgReceiptTime = GetCurrentTimestamp();
|
|
|
|
|
|
|
|
/* Update shared-memory status */
|
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
2012-12-28 17:06:15 +01:00
|
|
|
if (walrcv->latestWalEnd < walEnd)
|
2012-08-09 18:03:59 +02:00
|
|
|
walrcv->latestWalEndTime = sendTime;
|
|
|
|
walrcv->latestWalEnd = walEnd;
|
2011-12-31 14:30:26 +01:00
|
|
|
walrcv->lastMsgSendTime = sendTime;
|
|
|
|
walrcv->lastMsgReceiptTime = lastMsgReceiptTime;
|
|
|
|
SpinLockRelease(&walrcv->mutex);
|
|
|
|
|
2012-01-13 14:21:45 +01:00
|
|
|
if (log_min_messages <= DEBUG2)
|
2014-04-04 17:43:34 +02:00
|
|
|
{
|
|
|
|
char *sendtime;
|
|
|
|
char *receipttime;
|
2015-03-14 00:16:50 +01:00
|
|
|
int applyDelay;
|
2014-04-04 17:43:34 +02:00
|
|
|
|
|
|
|
/* Copy because timestamptz_to_str returns a static buffer */
|
|
|
|
sendtime = pstrdup(timestamptz_to_str(sendTime));
|
|
|
|
receipttime = pstrdup(timestamptz_to_str(lastMsgReceiptTime));
|
2015-03-14 00:16:50 +01:00
|
|
|
applyDelay = GetReplicationApplyDelay();
|
|
|
|
|
|
|
|
/* apply delay is not available */
|
|
|
|
if (applyDelay == -1)
|
|
|
|
elog(DEBUG2, "sendtime %s receipttime %s replication apply delay (N/A) transfer latency %d ms",
|
|
|
|
sendtime,
|
|
|
|
receipttime,
|
|
|
|
GetReplicationTransferLatency());
|
|
|
|
else
|
|
|
|
elog(DEBUG2, "sendtime %s receipttime %s replication apply delay %d ms transfer latency %d ms",
|
|
|
|
sendtime,
|
|
|
|
receipttime,
|
|
|
|
applyDelay,
|
|
|
|
GetReplicationTransferLatency());
|
|
|
|
|
2014-04-04 17:43:34 +02:00
|
|
|
pfree(sendtime);
|
|
|
|
pfree(receipttime);
|
|
|
|
}
|
2011-12-31 14:30:26 +01:00
|
|
|
}
|
2016-01-07 20:21:19 +01:00
|
|
|
|
2016-03-30 03:16:12 +02:00
|
|
|
/*
|
|
|
|
* Wake up the walreceiver main loop.
|
|
|
|
*
|
|
|
|
* This is called by the startup process whenever interesting xlog records
|
|
|
|
* are applied, so that walreceiver can check if it needs to send an apply
|
2020-06-14 23:05:18 +02:00
|
|
|
* notification back to the primary which may be waiting in a COMMIT with
|
2016-03-30 03:16:12 +02:00
|
|
|
* synchronous_commit = remote_apply.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
WalRcvForceReply(void)
|
|
|
|
{
|
2017-10-03 20:00:56 +02:00
|
|
|
Latch *latch;
|
|
|
|
|
2016-03-30 03:16:12 +02:00
|
|
|
WalRcv->force_reply = true;
|
2017-10-03 20:00:56 +02:00
|
|
|
/* fetching the latch pointer might not be atomic, so use spinlock */
|
|
|
|
SpinLockAcquire(&WalRcv->mutex);
|
|
|
|
latch = WalRcv->latch;
|
|
|
|
SpinLockRelease(&WalRcv->mutex);
|
|
|
|
if (latch)
|
|
|
|
SetLatch(latch);
|
2016-03-30 03:16:12 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:21:19 +01:00
|
|
|
/*
|
|
|
|
* Return a string constant representing the state. This is used
|
|
|
|
* in system functions and views, and should *not* be translated.
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
WalRcvGetStateString(WalRcvState state)
|
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case WALRCV_STOPPED:
|
|
|
|
return "stopped";
|
|
|
|
case WALRCV_STARTING:
|
|
|
|
return "starting";
|
|
|
|
case WALRCV_STREAMING:
|
|
|
|
return "streaming";
|
|
|
|
case WALRCV_WAITING:
|
|
|
|
return "waiting";
|
|
|
|
case WALRCV_RESTARTING:
|
|
|
|
return "restarting";
|
|
|
|
case WALRCV_STOPPING:
|
|
|
|
return "stopping";
|
|
|
|
}
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns activity of WAL receiver, including pid, state and xlog locations
|
|
|
|
* received from the WAL sender of another server.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TupleDesc tupdesc;
|
2016-06-29 22:57:17 +02:00
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
Fix locking in WAL receiver/sender shmem state structs
In WAL receiver and WAL server, some accesses to their corresponding
shared memory control structs were done without holding any kind of
lock, which could lead to inconsistent and possibly insecure results.
In walsender, fix by clarifying the locking rules and following them
correctly, as documented in the new comment in walsender_private.h;
namely that some members can be read in walsender itself without a lock,
because the only writes occur in the same process. The rest of the
struct requires spinlock for accesses, as usual.
In walreceiver, fix by always holding spinlock while accessing the
struct.
While there is potentially a problem in all branches, it is minor in
stable ones. This only became a real problem in pg10 because of quorum
commit in synchronous replication (commit 3901fd70cc7c), and a potential
security problem in walreceiver because a superuser() check was removed
by default monitoring roles (commit 25fff40798fc). Thus, no backpatch.
In passing, clean up some leftover braces which were used to create
unconditional blocks. Once upon a time these were used for
volatile-izing accesses to those shmem structs, which is no longer
required. Many other occurrences of this pattern remain.
Author: Michaël Paquier
Reported-by: Michaël Paquier
Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro,
Robert Haas
Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
2017-07-01 00:06:33 +02:00
|
|
|
int pid;
|
|
|
|
bool ready_to_display;
|
2016-01-07 20:21:19 +01:00
|
|
|
WalRcvState state;
|
|
|
|
XLogRecPtr receive_start_lsn;
|
|
|
|
TimeLineID receive_start_tli;
|
2020-05-17 02:22:07 +02:00
|
|
|
XLogRecPtr written_lsn;
|
|
|
|
XLogRecPtr flushed_lsn;
|
2016-01-07 20:21:19 +01:00
|
|
|
TimeLineID received_tli;
|
2016-06-10 00:02:36 +02:00
|
|
|
TimestampTz last_send_time;
|
|
|
|
TimestampTz last_receipt_time;
|
2016-01-07 20:21:19 +01:00
|
|
|
XLogRecPtr latest_end_lsn;
|
2016-06-10 00:02:36 +02:00
|
|
|
TimestampTz latest_end_time;
|
2018-03-31 00:51:22 +02:00
|
|
|
char sender_host[NI_MAXHOST];
|
|
|
|
int sender_port = 0;
|
2017-10-03 14:58:25 +02:00
|
|
|
char slotname[NAMEDATALEN];
|
|
|
|
char conninfo[MAXCONNINFO];
|
2016-01-07 20:21:19 +01:00
|
|
|
|
Fix locking in WAL receiver/sender shmem state structs
In WAL receiver and WAL server, some accesses to their corresponding
shared memory control structs were done without holding any kind of
lock, which could lead to inconsistent and possibly insecure results.
In walsender, fix by clarifying the locking rules and following them
correctly, as documented in the new comment in walsender_private.h;
namely that some members can be read in walsender itself without a lock,
because the only writes occur in the same process. The rest of the
struct requires spinlock for accesses, as usual.
In walreceiver, fix by always holding spinlock while accessing the
struct.
While there is potentially a problem in all branches, it is minor in
stable ones. This only became a real problem in pg10 because of quorum
commit in synchronous replication (commit 3901fd70cc7c), and a potential
security problem in walreceiver because a superuser() check was removed
by default monitoring roles (commit 25fff40798fc). Thus, no backpatch.
In passing, clean up some leftover braces which were used to create
unconditional blocks. Once upon a time these were used for
volatile-izing accesses to those shmem structs, which is no longer
required. Many other occurrences of this pattern remain.
Author: Michaël Paquier
Reported-by: Michaël Paquier
Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro,
Robert Haas
Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
2017-07-01 00:06:33 +02:00
|
|
|
/* Take a lock to ensure value consistency */
|
|
|
|
SpinLockAcquire(&WalRcv->mutex);
|
|
|
|
pid = (int) WalRcv->pid;
|
|
|
|
ready_to_display = WalRcv->ready_to_display;
|
|
|
|
state = WalRcv->walRcvState;
|
|
|
|
receive_start_lsn = WalRcv->receiveStart;
|
|
|
|
receive_start_tli = WalRcv->receiveStartTLI;
|
2020-05-17 02:22:07 +02:00
|
|
|
written_lsn = pg_atomic_read_u64(&WalRcv->writtenUpto);
|
|
|
|
flushed_lsn = WalRcv->flushedUpto;
|
Fix locking in WAL receiver/sender shmem state structs
In WAL receiver and WAL server, some accesses to their corresponding
shared memory control structs were done without holding any kind of
lock, which could lead to inconsistent and possibly insecure results.
In walsender, fix by clarifying the locking rules and following them
correctly, as documented in the new comment in walsender_private.h;
namely that some members can be read in walsender itself without a lock,
because the only writes occur in the same process. The rest of the
struct requires spinlock for accesses, as usual.
In walreceiver, fix by always holding spinlock while accessing the
struct.
While there is potentially a problem in all branches, it is minor in
stable ones. This only became a real problem in pg10 because of quorum
commit in synchronous replication (commit 3901fd70cc7c), and a potential
security problem in walreceiver because a superuser() check was removed
by default monitoring roles (commit 25fff40798fc). Thus, no backpatch.
In passing, clean up some leftover braces which were used to create
unconditional blocks. Once upon a time these were used for
volatile-izing accesses to those shmem structs, which is no longer
required. Many other occurrences of this pattern remain.
Author: Michaël Paquier
Reported-by: Michaël Paquier
Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro,
Robert Haas
Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
2017-07-01 00:06:33 +02:00
|
|
|
received_tli = WalRcv->receivedTLI;
|
|
|
|
last_send_time = WalRcv->lastMsgSendTime;
|
|
|
|
last_receipt_time = WalRcv->lastMsgReceiptTime;
|
|
|
|
latest_end_lsn = WalRcv->latestWalEnd;
|
|
|
|
latest_end_time = WalRcv->latestWalEndTime;
|
2017-10-03 14:58:25 +02:00
|
|
|
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
|
2018-03-31 00:51:22 +02:00
|
|
|
strlcpy(sender_host, (char *) WalRcv->sender_host, sizeof(sender_host));
|
|
|
|
sender_port = WalRcv->sender_port;
|
2017-10-03 14:58:25 +02:00
|
|
|
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
|
Fix locking in WAL receiver/sender shmem state structs
In WAL receiver and WAL server, some accesses to their corresponding
shared memory control structs were done without holding any kind of
lock, which could lead to inconsistent and possibly insecure results.
In walsender, fix by clarifying the locking rules and following them
correctly, as documented in the new comment in walsender_private.h;
namely that some members can be read in walsender itself without a lock,
because the only writes occur in the same process. The rest of the
struct requires spinlock for accesses, as usual.
In walreceiver, fix by always holding spinlock while accessing the
struct.
While there is potentially a problem in all branches, it is minor in
stable ones. This only became a real problem in pg10 because of quorum
commit in synchronous replication (commit 3901fd70cc7c), and a potential
security problem in walreceiver because a superuser() check was removed
by default monitoring roles (commit 25fff40798fc). Thus, no backpatch.
In passing, clean up some leftover braces which were used to create
unconditional blocks. Once upon a time these were used for
volatile-izing accesses to those shmem structs, which is no longer
required. Many other occurrences of this pattern remain.
Author: Michaël Paquier
Reported-by: Michaël Paquier
Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro,
Robert Haas
Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
2017-07-01 00:06:33 +02:00
|
|
|
SpinLockRelease(&WalRcv->mutex);
|
|
|
|
|
2016-06-29 22:57:17 +02:00
|
|
|
/*
|
2016-07-01 19:53:46 +02:00
|
|
|
* No WAL receiver (or not ready yet), just return a tuple with NULL
|
|
|
|
* values
|
2016-06-29 22:57:17 +02:00
|
|
|
*/
|
Fix locking in WAL receiver/sender shmem state structs
In WAL receiver and WAL server, some accesses to their corresponding
shared memory control structs were done without holding any kind of
lock, which could lead to inconsistent and possibly insecure results.
In walsender, fix by clarifying the locking rules and following them
correctly, as documented in the new comment in walsender_private.h;
namely that some members can be read in walsender itself without a lock,
because the only writes occur in the same process. The rest of the
struct requires spinlock for accesses, as usual.
In walreceiver, fix by always holding spinlock while accessing the
struct.
While there is potentially a problem in all branches, it is minor in
stable ones. This only became a real problem in pg10 because of quorum
commit in synchronous replication (commit 3901fd70cc7c), and a potential
security problem in walreceiver because a superuser() check was removed
by default monitoring roles (commit 25fff40798fc). Thus, no backpatch.
In passing, clean up some leftover braces which were used to create
unconditional blocks. Once upon a time these were used for
volatile-izing accesses to those shmem structs, which is no longer
required. Many other occurrences of this pattern remain.
Author: Michaël Paquier
Reported-by: Michaël Paquier
Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro,
Robert Haas
Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
2017-07-01 00:06:33 +02:00
|
|
|
if (pid == 0 || !ready_to_display)
|
2016-07-01 19:53:46 +02:00
|
|
|
PG_RETURN_NULL();
|
2016-06-29 22:57:17 +02:00
|
|
|
|
|
|
|
/* determine result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
values = palloc0(sizeof(Datum) * tupdesc->natts);
|
|
|
|
nulls = palloc0(sizeof(bool) * tupdesc->natts);
|
2016-01-07 20:21:19 +01:00
|
|
|
|
|
|
|
/* Fetch values */
|
Fix locking in WAL receiver/sender shmem state structs
In WAL receiver and WAL server, some accesses to their corresponding
shared memory control structs were done without holding any kind of
lock, which could lead to inconsistent and possibly insecure results.
In walsender, fix by clarifying the locking rules and following them
correctly, as documented in the new comment in walsender_private.h;
namely that some members can be read in walsender itself without a lock,
because the only writes occur in the same process. The rest of the
struct requires spinlock for accesses, as usual.
In walreceiver, fix by always holding spinlock while accessing the
struct.
While there is potentially a problem in all branches, it is minor in
stable ones. This only became a real problem in pg10 because of quorum
commit in synchronous replication (commit 3901fd70cc7c), and a potential
security problem in walreceiver because a superuser() check was removed
by default monitoring roles (commit 25fff40798fc). Thus, no backpatch.
In passing, clean up some leftover braces which were used to create
unconditional blocks. Once upon a time these were used for
volatile-izing accesses to those shmem structs, which is no longer
required. Many other occurrences of this pattern remain.
Author: Michaël Paquier
Reported-by: Michaël Paquier
Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro,
Robert Haas
Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
2017-07-01 00:06:33 +02:00
|
|
|
values[0] = Int32GetDatum(pid);
|
2016-01-07 20:21:19 +01:00
|
|
|
|
2017-03-30 20:18:53 +02:00
|
|
|
if (!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
|
2016-01-07 20:21:19 +01:00
|
|
|
{
|
|
|
|
/*
|
2018-01-06 12:48:21 +01:00
|
|
|
* Only superusers and members of pg_read_all_stats can see details.
|
2018-04-26 20:47:16 +02:00
|
|
|
* Other users only get the pid value to know whether it is a WAL
|
|
|
|
* receiver, but no details.
|
2016-01-07 20:21:19 +01:00
|
|
|
*/
|
2016-06-29 22:57:17 +02:00
|
|
|
MemSet(&nulls[1], true, sizeof(bool) * (tupdesc->natts - 1));
|
2016-01-07 20:21:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
values[1] = CStringGetTextDatum(WalRcvGetStateString(state));
|
|
|
|
|
|
|
|
if (XLogRecPtrIsInvalid(receive_start_lsn))
|
|
|
|
nulls[2] = true;
|
|
|
|
else
|
|
|
|
values[2] = LSNGetDatum(receive_start_lsn);
|
|
|
|
values[3] = Int32GetDatum(receive_start_tli);
|
2020-05-17 02:22:07 +02:00
|
|
|
if (XLogRecPtrIsInvalid(written_lsn))
|
2016-01-07 20:21:19 +01:00
|
|
|
nulls[4] = true;
|
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[4] = LSNGetDatum(written_lsn);
|
|
|
|
if (XLogRecPtrIsInvalid(flushed_lsn))
|
|
|
|
nulls[5] = true;
|
|
|
|
else
|
|
|
|
values[5] = LSNGetDatum(flushed_lsn);
|
|
|
|
values[6] = Int32GetDatum(received_tli);
|
2016-01-07 20:21:19 +01:00
|
|
|
if (last_send_time == 0)
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[7] = true;
|
2016-01-07 20:21:19 +01:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[7] = TimestampTzGetDatum(last_send_time);
|
2016-01-07 20:21:19 +01:00
|
|
|
if (last_receipt_time == 0)
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[8] = true;
|
2016-01-07 20:21:19 +01:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[8] = TimestampTzGetDatum(last_receipt_time);
|
2016-01-07 20:21:19 +01:00
|
|
|
if (XLogRecPtrIsInvalid(latest_end_lsn))
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[9] = true;
|
2016-01-07 20:21:19 +01:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[9] = LSNGetDatum(latest_end_lsn);
|
2016-01-07 20:21:19 +01:00
|
|
|
if (latest_end_time == 0)
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[10] = true;
|
2016-01-07 20:21:19 +01:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[10] = TimestampTzGetDatum(latest_end_time);
|
2016-01-07 20:21:19 +01:00
|
|
|
if (*slotname == '\0')
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[11] = true;
|
2016-01-07 20:21:19 +01:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[11] = CStringGetTextDatum(slotname);
|
2018-03-31 00:51:22 +02:00
|
|
|
if (*sender_host == '\0')
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[12] = true;
|
2016-06-29 22:57:17 +02:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[12] = CStringGetTextDatum(sender_host);
|
2018-03-31 00:51:22 +02:00
|
|
|
if (sender_port == 0)
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[13] = true;
|
2018-03-31 00:51:22 +02:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[13] = Int32GetDatum(sender_port);
|
2018-03-31 00:51:22 +02:00
|
|
|
if (*conninfo == '\0')
|
2020-05-17 02:22:07 +02:00
|
|
|
nulls[14] = true;
|
2018-03-31 00:51:22 +02:00
|
|
|
else
|
2020-05-17 02:22:07 +02:00
|
|
|
values[14] = CStringGetTextDatum(conninfo);
|
2016-01-07 20:21:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the record as Datum */
|
Fix locking in WAL receiver/sender shmem state structs
In WAL receiver and WAL server, some accesses to their corresponding
shared memory control structs were done without holding any kind of
lock, which could lead to inconsistent and possibly insecure results.
In walsender, fix by clarifying the locking rules and following them
correctly, as documented in the new comment in walsender_private.h;
namely that some members can be read in walsender itself without a lock,
because the only writes occur in the same process. The rest of the
struct requires spinlock for accesses, as usual.
In walreceiver, fix by always holding spinlock while accessing the
struct.
While there is potentially a problem in all branches, it is minor in
stable ones. This only became a real problem in pg10 because of quorum
commit in synchronous replication (commit 3901fd70cc7c), and a potential
security problem in walreceiver because a superuser() check was removed
by default monitoring roles (commit 25fff40798fc). Thus, no backpatch.
In passing, clean up some leftover braces which were used to create
unconditional blocks. Once upon a time these were used for
volatile-izing accesses to those shmem structs, which is no longer
required. Many other occurrences of this pattern remain.
Author: Michaël Paquier
Reported-by: Michaël Paquier
Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro,
Robert Haas
Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
2017-07-01 00:06:33 +02:00
|
|
|
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
|
2016-01-07 20:21:19 +01:00
|
|
|
}
|