mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
Add archive_mode='always' option.
In 'always' mode, the standby independently archives all files it receives from the primary. Original patch by Fujii Masao, docs and review by me.
This commit is contained in:
@ -2521,7 +2521,7 @@ include_dir 'conf.d'
|
|||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry id="guc-archive-mode" xreflabel="archive_mode">
|
<varlistentry id="guc-archive-mode" xreflabel="archive_mode">
|
||||||
<term><varname>archive_mode</varname> (<type>boolean</type>)
|
<term><varname>archive_mode</varname> (<type>enum</type>)
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary><varname>archive_mode</> configuration parameter</primary>
|
<primary><varname>archive_mode</> configuration parameter</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
@ -2530,7 +2530,16 @@ include_dir 'conf.d'
|
|||||||
<para>
|
<para>
|
||||||
When <varname>archive_mode</> is enabled, completed WAL segments
|
When <varname>archive_mode</> is enabled, completed WAL segments
|
||||||
are sent to archive storage by setting
|
are sent to archive storage by setting
|
||||||
<xref linkend="guc-archive-command">.
|
<xref linkend="guc-archive-command">. In addition to <literal>off</>,
|
||||||
|
to disable, there are two modes: <literal>on</>, and
|
||||||
|
<literal>always</>. During normal operation, there is no
|
||||||
|
difference between the two modes, but when set to <literal>always</>
|
||||||
|
the WAL archiver is enabled also during archive recovery or standby
|
||||||
|
mode. In <literal>always</> mode, all files restored from the archive
|
||||||
|
or streamed with streaming replication will be archived (again). See
|
||||||
|
<xref linkend="continuous-archiving-in-standby"> for details.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
<varname>archive_mode</> and <varname>archive_command</> are
|
<varname>archive_mode</> and <varname>archive_command</> are
|
||||||
separate variables so that <varname>archive_command</> can be
|
separate variables so that <varname>archive_command</> can be
|
||||||
changed without leaving archiving mode.
|
changed without leaving archiving mode.
|
||||||
|
@ -1220,6 +1220,45 @@ primary_slot_name = 'node_a_slot'
|
|||||||
|
|
||||||
</sect3>
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="continuous-archiving-in-standby">
|
||||||
|
<title>Continuous archiving in standby</title>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary>continuous archiving</primary>
|
||||||
|
<secondary>in standby</secondary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When continuous WAL archiving is used in a standby, there are two
|
||||||
|
different scenarios: the WAL archive can be shared between the primary
|
||||||
|
and the standby, or the standby can have its own WAL archive. When
|
||||||
|
the standby has its own WAL archive, set <varname>archive_mode</varname>
|
||||||
|
to <literal>always</literal>, and the standby will call the archive
|
||||||
|
command for every WAL segment it receives, whether it's by restoring
|
||||||
|
from the archive or by streaming replication. The shared archive can
|
||||||
|
be handled similarly, but the archive_command must test if the file
|
||||||
|
being archived exists already, and if the existing file has identical
|
||||||
|
contents. This requires more care in the archive_command, as it must
|
||||||
|
be careful to not overwrite an existing file with different contents,
|
||||||
|
but return success if the exactly same file is archived twice. And
|
||||||
|
all that must be done free of race conditions, if two servers attempt
|
||||||
|
to archive the same file at the same time.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
If <varname>archive_mode</varname> is set to <literal>on</>, the
|
||||||
|
archiver is not enabled during recovery or standby mode. If the standby
|
||||||
|
server is promoted, it will start archiving after the promotion, but
|
||||||
|
will not archive any WAL it did not generate itself. To get a complete
|
||||||
|
series of WAL files in the archive, you must ensure that all WAL is
|
||||||
|
archived, before it reaches the standby. This is inherently true with
|
||||||
|
file-based log shipping, as the standby can only restore files that
|
||||||
|
are found in the archive, but not if streaming replication is enabled.
|
||||||
|
When a server is not in recovery mode, there is no difference between
|
||||||
|
<literal>on</literal> and <literal>always</literal> modes.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="warm-standby-failover">
|
<sect1 id="warm-standby-failover">
|
||||||
|
@ -86,7 +86,7 @@ int min_wal_size = 5; /* 80 MB */
|
|||||||
int wal_keep_segments = 0;
|
int wal_keep_segments = 0;
|
||||||
int XLOGbuffers = -1;
|
int XLOGbuffers = -1;
|
||||||
int XLogArchiveTimeout = 0;
|
int XLogArchiveTimeout = 0;
|
||||||
bool XLogArchiveMode = false;
|
int XLogArchiveMode = ARCHIVE_MODE_OFF;
|
||||||
char *XLogArchiveCommand = NULL;
|
char *XLogArchiveCommand = NULL;
|
||||||
bool EnableHotStandby = false;
|
bool EnableHotStandby = false;
|
||||||
bool fullPageWrites = true;
|
bool fullPageWrites = true;
|
||||||
@ -140,6 +140,24 @@ const struct config_enum_entry sync_method_options[] = {
|
|||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Although only "on", "off", and "always" are documented,
|
||||||
|
* we accept all the likely variants of "on" and "off".
|
||||||
|
*/
|
||||||
|
const struct config_enum_entry archive_mode_options[] = {
|
||||||
|
{"always", ARCHIVE_MODE_ALWAYS, false},
|
||||||
|
{"on", ARCHIVE_MODE_ON, false},
|
||||||
|
{"off", ARCHIVE_MODE_OFF, false},
|
||||||
|
{"true", ARCHIVE_MODE_ON, true},
|
||||||
|
{"false", ARCHIVE_MODE_OFF, true},
|
||||||
|
{"yes", ARCHIVE_MODE_ON, true},
|
||||||
|
{"no", ARCHIVE_MODE_OFF, true},
|
||||||
|
{"1", ARCHIVE_MODE_ON, true},
|
||||||
|
{"0", ARCHIVE_MODE_OFF, true},
|
||||||
|
{NULL, 0, false}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Statistics for current checkpoint are collected in this global struct.
|
* Statistics for current checkpoint are collected in this global struct.
|
||||||
* Because only the checkpointer or a stand-alone backend can perform
|
* Because only the checkpointer or a stand-alone backend can perform
|
||||||
@ -767,7 +785,7 @@ static MemoryContext walDebugCxt = NULL;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void readRecoveryCommandFile(void);
|
static void readRecoveryCommandFile(void);
|
||||||
static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
|
static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog);
|
||||||
static bool recoveryStopsBefore(XLogReaderState *record);
|
static bool recoveryStopsBefore(XLogReaderState *record);
|
||||||
static bool recoveryStopsAfter(XLogReaderState *record);
|
static bool recoveryStopsAfter(XLogReaderState *record);
|
||||||
static void recoveryPausesHere(void);
|
static void recoveryPausesHere(void);
|
||||||
|
@ -480,7 +480,10 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname)
|
|||||||
* Create .done file forcibly to prevent the restored segment from being
|
* Create .done file forcibly to prevent the restored segment from being
|
||||||
* archived again later.
|
* archived again later.
|
||||||
*/
|
*/
|
||||||
XLogArchiveForceDone(xlogfname);
|
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
|
||||||
|
XLogArchiveForceDone(xlogfname);
|
||||||
|
else
|
||||||
|
XLogArchiveNotify(xlogfname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the existing file was replaced, since walsenders might have it open,
|
* If the existing file was replaced, since walsenders might have it open,
|
||||||
|
@ -828,9 +828,9 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
write_stderr("%s: max_wal_senders must be less than max_connections\n", progname);
|
write_stderr("%s: max_wal_senders must be less than max_connections\n", progname);
|
||||||
ExitPostmaster(1);
|
ExitPostmaster(1);
|
||||||
}
|
}
|
||||||
if (XLogArchiveMode && wal_level == WAL_LEVEL_MINIMAL)
|
if (XLogArchiveMode > ARCHIVE_MODE_OFF && wal_level == WAL_LEVEL_MINIMAL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("WAL archival (archive_mode=on) requires wal_level \"archive\", \"hot_standby\", or \"logical\"")));
|
(errmsg("WAL archival cannot be enabled when wal_level is \"minimal\"")));
|
||||||
if (max_wal_senders > 0 && wal_level == WAL_LEVEL_MINIMAL)
|
if (max_wal_senders > 0 && wal_level == WAL_LEVEL_MINIMAL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("WAL streaming (max_wal_senders > 0) requires wal_level \"archive\", \"hot_standby\", or \"logical\"")));
|
(errmsg("WAL streaming (max_wal_senders > 0) requires wal_level \"archive\", \"hot_standby\", or \"logical\"")));
|
||||||
@ -1645,13 +1645,21 @@ ServerLoop(void)
|
|||||||
start_autovac_launcher = false; /* signal processed */
|
start_autovac_launcher = false; /* signal processed */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have lost the archiver, try to start a new one */
|
/*
|
||||||
if (XLogArchivingActive() && PgArchPID == 0 && pmState == PM_RUN)
|
* If we have lost the archiver, try to start a new one.
|
||||||
PgArchPID = pgarch_start();
|
*
|
||||||
|
* If WAL archiving is enabled always, we try to start a new archiver
|
||||||
/* If we have lost the stats collector, try to start a new one */
|
* even during recovery.
|
||||||
if (PgStatPID == 0 && pmState == PM_RUN)
|
*/
|
||||||
PgStatPID = pgstat_start();
|
if (PgArchPID == 0 && wal_level >= WAL_LEVEL_ARCHIVE)
|
||||||
|
{
|
||||||
|
if ((pmState == PM_RUN && XLogArchiveMode > ARCHIVE_MODE_OFF) ||
|
||||||
|
((pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY) &&
|
||||||
|
XLogArchiveMode == ARCHIVE_MODE_ALWAYS))
|
||||||
|
{
|
||||||
|
PgArchPID = pgarch_start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we need to signal the autovacuum launcher, do so now */
|
/* If we need to signal the autovacuum launcher, do so now */
|
||||||
if (avlauncher_needs_signal)
|
if (avlauncher_needs_signal)
|
||||||
@ -4807,6 +4815,17 @@ sigusr1_handler(SIGNAL_ARGS)
|
|||||||
Assert(BgWriterPID == 0);
|
Assert(BgWriterPID == 0);
|
||||||
BgWriterPID = StartBackgroundWriter();
|
BgWriterPID = StartBackgroundWriter();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the archiver if we're responsible for (re-)archiving received
|
||||||
|
* files.
|
||||||
|
*/
|
||||||
|
Assert(PgArchPID == 0);
|
||||||
|
if (wal_level >= WAL_LEVEL_ARCHIVE &&
|
||||||
|
XLogArchiveMode == ARCHIVE_MODE_ALWAYS)
|
||||||
|
{
|
||||||
|
PgArchPID = pgarch_start();
|
||||||
|
}
|
||||||
|
|
||||||
pmState = PM_RECOVERY;
|
pmState = PM_RECOVERY;
|
||||||
}
|
}
|
||||||
if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
|
if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
|
||||||
|
@ -540,7 +540,10 @@ WalReceiverMain(void)
|
|||||||
* being archived later.
|
* being archived later.
|
||||||
*/
|
*/
|
||||||
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
||||||
XLogArchiveForceDone(xlogfname);
|
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
|
||||||
|
XLogArchiveForceDone(xlogfname);
|
||||||
|
else
|
||||||
|
XLogArchiveNotify(xlogfname);
|
||||||
}
|
}
|
||||||
recvFile = -1;
|
recvFile = -1;
|
||||||
|
|
||||||
@ -897,7 +900,10 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
|
|||||||
* from being archived later.
|
* from being archived later.
|
||||||
*/
|
*/
|
||||||
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
||||||
XLogArchiveForceDone(xlogfname);
|
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
|
||||||
|
XLogArchiveForceDone(xlogfname);
|
||||||
|
else
|
||||||
|
XLogArchiveNotify(xlogfname);
|
||||||
}
|
}
|
||||||
recvFile = -1;
|
recvFile = -1;
|
||||||
|
|
||||||
|
@ -396,6 +396,7 @@ static const struct config_enum_entry row_security_options[] = {
|
|||||||
* Options for enum values stored in other modules
|
* Options for enum values stored in other modules
|
||||||
*/
|
*/
|
||||||
extern const struct config_enum_entry wal_level_options[];
|
extern const struct config_enum_entry wal_level_options[];
|
||||||
|
extern const struct config_enum_entry archive_mode_options[];
|
||||||
extern const struct config_enum_entry sync_method_options[];
|
extern const struct config_enum_entry sync_method_options[];
|
||||||
extern const struct config_enum_entry dynamic_shared_memory_options[];
|
extern const struct config_enum_entry dynamic_shared_memory_options[];
|
||||||
|
|
||||||
@ -1529,16 +1530,6 @@ static struct config_bool ConfigureNamesBool[] =
|
|||||||
NULL, NULL, NULL
|
NULL, NULL, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
{"archive_mode", PGC_POSTMASTER, WAL_ARCHIVING,
|
|
||||||
gettext_noop("Allows archiving of WAL files using archive_command."),
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
&XLogArchiveMode,
|
|
||||||
false,
|
|
||||||
NULL, NULL, NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
|
{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
|
||||||
gettext_noop("Allows connections and queries during recovery."),
|
gettext_noop("Allows connections and queries during recovery."),
|
||||||
@ -3551,6 +3542,16 @@ static struct config_enum ConfigureNamesEnum[] =
|
|||||||
NULL, assign_synchronous_commit, NULL
|
NULL, assign_synchronous_commit, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
{"archive_mode", PGC_POSTMASTER, WAL_ARCHIVING,
|
||||||
|
gettext_noop("Allows archiving of WAL files using archive_command."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&XLogArchiveMode,
|
||||||
|
ARCHIVE_MODE_OFF, archive_mode_options,
|
||||||
|
NULL, NULL, NULL
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{"trace_recovery_messages", PGC_SIGHUP, DEVELOPER_OPTIONS,
|
{"trace_recovery_messages", PGC_SIGHUP, DEVELOPER_OPTIONS,
|
||||||
gettext_noop("Enables logging of recovery-related debugging information."),
|
gettext_noop("Enables logging of recovery-related debugging information."),
|
||||||
|
@ -206,7 +206,7 @@
|
|||||||
|
|
||||||
# - Archiving -
|
# - Archiving -
|
||||||
|
|
||||||
#archive_mode = off # allows archiving to be done
|
#archive_mode = off # enables archiving; off, on, or always
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
#archive_command = '' # command to use to archive a logfile segment
|
#archive_command = '' # command to use to archive a logfile segment
|
||||||
# placeholders: %p = path of file to archive
|
# placeholders: %p = path of file to archive
|
||||||
|
@ -98,7 +98,6 @@ extern int wal_keep_segments;
|
|||||||
extern int XLOGbuffers;
|
extern int XLOGbuffers;
|
||||||
extern int XLogArchiveTimeout;
|
extern int XLogArchiveTimeout;
|
||||||
extern int wal_retrieve_retry_interval;
|
extern int wal_retrieve_retry_interval;
|
||||||
extern bool XLogArchiveMode;
|
|
||||||
extern char *XLogArchiveCommand;
|
extern char *XLogArchiveCommand;
|
||||||
extern bool EnableHotStandby;
|
extern bool EnableHotStandby;
|
||||||
extern bool fullPageWrites;
|
extern bool fullPageWrites;
|
||||||
@ -108,6 +107,15 @@ extern bool log_checkpoints;
|
|||||||
|
|
||||||
extern int CheckPointSegments;
|
extern int CheckPointSegments;
|
||||||
|
|
||||||
|
/* Archive modes */
|
||||||
|
typedef enum ArchiveMode
|
||||||
|
{
|
||||||
|
ARCHIVE_MODE_OFF = 0, /* disabled */
|
||||||
|
ARCHIVE_MODE_ON, /* enabled while server is running normally */
|
||||||
|
ARCHIVE_MODE_ALWAYS /* enabled always (even during recovery) */
|
||||||
|
} ArchiveMode;
|
||||||
|
extern int XLogArchiveMode;
|
||||||
|
|
||||||
/* WAL levels */
|
/* WAL levels */
|
||||||
typedef enum WalLevel
|
typedef enum WalLevel
|
||||||
{
|
{
|
||||||
@ -118,7 +126,8 @@ typedef enum WalLevel
|
|||||||
} WalLevel;
|
} WalLevel;
|
||||||
extern int wal_level;
|
extern int wal_level;
|
||||||
|
|
||||||
#define XLogArchivingActive() (XLogArchiveMode && wal_level >= WAL_LEVEL_ARCHIVE)
|
#define XLogArchivingActive() \
|
||||||
|
(XLogArchiveMode > ARCHIVE_MODE_OFF && wal_level >= WAL_LEVEL_ARCHIVE)
|
||||||
#define XLogArchiveCommandSet() (XLogArchiveCommand[0] != '\0')
|
#define XLogArchiveCommandSet() (XLogArchiveCommand[0] != '\0')
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user