Here's a cutdown version of the idea about including WAL in the base
backup. What I initially wanted was to introduce a way to guarantee
that the required WAL (with some sort of cutoff of course) would be
available for the backup, but I ran out of time for that. We can
always add that later.

For now, you need to set wal_keep_segments to make it work properly,
but if you do the idea is that the tar file/stream generated in the
base backup will include all the required WAL files. That means that
you can start a postmaster directly against the directory extracted
from the tarball, and you no longer need to set up archive logging to
get a backup.

I've got some refactoring I want to do around the
SendBackupDirectory() function after this, but a review of the
functionality first would be good. And obviously, documentation is
still necessary.

The patch to pg_basebackup applies on top of the previously posted version.

-- 
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index b4d5bbe..d8f0031 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -38,9 +38,9 @@ static void _tarWriteHeader(char *filename, char *linktarget,
 				struct stat * statbuf);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
-static void SendBackupDirectory(char *location, char *spcoid);
+static void SendBackupDirectory(char *location, char *spcoid, bool closetar);
 static void base_backup_cleanup(int code, Datum arg);
-static void perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir);
+static void perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, bool includewal);
 
 typedef struct
 {
@@ -67,9 +67,12 @@ base_backup_cleanup(int code, Datum arg)
  * clobbered by longjmp" from stupider versions of gcc.
  */
 static void
-perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir)
+perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, bool includewal)
 {
-	do_pg_start_backup(backup_label, true);
+	XLogRecPtr	startptr;
+	XLogRecPtr	endptr;
+
+	startptr = do_pg_start_backup(backup_label, true);
 
 	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 	{
@@ -79,11 +82,6 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir)
 		tablespaceinfo *ti;
 
 
-		/* Add a node for the base directory */
-		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = progress ? sendDir(".", 1, true) : -1;
-		tablespaces = lappend(tablespaces, ti);
-
 		/* Collect information about all tablespaces */
 		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
 		{
@@ -111,6 +109,10 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir)
 			tablespaces = lappend(tablespaces, ti);
 		}
 
+		/* Add a node for the base directory at the end */
+		ti = palloc0(sizeof(tablespaceinfo));
+		ti->size = progress ? sendDir(".", 1, true) : -1;
+		tablespaces = lappend(tablespaces, ti);
 
 		/* Send tablespace header */
 		SendBackupHeader(tablespaces);
@@ -120,12 +122,62 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir)
 		{
 			tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
 
-			SendBackupDirectory(ti->path, ti->oid);
+			SendBackupDirectory(ti->path, ti->oid,
+								!includewal || ti->path != NULL);
 		}
 	}
 	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 
-	do_pg_stop_backup();
+	endptr = do_pg_stop_backup();
+
+	if (includewal)
+	{
+		/*
+		 * We've left the last tar file "open", so we can now append the
+		 * required WAL files to it.
+		 */
+		int 	logid;
+		int		logseg;
+
+		elog(LOG, "Going to write wal from %i.%i to %i.%i",
+			 startptr.xlogid, startptr.xrecoff / XLogSegSize,
+			 endptr.xlogid, endptr.xrecoff / XLogSegSize);
+		logid = startptr.xlogid;
+		logseg = startptr.xrecoff / XLogSegSize;
+
+		while (true)
+		{
+			char	xlogname[64];
+			char	fn[MAXPGPATH];
+			struct stat statbuf;
+
+			/* Send the current WAL file */
+#define TIMELINE 1
+			XLogFileName(xlogname, TIMELINE, logid, logseg);
+			sprintf(fn, "./pg_xlog/%s", xlogname);
+			if (lstat(fn, &statbuf) != 0)
+				ereport(ERROR,
+						(errcode(errcode_for_file_access()),
+						 errmsg("could not stat file \"%s\": %m",
+								fn)));
+
+			if (!S_ISREG(statbuf.st_mode))
+				ereport(ERROR,
+						(errmsg("\"%s\" is not a file",
+								fn)));
+			sendFile(fn, 1, &statbuf);
+
+			/* Advance to the next WAL file */
+			NextLogSeg(logid, logseg);
+
+			/* Have we reached our stop position yet? */
+			if (logid > endptr.xlogid ||
+				(logid == endptr.xlogid && logseg >= endptr.xrecoff / XLogSegSize))
+				break;
+		}
+		/* Send CopyDone message for the last tar file*/
+		pq_putemptymessage('c');
+	}
 }
 
 /*
@@ -135,7 +187,7 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir)
  * pg_stop_backup() for the user.
  */
 void
