Ensure cleanup of orphan archive status files
When a WAL segment is recycled, its ".ready" and ".done" status files get also automatically removed, however this is not done in a durable manner. Hence, in a subsequent crash, it could be possible that a ".ready" status file is still around with its corresponding segment already gone. If the backend reaches such a state, the archive command would most likely complain about a segment non-existing and would keep retrying, causing WAL segments to bloat pg_wal/, potentially making Postgres crash hard when running out of space. As status files are removed after each individual segment, using durable_unlink() does not completely close the window either, as a crash could happen between the moment the WAL segment is recycled and the moment its status files are removed. This has also some performance impact with the additional fsync() calls needed to make the removal in a durable manner. Doing the cleanup at recovery is not cost-free either as this makes crash recovery potentially take longer than necessary. So, instead, as per an idea of Stephen Frost, make the archiver aware of orphan status files and remove them on-the-fly if the corresponding segment goes missing. Removal failures follow a model close to what happens for WAL segments, where multiple attempts are done before giving up temporarily, and where a successful orphan removal makes the archiver move immediately to the next WAL segment thought as ready to be archived. Author: Michael Paquier Reviewed-by: Nathan Bossart, Andres Freund, Stephen Frost, Kyotaro Horiguchi Discussion: https://postgr.es/m/20180928032827.GF1500@paquier.xyz
This commit is contained in:
parent
7fee252f6f
commit
6d8727f95e
@ -28,6 +28,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
@ -59,8 +60,18 @@
|
||||
#define PGARCH_RESTART_INTERVAL 10 /* How often to attempt to restart a
|
||||
* failed archiver; in seconds. */
|
||||
|
||||
/*
|
||||
* Maximum number of retries allowed when attempting to archive a WAL
|
||||
* file.
|
||||
*/
|
||||
#define NUM_ARCHIVE_RETRIES 3
|
||||
|
||||
/*
|
||||
* Maximum number of retries allowed when attempting to remove an
|
||||
* orphan archive status file.
|
||||
*/
|
||||
#define NUM_ORPHAN_CLEANUP_RETRIES 3
|
||||
|
||||
|
||||
/* ----------
|
||||
* Local data
|
||||
@ -424,9 +435,13 @@ pgarch_ArchiverCopyLoop(void)
|
||||
while (pgarch_readyXlog(xlog))
|
||||
{
|
||||
int failures = 0;
|
||||
int failures_orphan = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
char pathname[MAXPGPATH];
|
||||
|
||||
/*
|
||||
* Do not initiate any more archive commands after receiving
|
||||
* SIGTERM, nor after the postmaster has died unexpectedly. The
|
||||
@ -456,6 +471,46 @@ pgarch_ArchiverCopyLoop(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since archive status files are not removed in a durable manner,
|
||||
* a system crash could leave behind .ready files for WAL segments
|
||||
* that have already been recycled or removed. In this case,
|
||||
* simply remove the orphan status file and move on. unlink() is
|
||||
* used here as even on subsequent crashes the same orphan files
|
||||
* would get removed, so there is no need to worry about
|
||||
* durability.
|
||||
*/
|
||||
snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
|
||||
if (stat(pathname, &stat_buf) != 0 && errno == ENOENT)
|
||||
{
|
||||
char xlogready[MAXPGPATH];
|
||||
|
||||
StatusFilePath(xlogready, xlog, ".ready");
|
||||
if (unlink(xlogready) == 0)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errmsg("removed orphan archive status file \"%s\"",
|
||||
xlogready)));
|
||||
|
||||
/* leave loop and move to the next status file */
|
||||
break;
|
||||
}
|
||||
|
||||
if (++failures_orphan >= NUM_ORPHAN_CLEANUP_RETRIES)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errmsg("removal of orphan archive status file \"%s\" failed too many times, will try again later",
|
||||
xlogready)));
|
||||
|
||||
/* give up cleanup of orphan status files */
|
||||
return;
|
||||
}
|
||||
|
||||
/* wait a bit before retrying */
|
||||
pg_usleep(1000000L);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pgarch_archiveXlog(xlog))
|
||||
{
|
||||
/* successful */
|
||||
|
Loading…
x
Reference in New Issue
Block a user