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
|
2011-02-11 17:55:12 +01:00
|
|
|
* WalRcv->receivedUpto 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.
|
|
|
|
*
|
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
|
|
|
|
* disconnection, and will rescan the archive/pg_xlog directory. But when the
|
|
|
|
* 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
|
|
|
*
|
2015-01-06 17:43:47 +01:00
|
|
|
* Portions Copyright (c) 2010-2015, 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"
|
|
|
|
|
2010-01-20 10:16:24 +01:00
|
|
|
#include <signal.h>
|
2010-01-15 10:19:10 +01:00
|
|
|
#include <unistd.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"
|
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"
|
|
|
|
#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"
|
2011-09-04 07:13:16 +02:00
|
|
|
#include "utils/guc.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
|
|
|
|
Fix management of pendingOpsTable in auxiliary processes.
mdinit() was misusing IsBootstrapProcessingMode() to decide whether to
create an fsync pending-operations table in the current process. This led
to creating a table not only in the startup and checkpointer processes as
intended, but also in the bgwriter process, not to mention other auxiliary
processes such as walwriter and walreceiver. Creation of the table in the
bgwriter is fatal, because it absorbs fsync requests that should have gone
to the checkpointer; instead they just sit in bgwriter local memory and are
never acted on. So writes performed by the bgwriter were not being fsync'd
which could result in data loss after an OS crash. I think there is no
live bug with respect to walwriter and walreceiver because those never
perform any writes of shared buffers; but the potential is there for
future breakage in those processes too.
To fix, make AuxiliaryProcessMain() export the current process's
AuxProcType as a global variable, and then make mdinit() test directly for
the types of aux process that should have a pendingOpsTable. Having done
that, we might as well also get rid of the random bool flags such as
am_walreceiver that some of the aux processes had grown. (Note that we
could not have fixed the bug by examining those variables in mdinit(),
because it's called from BaseInit() which is run by AuxiliaryProcessMain()
before entering any of the process-type-specific code.)
Back-patch to 9.2, where the problem was introduced by the split-up of
bgwriter and checkpointer processes. The bogus pendingOpsTable exists
in walwriter and walreceiver processes in earlier branches, but absent
any evidence that it causes actual problems there, I'll leave the older
branches alone.
2012-07-18 21:28:10 +02:00
|
|
|
/* GUC variables */
|
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
|
|
|
|
2010-01-20 10:16:24 +01:00
|
|
|
/* libpqreceiver hooks to these when loaded */
|
|
|
|
walrcv_connect_type walrcv_connect = 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
|
|
|
walrcv_identify_system_type walrcv_identify_system = NULL;
|
|
|
|
walrcv_startstreaming_type walrcv_startstreaming = NULL;
|
|
|
|
walrcv_endstreaming_type walrcv_endstreaming = NULL;
|
|
|
|
walrcv_readtimelinehistoryfile_type walrcv_readtimelinehistoryfile = NULL;
|
2010-01-20 10:16:24 +01:00
|
|
|
walrcv_receive_type walrcv_receive = NULL;
|
2010-12-11 15:27:37 +01:00
|
|
|
walrcv_send_type walrcv_send = NULL;
|
2010-01-20 10:16:24 +01:00
|
|
|
walrcv_disconnect_type walrcv_disconnect = NULL;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
#define NAPTIME_PER_CYCLE 100 /* max sleep time between cycles (100ms) */
|
|
|
|
|
|
|
|
/*
|
2012-06-27 16:53:53 +02:00
|
|
|
* These variables are used similarly to openLogFile/SegNo/Off,
|
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
|
|
|
static uint32 recvOff = 0;
|
|
|
|
|
2010-01-20 10:16:24 +01:00
|
|
|
/*
|
|
|
|
* Flags set by interrupt handlers of walreceiver for later service in the
|
|
|
|
* main loop.
|
|
|
|
*/
|
2010-01-15 10:19:10 +01:00
|
|
|
static volatile sig_atomic_t got_SIGHUP = false;
|
|
|
|
static volatile sig_atomic_t got_SIGTERM = false;
|
|
|
|
|
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 */
|
|
|
|
} 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-01-15 10:19:10 +01:00
|
|
|
/*
|
|
|
|
* About SIGTERM handling:
|
|
|
|
*
|
|
|
|
* We can't just exit(1) within SIGTERM signal handler, because the signal
|
|
|
|
* might arrive in the middle of some critical operation, like while we're
|
|
|
|
* holding a spinlock. We also can't just set a flag in signal handler and
|
2010-04-19 16:10:45 +02:00
|
|
|
* check it in the main loop, because we perform some blocking operations
|
|
|
|
* like libpqrcv_PQexec(), which can take a long time to finish.
|
2010-01-15 10:19:10 +01:00
|
|
|
*
|
|
|
|
* We use a combined approach: When WalRcvImmediateInterruptOK is true, it's
|
|
|
|
* safe for the signal handler to elog(FATAL) immediately. Otherwise it just
|
|
|
|
* sets got_SIGTERM flag, which is checked in the main loop when convenient.
|
|
|
|
*
|
|
|
|
* This is very much like what regular backends do with ImmediateInterruptOK,
|
|
|
|
* ProcessInterrupts() etc.
|
|
|
|
*/
|
|
|
|
static volatile bool WalRcvImmediateInterruptOK = false;
|
|
|
|
|
2010-04-21 00:55:03 +02:00
|
|
|
/* Prototypes for private functions */
|
|
|
|
static void ProcessWalRcvInterrupts(void);
|
|
|
|
static void EnableWalRcvImmediateExit(void);
|
|
|
|
static void DisableWalRcvImmediateExit(void);
|
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
|
|
|
|
|
|
|
/* Signal handlers */
|
|
|
|
static void WalRcvSigHupHandler(SIGNAL_ARGS);
|
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 WalRcvSigUsr1Handler(SIGNAL_ARGS);
|
2010-04-21 00:55:03 +02:00
|
|
|
static void WalRcvShutdownHandler(SIGNAL_ARGS);
|
|
|
|
static void WalRcvQuickDieHandler(SIGNAL_ARGS);
|
|
|
|
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
static void
|
|
|
|
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
|
|
|
|
* any incoming signals on Win32.
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
|
|
|
|
if (got_SIGTERM)
|
|
|
|
{
|
|
|
|
WalRcvImmediateInterruptOK = false;
|
|
|
|
ereport(FATAL,
|
|
|
|
(errcode(ERRCODE_ADMIN_SHUTDOWN),
|
|
|
|
errmsg("terminating walreceiver process due to administrator command")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-04-21 00:55:03 +02:00
|
|
|
EnableWalRcvImmediateExit(void)
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
|
|
|
WalRcvImmediateInterruptOK = true;
|
|
|
|
ProcessWalRcvInterrupts();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-04-21 00:55:03 +02:00
|
|
|
DisableWalRcvImmediateExit(void)
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
|
|
|
WalRcvImmediateInterruptOK = false;
|
|
|
|
ProcessWalRcvInterrupts();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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];
|
2014-02-01 04:45:17 +01:00
|
|
|
char slotname[NAMEDATALEN];
|
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;
|
|
|
|
|
2010-01-20 10:16:24 +01:00
|
|
|
/* use volatile pointer to prevent code rearrangement */
|
|
|
|
volatile WalRcvData *walrcv = WalRcv;
|
2012-10-11 16:39:52 +02:00
|
|
|
TimestampTz last_recv_timestamp;
|
|
|
|
bool ping_sent;
|
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);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
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 */
|
|
|
|
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 */
|
|
|
|
strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
|
2014-02-01 04:45:17 +01:00
|
|
|
strlcpy(slotname, (char *) walrcv->slotname, NAMEDATALEN);
|
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
|
|
|
|
|
|
|
/* Initialise to a sanish value */
|
2012-08-09 18:03:59 +02:00
|
|
|
walrcv->lastMsgSendTime = walrcv->lastMsgReceiptTime = walrcv->latestWalEndTime = GetCurrentTimestamp();
|
2011-12-31 14:30:26 +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
|
|
|
SpinLockRelease(&walrcv->mutex);
|
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
|
|
|
/* Arrange to clean up at walreceiver exit */
|
|
|
|
on_shmem_exit(WalRcvDie, 0);
|
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
|
|
|
OwnLatch(&walrcv->latch);
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/* Properly accept or ignore signals the postmaster might send us */
|
2010-02-26 03:01:40 +01:00
|
|
|
pqsignal(SIGHUP, WalRcvSigHupHandler); /* set flag to read config
|
|
|
|
* file */
|
2010-01-15 10:19:10 +01:00
|
|
|
pqsignal(SIGINT, SIG_IGN);
|
|
|
|
pqsignal(SIGTERM, WalRcvShutdownHandler); /* request shutdown */
|
|
|
|
pqsignal(SIGQUIT, WalRcvQuickDieHandler); /* hard crash time */
|
|
|
|
pqsignal(SIGALRM, SIG_IGN);
|
|
|
|
pqsignal(SIGPIPE, SIG_IGN);
|
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
|
|
|
pqsignal(SIGUSR1, WalRcvSigUsr1Handler);
|
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);
|
|
|
|
pqsignal(SIGTTIN, SIG_DFL);
|
|
|
|
pqsignal(SIGTTOU, SIG_DFL);
|
|
|
|
pqsignal(SIGCONT, SIG_DFL);
|
|
|
|
pqsignal(SIGWINCH, SIG_DFL);
|
|
|
|
|
|
|
|
/* We allow SIGQUIT (quickdie) at all times */
|
|
|
|
sigdelset(&BlockSig, SIGQUIT);
|
|
|
|
|
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);
|
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 (walrcv_connect == NULL || walrcv_startstreaming == NULL ||
|
|
|
|
walrcv_endstreaming == NULL ||
|
|
|
|
walrcv_identify_system == NULL ||
|
|
|
|
walrcv_readtimelinehistoryfile == NULL ||
|
|
|
|
walrcv_receive == NULL || walrcv_send == NULL ||
|
|
|
|
walrcv_disconnect == 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
|
|
|
/*
|
|
|
|
* Create a resource owner to keep track of our resources (not clear that
|
|
|
|
* we need this, but may as well have one).
|
|
|
|
*/
|
|
|
|
CurrentResourceOwner = ResourceOwnerCreate(NULL, "Wal Receiver");
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
EnableWalRcvImmediateExit();
|
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_connect(conninfo);
|
2010-01-20 10:16:24 +01:00
|
|
|
DisableWalRcvImmediateExit();
|
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
|
|
|
first_stream = true;
|
2010-01-15 10:19:10 +01:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/*
|
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
|
|
|
|
* IDENTIFY_SYSTEM replication command,
|
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
|
|
|
EnableWalRcvImmediateExit();
|
|
|
|
walrcv_identify_system(&primaryTLI);
|
|
|
|
DisableWalRcvImmediateExit();
|
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
|
|
|
|
* become the master later on, we don't select the same timeline that
|
|
|
|
* was already used in the current master. This isn't bullet-proof -
|
|
|
|
* 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
|
|
|
|
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
|
|
|
|
* 'latest', the startup process will scan pg_xlog and find the new
|
|
|
|
* history file, bump recovery target timeline, and ask us to restart
|
|
|
|
* on the new timeline.
|
|
|
|
*/
|
|
|
|
ThisTimeLineID = startpointTLI;
|
2014-02-01 04:45:17 +01:00
|
|
|
if (walrcv_startstreaming(startpointTLI, startpoint,
|
|
|
|
slotname[0] != '\0' ? slotname : NULL))
|
2010-01-15 10:19:10 +01:00
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
bool endofwal = 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
|
|
|
|
|
|
|
if (first_stream)
|
|
|
|
ereport(LOG,
|
|
|
|
(errmsg("started streaming WAL from primary at %X/%X on timeline %u",
|
2013-05-29 22:58:43 +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,
|
2013-05-29 22:58:43 +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 */
|
|
|
|
while (!endofwal)
|
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;
|
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
|
|
|
/*
|
|
|
|
* Emergency bailout if postmaster has died. This is to avoid
|
2013-05-29 22:58:43 +02:00
|
|
|
* the necessity for manual cleanup of all postmaster
|
|
|
|
* children.
|
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 (!PostmasterIsAlive())
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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();
|
|
|
|
|
|
|
|
if (got_SIGHUP)
|
|
|
|
{
|
|
|
|
got_SIGHUP = false;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait a while for data to arrive */
|
|
|
|
len = walrcv_receive(NAPTIME_PER_CYCLE, &buf);
|
|
|
|
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
|
|
|
/*
|
|
|
|
* Something was received from master, so reset
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
len = walrcv_receive(0, &buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let the master know that we received some data. */
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* the master anyway, to report any progress in applying
|
|
|
|
* 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,
|
2013-05-29 22:58:43 +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
|
|
|
*/
|
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
|
|
|
EnableWalRcvImmediateExit();
|
2013-01-18 10:48:29 +01:00
|
|
|
walrcv_endstreaming(&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
|
|
|
DisableWalRcvImmediateExit();
|
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);
|
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",
|
|
|
|
XLogFileNameP(recvFileTLI, recvSegNo))));
|
2012-08-09 00:58:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create .done file forcibly to prevent the streamed segment from
|
|
|
|
* being archived later.
|
|
|
|
*/
|
|
|
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
|
|
|
XLogArchiveForceDone(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)
|
|
|
|
{
|
|
|
|
/* use volatile pointer to prevent code rearrangement */
|
|
|
|
volatile WalRcvData *walrcv = WalRcv;
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (update_process_title)
|
|
|
|
set_ps_display("idle", false);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nudge startup process to notice that we've stopped streaming and are
|
|
|
|
* now waiting for instructions.
|
|
|
|
*/
|
|
|
|
WakeupRecovery();
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
ResetLatch(&walrcv->latch);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Emergency bailout if postmaster has died. This is to avoid the
|
|
|
|
* necessity for manual cleanup of all postmaster children.
|
|
|
|
*/
|
|
|
|
if (!PostmasterIsAlive())
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
ProcessWalRcvInterrupts();
|
|
|
|
|
|
|
|
SpinLockAcquire(&walrcv->mutex);
|
|
|
|
Assert(walrcv->walRcvState == WALRCV_RESTARTING ||
|
|
|
|
walrcv->walRcvState == WALRCV_WAITING ||
|
|
|
|
walrcv->walRcvState == WALRCV_STOPPING);
|
|
|
|
if (walrcv->walRcvState == WALRCV_RESTARTING)
|
|
|
|
{
|
|
|
|
/* we don't expect primary_conninfo to change */
|
|
|
|
*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
|
|
|
|
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
|
|
|
WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
set_ps_display(activitymsg, false);
|
|
|
|
}
|
|
|
|
}
|
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)));
|
|
|
|
|
|
|
|
EnableWalRcvImmediateExit();
|
|
|
|
walrcv_readtimelinehistoryfile(tli, &fname, &content, &len);
|
|
|
|
DisableWalRcvImmediateExit();
|
|
|
|
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Check that the filename on the master matches what we
|
|
|
|
* 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)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the file to pg_xlog.
|
|
|
|
*/
|
|
|
|
writeTimeLineHistoryFile(tli, content, len);
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
/* use volatile pointer to prevent code rearrangement */
|
|
|
|
volatile WalRcvData *walrcv = WalRcv;
|
|
|
|
|
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
|
|
|
|
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
|
|
|
DisownLatch(&walrcv->latch);
|
|
|
|
|
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;
|
|
|
|
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. */
|
2010-04-13 10:16:09 +02:00
|
|
|
if (walrcv_disconnect != NULL)
|
|
|
|
walrcv_disconnect();
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/* SIGHUP: set flag to re-read config file at next convenient time */
|
|
|
|
static void
|
|
|
|
WalRcvSigHupHandler(SIGNAL_ARGS)
|
|
|
|
{
|
|
|
|
got_SIGHUP = 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
|
|
|
|
|
|
|
/* SIGUSR1: used by latch mechanism */
|
|
|
|
static void
|
|
|
|
WalRcvSigUsr1Handler(SIGNAL_ARGS)
|
|
|
|
{
|
2014-02-01 22:20:56 +01:00
|
|
|
int save_errno = errno;
|
|
|
|
|
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
|
|
|
latch_sigusr1_handler();
|
2014-02-01 22:20:56 +01:00
|
|
|
|
|
|
|
errno = save_errno;
|
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
|
|
|
}
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/* SIGTERM: set flag for main loop, or shutdown immediately if safe */
|
|
|
|
static void
|
|
|
|
WalRcvShutdownHandler(SIGNAL_ARGS)
|
|
|
|
{
|
2011-08-10 18:20:30 +02:00
|
|
|
int save_errno = errno;
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
got_SIGTERM = 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
|
|
|
SetLatch(&WalRcv->latch);
|
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
/* Don't joggle the elbow of proc_exit */
|
|
|
|
if (!proc_exit_inprogress && WalRcvImmediateInterruptOK)
|
|
|
|
ProcessWalRcvInterrupts();
|
2011-08-10 18:20:30 +02:00
|
|
|
|
|
|
|
errno = save_errno;
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* WalRcvQuickDieHandler() occurs when signalled SIGQUIT by the postmaster.
|
|
|
|
*
|
|
|
|
* Some backend has bought the farm, so we need to stop what we're doing and
|
|
|
|
* exit.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
WalRcvQuickDieHandler(SIGNAL_ARGS)
|
|
|
|
{
|
|
|
|
PG_SETMASK(&BlockSig);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We DO NOT want to run proc_exit() callbacks -- we're here because
|
|
|
|
* shared memory may be corrupted, so we don't want to try to clean up our
|
|
|
|
* transaction. Just nail the windows shut and get out of town. Now that
|
|
|
|
* there's an atexit callback to prevent third-party code from breaking
|
|
|
|
* things by calling exit() directly, we have to reset the callbacks
|
|
|
|
* explicitly to make this work as intended.
|
|
|
|
*/
|
|
|
|
on_exit_reset();
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Note we do exit(2) not exit(0). This is to force the postmaster into a
|
2010-01-15 10:19:10 +01:00
|
|
|
* system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
|
|
|
|
* backend. This is necessary precisely because we don't clean up our
|
|
|
|
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
|
2010-02-26 03:01:40 +01:00
|
|
|
* should ensure the postmaster sees this as a crash, too, but no harm in
|
|
|
|
* being doubly sure.)
|
2010-01-15 10:19:10 +01:00
|
|
|
*/
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
sendTime = IntegerTimestampToTimestampTz(
|
2013-05-29 22:58:43 +02:00
|
|
|
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);
|
|
|
|
sendTime = IntegerTimestampToTimestampTz(
|
2013-05-29 22:58:43 +02:00
|
|
|
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
|
|
|
|
2012-06-24 17:06:38 +02:00
|
|
|
if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo))
|
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
|
|
|
|
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",
|
|
|
|
XLogFileNameP(recvFileTLI, recvSegNo))));
|
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
|
|
|
*/
|
|
|
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
|
|
|
XLogArchiveForceDone(xlogfname);
|
2010-01-15 10:19:10 +01:00
|
|
|
}
|
|
|
|
recvFile = -1;
|
|
|
|
|
|
|
|
/* Create/use new log file */
|
2012-06-24 17:06:38 +02:00
|
|
|
XLByteToSeg(recptr, recvSegNo);
|
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
|
|
|
recvOff = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the start offset of the received logs */
|
2012-06-24 17:51:37 +02:00
|
|
|
startoff = recptr % XLogSegSize;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
if (startoff + nbytes > XLogSegSize)
|
|
|
|
segbytes = XLogSegSize - startoff;
|
|
|
|
else
|
|
|
|
segbytes = nbytes;
|
|
|
|
|
|
|
|
/* Need to seek in the file? */
|
|
|
|
if (recvOff != startoff)
|
|
|
|
{
|
|
|
|
if (lseek(recvFile, (off_t) startoff, SEEK_SET) < 0)
|
|
|
|
ereport(PANIC,
|
|
|
|
(errcode_for_file_access(),
|
2014-05-06 18:12:18 +02:00
|
|
|
errmsg("could not seek in log segment %s to offset %u: %m",
|
|
|
|
XLogFileNameP(recvFileTLI, recvSegNo),
|
|
|
|
startoff)));
|
2010-01-15 10:19:10 +01:00
|
|
|
recvOff = startoff;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OK to write the logs */
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
byteswritten = write(recvFile, buf, segbytes);
|
|
|
|
if (byteswritten <= 0)
|
|
|
|
{
|
|
|
|
/* if write didn't set errno, assume no disk space */
|
|
|
|
if (errno == 0)
|
|
|
|
errno = ENOSPC;
|
|
|
|
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",
|
2012-06-24 17:06:38 +02:00
|
|
|
XLogFileNameP(recvFileTLI, recvSegNo),
|
2010-01-15 10:19:10 +01:00
|
|
|
recvOff, (unsigned long) segbytes)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update state for write */
|
2012-12-28 17:06:15 +01:00
|
|
|
recptr += byteswritten;
|
2010-01-15 10:19:10 +01:00
|
|
|
|
|
|
|
recvOff += byteswritten;
|
|
|
|
nbytes -= byteswritten;
|
|
|
|
buf += byteswritten;
|
|
|
|
|
2010-02-26 03:01:40 +01:00
|
|
|
LogstreamResult.Write = recptr;
|
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
|
|
|
{
|
|
|
|
/* use volatile pointer to prevent code rearrangement */
|
|
|
|
volatile WalRcvData *walrcv = WalRcv;
|
|
|
|
|
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);
|
2012-12-28 17:06:15 +01:00
|
|
|
if (walrcv->receivedUpto < LogstreamResult.Flush)
|
2011-03-01 19:46:57 +01:00
|
|
|
{
|
|
|
|
walrcv->latestChunkStart = walrcv->receivedUpto;
|
|
|
|
walrcv->receivedUpto = 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);
|
2010-06-07 17:49:30 +02:00
|
|
|
set_ps_display(activitymsg, false);
|
|
|
|
}
|
2011-02-10 20:00:29 +01:00
|
|
|
|
|
|
|
/* Also let the master 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
|
|
|
|
|
|
|
/*
|
2012-10-11 16:39:52 +02:00
|
|
|
* Send reply message to primary, indicating our current XLOG positions, oldest
|
|
|
|
* 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
|
|
|
|
* receiving this message. This is used for heartbearts, when approaching
|
|
|
|
* 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
|
|
|
|
|
|
|
/*
|
|
|
|
* If the user doesn't want status to be reported to the master, be sure
|
|
|
|
* 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
|
|
|
|
* seconds have passed. This means that the apply log position will
|
|
|
|
* appear, from the master's point of view, to lag slightly, but since
|
|
|
|
* 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);
|
|
|
|
pq_sendint64(&reply_message, GetCurrentIntegerTimestamp());
|
|
|
|
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)" : "");
|
|
|
|
|
|
|
|
walrcv_send(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
|
|
|
|
* to forget about the xmin on this standby.
|
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;
|
|
|
|
TransactionId nextXid;
|
|
|
|
uint32 nextEpoch;
|
|
|
|
TransactionId xmin;
|
2012-11-07 17:59:12 +01:00
|
|
|
static TimestampTz sendTime = 0;
|
2013-02-04 11:29:22 +01:00
|
|
|
static bool master_has_standby_xmin = false;
|
2011-02-18 12:31:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the user doesn't want status to be reported to the master, be sure
|
|
|
|
* to exit before doing anything at all.
|
|
|
|
*/
|
2013-02-04 11:29:22 +01:00
|
|
|
if ((wal_receiver_status_interval <= 0 || !hot_standby_feedback) &&
|
|
|
|
!master_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
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
* If Hot Standby is not yet active there is nothing to send. Check this
|
|
|
|
* after the interval has expired to reduce number of calls.
|
2011-02-18 12:31:49 +01:00
|
|
|
*/
|
|
|
|
if (!HotStandbyActive())
|
2013-02-04 11:29:22 +01:00
|
|
|
{
|
|
|
|
Assert(!master_has_standby_xmin);
|
2011-02-18 12:31:49 +01:00
|
|
|
return;
|
2013-02-04 11:29:22 +01:00
|
|
|
}
|
2011-02-18 12:31:49 +01:00
|
|
|
|
|
|
|
/*
|
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)
|
Introduce logical decoding.
This feature, building on previous commits, allows the write-ahead log
stream to be decoded into a series of logical changes; that is,
inserts, updates, and deletes and the transactions which contain them.
It is capable of handling decoding even across changes to the schema
of the effected tables. The output format is controlled by a
so-called "output plugin"; an example is included. To make use of
this in a real replication system, the output plugin will need to be
modified to produce output in the format appropriate to that system,
and to perform filtering.
Currently, information can be extracted from the logical decoding
system only via SQL; future commits will add the ability to stream
changes via walsender.
Andres Freund, with review and other contributions from many other
people, including Álvaro Herrera, Abhijit Menon-Sen, Peter Gheogegan,
Kevin Grittner, Robert Haas, Heikki Linnakangas, Fujii Masao, Abhijit
Menon-Sen, Michael Paquier, Simon Riggs, Craig Ringer, and Steve
Singer.
2014-03-03 22:32:18 +01:00
|
|
|
xmin = GetOldestXmin(NULL, false);
|
2013-02-04 11:29:22 +01:00
|
|
|
else
|
|
|
|
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
|
|
|
*/
|
|
|
|
GetNextXidAndEpoch(&nextXid, &nextEpoch);
|
|
|
|
if (nextXid < xmin)
|
|
|
|
nextEpoch--;
|
|
|
|
|
|
|
|
elog(DEBUG2, "sending hot standby feedback xmin %u epoch %u",
|
2012-11-07 17:59:12 +01:00
|
|
|
xmin, nextEpoch);
|
|
|
|
|
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');
|
|
|
|
pq_sendint64(&reply_message, GetCurrentIntegerTimestamp());
|
|
|
|
pq_sendint(&reply_message, xmin, 4);
|
|
|
|
pq_sendint(&reply_message, nextEpoch, 4);
|
|
|
|
walrcv_send(reply_message.data, reply_message.len);
|
2013-02-04 11:29:22 +01:00
|
|
|
if (TransactionIdIsValid(xmin))
|
|
|
|
master_has_standby_xmin = true;
|
|
|
|
else
|
|
|
|
master_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)
|
|
|
|
{
|
|
|
|
/* use volatile pointer to prevent code rearrangement */
|
|
|
|
volatile WalRcvData *walrcv = WalRcv;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* Copy because timestamptz_to_str returns a static buffer */
|
|
|
|
sendtime = pstrdup(timestamptz_to_str(sendTime));
|
|
|
|
receipttime = pstrdup(timestamptz_to_str(lastMsgReceiptTime));
|
2012-01-13 13:59:08 +01:00
|
|
|
elog(DEBUG2, "sendtime %s receipttime %s replication apply delay %d ms transfer latency %d ms",
|
2014-04-04 17:43:34 +02:00
|
|
|
sendtime,
|
|
|
|
receipttime,
|
2012-06-10 21:20:04 +02:00
|
|
|
GetReplicationApplyDelay(),
|
|
|
|
GetReplicationTransferLatency());
|
2014-04-04 17:43:34 +02:00
|
|
|
pfree(sendtime);
|
|
|
|
pfree(receipttime);
|
|
|
|
}
|
2011-12-31 14:30:26 +01:00
|
|
|
}
|