4 * To be used as archive_cleanup_command to clean an archive when using
7 * src/bin/pg_archivecleanup/pg_archivecleanup.c
24/* Options and defaults */
25 static bool dryrun =
false;
/* are we performing a dry-run operation? */
34 * to remain in archive */
37/* =====================================================================
39 * Customizable section
41 * =====================================================================
43 * Currently, this section assumes that the Archive is a locally
44 * accessible directory. If you want to make other assumptions,
45 * such as using a vendor-specific archive and access API, these
46 * routines are the ones you'll need to change. You're
47 * encouraged to submit any changes to pgsql-hackers@lists.postgresql.org
48 * or personally to the current maintainer. Those changes may be
49 * folded in to later versions of this program.
53 * Initialize allows customized commands into the archive cleanup program.
55 * You may wish to add code to check for tape libraries, etc..
61 * This code assumes that archiveLocation is a directory, so we use stat
62 * to test if it's accessible.
81 if (extension == NULL)
84 elen = strlen(extension);
87 if (flen > elen && strcmp(
filename + flen - elen, extension) == 0)
101 pg_fatal(
"could not open archive location \"%s\": %m",
104 while (errno = 0, (xlde =
readdir(xldir)) != NULL)
106 char WALFilePath[
MAXPGPATH * 2];
/* the file path including
110 * Truncation is essentially harmless, because we skip files whose
111 * format is different from WAL files and backup history files. (In
112 * principle, one could use a 1000-character additional_ext and get
119 * Ignore anything does that not look like a WAL segment, a .partial
120 * WAL segment or a backup history file (if requested).
127 * We ignore the timeline part of the XLOG segment identifiers in
128 * deciding whether a segment is still needed. This ensures that we
129 * won't prematurely remove a segment from a parent timeline. We could
130 * probably be a little more proactive about removing segments of
131 * non-parent timelines, but that would be a whole lot more
134 * We use the alphanumeric sorting property of the filenames to decide
135 * which ones are earlier than the exclusiveCleanupFileName file. Note
136 * that this means files are not removed in the order they were
137 * originally written, in case this worries you.
143 * Use the original file name again now, including any extension that
144 * might have been chopped off before testing the sequence.
146 snprintf(WALFilePath,
sizeof(WALFilePath),
"%s/%s",
152 * Prints the name of the file to be removed and skips the actual
153 * removal. The regular printout is so that the user can pipe the
154 * output into some other program.
156 printf(
"%s\n", WALFilePath);
157 pg_log_debug(
"file \"%s\" would be removed", WALFilePath);
163 rc = unlink(WALFilePath);
165 pg_fatal(
"could not remove file \"%s\": %m",
170 pg_fatal(
"could not read archive location \"%s\": %m",
173 pg_fatal(
"could not close archive location \"%s\": %m",
178 * SetWALFileNameForCleanup()
180 * Set the earliest WAL filename that we want to keep on the archive
181 * and decide whether we need cleanup
186 bool fnameOK =
false;
191 * If restartWALFileName is a WAL file name then just use it directly. If
192 * restartWALFileName is a .partial or .backup filename, make sure we use
193 * the prefix of the filename, otherwise we will remove wrong files since
194 * 000000010000000000000010.partial and
195 * 000000010000000000000010.00000020.backup are after
196 * 000000010000000000000010.
217 * Use just the prefix of the filename, ignore everything after
237 * Use just the prefix of the filename, ignore everything after
252/* =====================================================================
253 * End of Customizable section
254 * =====================================================================
260 printf(
_(
"%s removes older WAL files from PostgreSQL archives.\n\n"),
progname);
262 printf(
_(
" %s [OPTION]... ARCHIVELOCATION OLDESTKEPTWALFILE\n"),
progname);
264 printf(
_(
" -b, --clean-backup-history clean up files including backup history files\n"));
265 printf(
_(
" -d, --debug generate debug output (verbose mode)\n"));
266 printf(
_(
" -n, --dry-run dry run, show the names of the files that would be\n"
268 printf(
_(
" -V, --version output version information, then exit\n"));
269 printf(
_(
" -x, --strip-extension=EXT strip this extension before identifying files for\n"
271 printf(
_(
" -?, --help show this help, then exit\n"));
273 "For use as \"archive_cleanup_command\" in postgresql.conf:\n"
274 " archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
276 " archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n"));
278 "Or for use as a standalone archive cleaner:\n"
280 " pg_archivecleanup /mnt/server/archiverdir 000000010000000000000010.00000020.backup\n"));
281 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
282 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
285/*------------ MAIN ----------------------------------------*/
289 static struct option long_options[] = {
304 if (strcmp(argv[1],
"--help") == 0 || strcmp(argv[1],
"-?") == 0)
309 if (strcmp(argv[1],
"--version") == 0 || strcmp(argv[1],
"-V") == 0)
311 puts(
"pg_archivecleanup (PostgreSQL) " PG_VERSION);
316 while ((
c =
getopt_long(argc, argv,
"bdnx:", long_options, NULL)) != -1)
320 case 'b':
/* Remove backup history files as well */
323 case 'd':
/* Debug mode */
326 case 'n':
/* Dry-Run mode */
331 * from xlogfile names */
334 /* getopt already emitted a complaint */
341 * We will go to the archiveLocation to check restartWALFileName.
342 * restartWALFileName may not exist anymore, which would not be an error,
343 * so we separate the archiveLocation and restartWALFileName so we can
344 * check separately whether archiveLocation exists, if not that is an
379 * Check archive exists and other initialization if required.
384 * Check filename is a valid name, then process to find cut-off
392 * Remove WAL files older than cut-off
#define PG_TEXTDOMAIN(domain)
void set_pglocale_pgservice(const char *argv0, const char *app)
struct dirent * readdir(DIR *)
DIR * opendir(const char *)
char * pg_strdup(const char *in)
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
void pg_logging_increase_verbosity(void)
void pg_logging_init(const char *argv0)
#define pg_log_error(...)
#define pg_log_error_hint(...)
#define pg_log_debug(...)
static char * restartWALFileName
int main(int argc, char **argv)
static char * archiveLocation
static char * additional_ext
static bool cleanBackupHistory
static char exclusiveCleanupFileName[MAXFNAMELEN]
static void SetWALFileNameForCleanup(void)
static void CleanupPriorWALFiles(void)
static void Initialize(void)
static const char * progname
static void TrimExtension(char *filename, char *extension)
PGDLLIMPORT char * optarg
const char * get_progname(const char *argv0)
size_t strlcpy(char *dst, const char *src, size_t siz)
static bool IsXLogFileName(const char *fname)
static bool IsBackupHistoryFileName(const char *fname)
static void XLogFileNameById(char *fname, TimeLineID tli, uint32 log, uint32 seg)
static bool IsPartialXLogFileName(const char *fname)