-SendBaseBackup(const char *backup_label, bool progress)
+SendBaseBackup(const char *backup_label, bool progress, bool includewal)
 {
 	DIR		   *dir;
 	MemoryContext backup_context;
@@ -168,7 +220,7 @@ SendBaseBackup(const char *backup_label, bool progress)
 		ereport(ERROR,
 				(errmsg("unable to open directory pg_tblspc: %m")));
 
-	perform_base_backup(backup_label, progress, dir);
+	perform_base_backup(backup_label, progress, dir, includewal);
 
 	FreeDir(dir);
 
@@ -256,7 +308,7 @@ SendBackupHeader(List *tablespaces)
 }
 
 static void
-SendBackupDirectory(char *location, char *spcoid)
+SendBackupDirectory(char *location, char *spcoid, bool closetar)
 {
 	StringInfoData buf;
 
@@ -272,7 +324,8 @@ SendBackupDirectory(char *location, char *spcoid)
 			false);
 
 	/* Send CopyDone message */
-	pq_putemptymessage('c');
+	if (closetar)
+		pq_putemptymessage('c');
 }
 
 
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index 0ef33dd..d4bbcbe 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -66,11 +66,12 @@ Node *replication_parse_result;
 %token K_IDENTIFY_SYSTEM
 %token K_LABEL
 %token K_PROGRESS
+%token K_WAL
 %token K_START_REPLICATION
 
 %type <node>	command
 %type <node>	base_backup start_replication identify_system
-%type <boolval>	opt_progress
+%type <boolval>	opt_progress opt_wal
 %type <str>     opt_label
 
 %%
@@ -105,12 +106,13 @@ identify_system:
  * BASE_BACKUP [LABEL <label>] [PROGRESS]
  */
 base_backup:
-			K_BASE_BACKUP opt_label opt_progress
+			K_BASE_BACKUP opt_label opt_progress opt_wal
 				{
 					BaseBackupCmd *cmd = (BaseBackupCmd *) makeNode(BaseBackupCmd);
 
 					cmd->label = $2;
 					cmd->progress = $3;
+					cmd->includewal = $4;
 
 					$$ = (Node *) cmd;
 				}
@@ -124,6 +126,10 @@ opt_progress: K_PROGRESS		{ $$ = true; }
 			| /* EMPTY */		{ $$ = false; }
 			;
 
+opt_wal: K_WAL				{ $$ = true; }
+			| /* EMPTY */		{ $$ = false; }
+			;
+
 /*
  * START_REPLICATION %X/%X
  */
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 014a720..9f75346 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -60,6 +60,7 @@ BASE_BACKUP			{ return K_BASE_BACKUP; }
 IDENTIFY_SYSTEM		{ return K_IDENTIFY_SYSTEM; }
 LABEL			{ return K_LABEL; }
 PROGRESS			{ return K_PROGRESS; }
