<variablelist>
<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>
<primary><varname>archive_mode</> configuration parameter</primary>
</indexterm>
<para>
When <varname>archive_mode</> is enabled, completed WAL segments
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
separate variables so that <varname>archive_command</> can be
changed without leaving archiving mode.
</sect3>
</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 id="warm-standby-failover">
int wal_keep_segments = 0;
int XLOGbuffers = -1;
int XLogArchiveTimeout = 0;
-bool XLogArchiveMode = false;
+int XLogArchiveMode = ARCHIVE_MODE_OFF;
char *XLogArchiveCommand = NULL;
bool EnableHotStandby = false;
bool fullPageWrites = true;
{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.
* Because only the checkpointer or a stand-alone backend can perform
#endif
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 recoveryStopsAfter(XLogReaderState *record);
static void recoveryPausesHere(void);
* Create .done file forcibly to prevent the restored segment from being
* 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,
write_stderr("%s: max_wal_senders must be less than max_connections\n", progname);
ExitPostmaster(1);
}
- if (XLogArchiveMode && wal_level == WAL_LEVEL_MINIMAL)
+ if (XLogArchiveMode > ARCHIVE_MODE_OFF && wal_level == WAL_LEVEL_MINIMAL)
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)
ereport(ERROR,
(errmsg("WAL streaming (max_wal_senders > 0) requires wal_level \"archive\", \"hot_standby\", or \"logical\"")));
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)
- PgArchPID = pgarch_start();
-
- /* If we have lost the stats collector, try to start a new one */
- if (PgStatPID == 0 && pmState == PM_RUN)
- PgStatPID = pgstat_start();
+ /*
+ * If we have lost the archiver, try to start a new one.
+ *
+ * If WAL archiving is enabled always, we try to start a new archiver
+ * even during recovery.
+ */
+ 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 (avlauncher_needs_signal)
Assert(BgWriterPID == 0);
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;
}
if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
* being archived later.
*/
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
- XLogArchiveForceDone(xlogfname);
+ if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
+ XLogArchiveForceDone(xlogfname);
+ else
+ XLogArchiveNotify(xlogfname);
}
recvFile = -1;
* from being archived later.
*/
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
- XLogArchiveForceDone(xlogfname);
+ if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
+ XLogArchiveForceDone(xlogfname);
+ else
+ XLogArchiveNotify(xlogfname);
}
recvFile = -1;
* Options for enum values stored in other modules
*/
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 dynamic_shared_memory_options[];
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,
gettext_noop("Allows connections and queries during recovery."),
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,
gettext_noop("Enables logging of recovery-related debugging information."),
# - Archiving -
-#archive_mode = off # allows archiving to be done
+#archive_mode = off # enables archiving; off, on, or always
# (change requires restart)
#archive_command = '' # command to use to archive a logfile segment
# placeholders: %p = path of file to archive
extern int XLOGbuffers;
extern int XLogArchiveTimeout;
extern int wal_retrieve_retry_interval;
-extern bool XLogArchiveMode;
extern char *XLogArchiveCommand;
extern bool EnableHotStandby;
extern bool fullPageWrites;
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 */
typedef enum WalLevel
{
} WalLevel;
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')
/*