Move the code to archive files via the shell to a separate file.
This is preparatory work for allowing more extensibility in this area. Nathan Bossart Discussion: http://postgr.es/m/668D2428-F73B-475E-87AE-F89D67942270@amazon.com
This commit is contained in:
parent
7f6772317b
commit
aeb4cc9ea0
|
@ -23,6 +23,7 @@ OBJS = \
|
||||||
pgarch.o \
|
pgarch.o \
|
||||||
pgstat.o \
|
pgstat.o \
|
||||||
postmaster.o \
|
postmaster.o \
|
||||||
|
shell_archive.o \
|
||||||
startup.o \
|
startup.o \
|
||||||
syslogger.o \
|
syslogger.o \
|
||||||
walwriter.o
|
walwriter.o
|
||||||
|
|
|
@ -25,19 +25,14 @@
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "access/xlog.h"
|
#include "access/xlog.h"
|
||||||
#include "access/xlog_internal.h"
|
#include "access/xlog_internal.h"
|
||||||
#include "lib/binaryheap.h"
|
#include "lib/binaryheap.h"
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "postmaster/pgarch.h"
|
#include "postmaster/pgarch.h"
|
||||||
|
@ -504,132 +499,24 @@ pgarch_ArchiverCopyLoop(void)
|
||||||
static bool
|
static bool
|
||||||
pgarch_archiveXlog(char *xlog)
|
pgarch_archiveXlog(char *xlog)
|
||||||
{
|
{
|
||||||
char xlogarchcmd[MAXPGPATH];
|
|
||||||
char pathname[MAXPGPATH];
|
char pathname[MAXPGPATH];
|
||||||
char activitymsg[MAXFNAMELEN + 16];
|
char activitymsg[MAXFNAMELEN + 16];
|
||||||
char *dp;
|
bool ret;
|
||||||
char *endp;
|
|
||||||
const char *sp;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
|
snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
|
||||||
|
|
||||||
/*
|
|
||||||
* construct the command to be executed
|
|
||||||
*/
|
|
||||||
dp = xlogarchcmd;
|
|
||||||
endp = xlogarchcmd + MAXPGPATH - 1;
|
|
||||||
*endp = '\0';
|
|
||||||
|
|
||||||
for (sp = XLogArchiveCommand; *sp; sp++)
|
|
||||||
{
|
|
||||||
if (*sp == '%')
|
|
||||||
{
|
|
||||||
switch (sp[1])
|
|
||||||
{
|
|
||||||
case 'p':
|
|
||||||
/* %p: relative path of source file */
|
|
||||||
sp++;
|
|
||||||
strlcpy(dp, pathname, endp - dp);
|
|
||||||
make_native_path(dp);
|
|
||||||
dp += strlen(dp);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
/* %f: filename of source file */
|
|
||||||
sp++;
|
|
||||||
strlcpy(dp, xlog, endp - dp);
|
|
||||||
dp += strlen(dp);
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
/* convert %% to a single % */
|
|
||||||
sp++;
|
|
||||||
if (dp < endp)
|
|
||||||
*dp++ = *sp;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* otherwise treat the % as not special */
|
|
||||||
if (dp < endp)
|
|
||||||
*dp++ = *sp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (dp < endp)
|
|
||||||
*dp++ = *sp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*dp = '\0';
|
|
||||||
|
|
||||||
ereport(DEBUG3,
|
|
||||||
(errmsg_internal("executing archive command \"%s\"",
|
|
||||||
xlogarchcmd)));
|
|
||||||
|
|
||||||
/* Report archive activity in PS display */
|
/* Report archive activity in PS display */
|
||||||
snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog);
|
snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog);
|
||||||
set_ps_display(activitymsg);
|
set_ps_display(activitymsg);
|
||||||
|
|
||||||
pgstat_report_wait_start(WAIT_EVENT_ARCHIVE_COMMAND);
|
ret = shell_archive_file(xlog, pathname);
|
||||||
rc = system(xlogarchcmd);
|
if (ret)
|
||||||
pgstat_report_wait_end();
|
snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog);
|
||||||
|
|
||||||
if (rc != 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If either the shell itself, or a called command, died on a signal,
|
|
||||||
* abort the archiver. We do this because system() ignores SIGINT and
|
|
||||||
* SIGQUIT while waiting; so a signal is very likely something that
|
|
||||||
* should have interrupted us too. Also die if the shell got a hard
|
|
||||||
* "command not found" type of error. If we overreact it's no big
|
|
||||||
* deal, the postmaster will just start the archiver again.
|
|
||||||
*/
|
|
||||||
int lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG;
|
|
||||||
|
|
||||||
if (WIFEXITED(rc))
|
|
||||||
{
|
|
||||||
ereport(lev,
|
|
||||||
(errmsg("archive command failed with exit code %d",
|
|
||||||
WEXITSTATUS(rc)),
|
|
||||||
errdetail("The failed archive command was: %s",
|
|
||||||
xlogarchcmd)));
|
|
||||||
}
|
|
||||||
else if (WIFSIGNALED(rc))
|
|
||||||
{
|
|
||||||
#if defined(WIN32)
|
|
||||||
ereport(lev,
|
|
||||||
(errmsg("archive command was terminated by exception 0x%X",
|
|
||||||
WTERMSIG(rc)),
|
|
||||||
errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
|
|
||||||
errdetail("The failed archive command was: %s",
|
|
||||||
xlogarchcmd)));
|
|
||||||
#else
|
|
||||||
ereport(lev,
|
|
||||||
(errmsg("archive command was terminated by signal %d: %s",
|
|
||||||
WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))),
|
|
||||||
errdetail("The failed archive command was: %s",
|
|
||||||
xlogarchcmd)));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
ereport(lev,
|
|
||||||
(errmsg("archive command exited with unrecognized status %d",
|
|
||||||
rc),
|
|
||||||
errdetail("The failed archive command was: %s",
|
|
||||||
xlogarchcmd)));
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(activitymsg, sizeof(activitymsg), "failed on %s", xlog);
|
snprintf(activitymsg, sizeof(activitymsg), "failed on %s", xlog);
|
||||||
set_ps_display(activitymsg);
|
set_ps_display(activitymsg);
|
||||||
|
|
||||||
return false;
|
return ret;
|
||||||
}
|
|
||||||
elog(DEBUG1, "archived write-ahead log file \"%s\"", xlog);
|
|
||||||
|
|
||||||
snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog);
|
|
||||||
set_ps_display(activitymsg);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* shell_archive.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* src/backend/postmaster/shell_archive.c
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "access/xlog.h"
|
||||||
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/pgarch.h"
|
||||||
|
|
||||||
|
bool
|
||||||
|
shell_archive_file(const char *file, const char *path)
|
||||||
|
{
|
||||||
|
char xlogarchcmd[MAXPGPATH];
|
||||||
|
char *dp;
|
||||||
|
char *endp;
|
||||||
|
const char *sp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* construct the command to be executed
|
||||||
|
*/
|
||||||
|
dp = xlogarchcmd;
|
||||||
|
endp = xlogarchcmd + MAXPGPATH - 1;
|
||||||
|
*endp = '\0';
|
||||||
|
|
||||||
|
for (sp = XLogArchiveCommand; *sp; sp++)
|
||||||
|
{
|
||||||
|
if (*sp == '%')
|
||||||
|
{
|
||||||
|
switch (sp[1])
|
||||||
|
{
|
||||||
|
case 'p':
|
||||||
|
/* %p: relative path of source file */
|
||||||
|
sp++;
|
||||||
|
strlcpy(dp, path, endp - dp);
|
||||||
|
make_native_path(dp);
|
||||||
|
dp += strlen(dp);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
/* %f: filename of source file */
|
||||||
|
sp++;
|
||||||
|
strlcpy(dp, file, endp - dp);
|
||||||
|
dp += strlen(dp);
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
/* convert %% to a single % */
|
||||||
|
sp++;
|
||||||
|
if (dp < endp)
|
||||||
|
*dp++ = *sp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* otherwise treat the % as not special */
|
||||||
|
if (dp < endp)
|
||||||
|
*dp++ = *sp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dp < endp)
|
||||||
|
*dp++ = *sp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dp = '\0';
|
||||||
|
|
||||||
|
ereport(DEBUG3,
|
||||||
|
(errmsg_internal("executing archive command \"%s\"",
|
||||||
|
xlogarchcmd)));
|
||||||
|
|
||||||
|
pgstat_report_wait_start(WAIT_EVENT_ARCHIVE_COMMAND);
|
||||||
|
rc = system(xlogarchcmd);
|
||||||
|
pgstat_report_wait_end();
|
||||||
|
|
||||||
|
if (rc != 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If either the shell itself, or a called command, died on a signal,
|
||||||
|
* abort the archiver. We do this because system() ignores SIGINT and
|
||||||
|
* SIGQUIT while waiting; so a signal is very likely something that
|
||||||
|
* should have interrupted us too. Also die if the shell got a hard
|
||||||
|
* "command not found" type of error. If we overreact it's no big
|
||||||
|
* deal, the postmaster will just start the archiver again.
|
||||||
|
*/
|
||||||
|
int lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG;
|
||||||
|
|
||||||
|
if (WIFEXITED(rc))
|
||||||
|
{
|
||||||
|
ereport(lev,
|
||||||
|
(errmsg("archive command failed with exit code %d",
|
||||||
|
WEXITSTATUS(rc)),
|
||||||
|
errdetail("The failed archive command was: %s",
|
||||||
|
xlogarchcmd)));
|
||||||
|
}
|
||||||
|
else if (WIFSIGNALED(rc))
|
||||||
|
{
|
||||||
|
#if defined(WIN32)
|
||||||
|
ereport(lev,
|
||||||
|
(errmsg("archive command was terminated by exception 0x%X",
|
||||||
|
WTERMSIG(rc)),
|
||||||
|
errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
|
||||||
|
errdetail("The failed archive command was: %s",
|
||||||
|
xlogarchcmd)));
|
||||||
|
#else
|
||||||
|
ereport(lev,
|
||||||
|
(errmsg("archive command was terminated by signal %d: %s",
|
||||||
|
WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))),
|
||||||
|
errdetail("The failed archive command was: %s",
|
||||||
|
xlogarchcmd)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ereport(lev,
|
||||||
|
(errmsg("archive command exited with unrecognized status %d",
|
||||||
|
rc),
|
||||||
|
errdetail("The failed archive command was: %s",
|
||||||
|
xlogarchcmd)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
elog(DEBUG1, "archived write-ahead log file \"%s\"", file);
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -33,4 +33,7 @@ extern void PgArchiverMain(void) pg_attribute_noreturn();
|
||||||
extern void PgArchWakeup(void);
|
extern void PgArchWakeup(void);
|
||||||
extern void PgArchForceDirScan(void);
|
extern void PgArchForceDirScan(void);
|
||||||
|
|
||||||
|
/* in shell_archive.c */
|
||||||
|
extern bool shell_archive_file(const char *file, const char *path);
|
||||||
|
|
||||||
#endif /* _PGARCH_H */
|
#endif /* _PGARCH_H */
|
||||||
|
|
Loading…
Reference in New Issue