+WAL			{ return K_WAL; }
 START_REPLICATION	{ return K_START_REPLICATION; }
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 0ad6804..be3f8ec 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -402,7 +402,7 @@ HandleReplicationCommand(const char *cmd_string)
 			{
 				BaseBackupCmd *cmd = (BaseBackupCmd *) cmd_node;
 
-				SendBaseBackup(cmd->label, cmd->progress);
+				SendBaseBackup(cmd->label, cmd->progress, cmd->includewal);
 
 				/* Send CommandComplete and ReadyForQuery messages */
 				EndCommand("SELECT", DestRemote);
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 7fcb20a..eb315b9 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -33,6 +33,7 @@ char	   *label = "pg_basebackup base backup";
 bool		showprogress = false;
 int			verbose = 0;
 int			compresslevel = 0;
+bool		includewal = false;
 char	   *conninfo = NULL;
 
 /* Progress counters */
@@ -97,6 +98,7 @@ usage(void)
 	printf(_("  -d, --basedir=directory   receive base backup into directory\n"));
 	printf(_("  -t, --tardir=directory    receive base backup into tar files\n"
 			 "                            stored in specified directory\n"));
+	printf(_("  -w, --wal                 include required WAL files in backup\n"));
 	printf(_("  -Z, --compress=0-9        compress tar output\n"));
 	printf(_("  -l, --label=label         set backup label\n"));
 	printf(_("  -p, --progress            show progress information\n"));
@@ -642,9 +644,10 @@ BaseBackup()
 	conn = GetConnection();
 
 	PQescapeStringConn(conn, escaped_label, label, sizeof(escaped_label), &i);
-	snprintf(current_path, sizeof(current_path), "BASE_BACKUP LABEL '%s' %s",
+	snprintf(current_path, sizeof(current_path), "BASE_BACKUP LABEL '%s' %s %s",
 			 escaped_label,
-			 showprogress ? "PROGRESS" : "");
+			 showprogress ? "PROGRESS" : "",
+			 includewal ? "WAL" : "");
 
 	if (PQsendQuery(conn, current_path) == 0)
 	{
@@ -687,7 +690,7 @@ BaseBackup()
 		 * once since it can be relocated, and it will be checked before we do
 		 * anything anyway.
 		 */
-		if (basedir != NULL && i > 0)
+		if (basedir != NULL && !PQgetisnull(res, i, 1))
 			verify_dir_is_empty_or_create(PQgetvalue(res, i, 1));
 	}
 
@@ -747,6 +750,7 @@ main(int argc, char **argv)
 		{"conninfo", required_argument, NULL, 'c'},
 		{"basedir", required_argument, NULL, 'd'},
 		{"tardir", required_argument, NULL, 't'},
+		{"wal", no_argument, NULL, 'w'},
 		{"compress", required_argument, NULL, 'Z'},
 		{"label", required_argument, NULL, 'l'},
 		{"verbose", no_argument, NULL, 'v'},
@@ -776,7 +780,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	while ((c = getopt_long(argc, argv, "c:d:t:l:Z:vp",
+	while ((c = getopt_long(argc, argv, "c:d:t:l:Z:wvp",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -790,6 +794,9 @@ main(int argc, char **argv)
 			case 't':
 				tardir = xstrdup(optarg);
 				break;
+			case 'w':
+				includewal = true;
+				break;
 			case 'l':
 				label = xstrdup(optarg);
 				break;
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index eb2e160..3172d4b 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -12,6 +12,6 @@
 #ifndef _BASEBACKUP_H
 #define _BASEBACKUP_H
 
-extern void SendBaseBackup(const char *backup_label, bool progress);
+extern void SendBaseBackup(const char *backup_label, bool progress, bool includewal);
 
 #endif   /* _BASEBACKUP_H */
diff --git a/src/include/replication/replnodes.h b/src/include/replication/replnodes.h
index 4f4a1a3..4ecd18a 100644
--- a/src/include/replication/replnodes.h
+++ b/src/include/replication/replnodes.h
@@ -47,6 +47,7 @@ typedef struct BaseBackupCmd
 	NodeTag		type;
 	char	   *label;
 	bool		progress;
+	bool		includewal;
 }	BaseBackupCmd;
 
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to