From 1ccafb998fd54365cbe4de0acffd0d75878b1280 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Fri, 8 May 2020 15:21:01 -0400
Subject: [PATCH v1 11/11] WIP: Convert backup manifest generation to a
 bbarchiver.

---
 src/backend/replication/backup_manifest.c | 106 +++++++++++++++++++-
 src/backend/replication/basebackup.c      | 113 +++++++++-------------
 src/include/replication/backup_manifest.h |   5 +-
 3 files changed, 153 insertions(+), 71 deletions(-)

diff --git a/src/backend/replication/backup_manifest.c b/src/backend/replication/backup_manifest.c
index 61f6f2c12b..bd9a5e4204 100644
--- a/src/backend/replication/backup_manifest.c
+++ b/src/backend/replication/backup_manifest.c
@@ -17,7 +17,6 @@
 #include "libpq/pqformat.h"
 #include "mb/pg_wchar.h"
 #include "replication/backup_manifest.h"
-#include "replication/basebackup_sink.h"
 #include "utils/builtins.h"
 #include "utils/json.h"
 
@@ -371,3 +370,108 @@ AppendStringToManifest(backup_manifest_info *manifest, char *s)
 				 errmsg("could not write to temporary file: %m")));
 	manifest->manifest_size += len;
 }
+
+typedef struct bbarchiver_manifest
+{
+	bbarchiver	base;
+
+	/* These things are fixed at creation time. */
+	backup_manifest_info *manifest;
+
+	/* This changes for each tablespace. */
+	const char *spcoid;
+
+	/* These change for each file. */
+	const char *file_pathname;
+	size_t		file_size;
+	pg_time_t	file_mtime;
+	pg_checksum_context file_checksum_ctx;
+} bbarchiver_manifest;
+
+static void bbarchiver_manifest_begin_tablespace(bbarchiver *archiver,
+												 tablespaceinfo *tsinfo);
+static void bbarchiver_manifest_begin_file(bbarchiver *archiver,
+									  const char *relative_path,
+									  struct stat *statbuf);
+static void bbarchiver_manifest_file_contents(bbarchiver *archiver,
+										 const char *data,
+										 size_t len);
+static void bbarchiver_manifest_end_file(bbarchiver *archiver);
+
+static const bbarchiver_ops bbarchiver_manifest_ops = {
+	.begin_tablespace = bbarchiver_manifest_begin_tablespace,
+	.end_tablespace = bbarchiver_forward_end_tablespace,
+	.begin_file = bbarchiver_manifest_begin_file,
+	.file_contents = bbarchiver_manifest_file_contents,
+	.end_file = bbarchiver_manifest_end_file,
+	.directory = bbarchiver_forward_directory,
+	.symbolic_link = bbarchiver_forward_symbolic_link
+};
+
+extern bbarchiver *
+bbarchiver_manifest_new(bbarchiver *next, backup_manifest_info *manifest)
+{
+	bbarchiver_manifest *archiver = palloc0(sizeof(bbarchiver_manifest));
+
+	*((const bbarchiver_ops **) &archiver->base.bba_ops) =
+		&bbarchiver_manifest_ops;
+	archiver->base.bba_next = next;
+	archiver->manifest = manifest;
+
+	return &archiver->base;
+}
+
+static void
+bbarchiver_manifest_begin_tablespace(bbarchiver *archiver,
+									 tablespaceinfo *tsinfo)
+{
+	bbarchiver_manifest *myarchiver = (bbarchiver_manifest *) archiver;
+
+	myarchiver->spcoid = tsinfo->oid;
+
+	bbarchiver_begin_tablespace(archiver->bba_next, tsinfo);
+}
+
+static void
+bbarchiver_manifest_begin_file(bbarchiver *archiver,
+							   const char *relative_path,
+							   struct stat *statbuf)
+{
+	bbarchiver_manifest *myarchiver = (bbarchiver_manifest *) archiver;
+
+	myarchiver->file_pathname = relative_path;
+	myarchiver->file_size = statbuf->st_size;
+	myarchiver->file_mtime = statbuf->st_mtime;
+
+	pg_checksum_init(&myarchiver->file_checksum_ctx,
+					 myarchiver->manifest->checksum_type);
+
+	bbarchiver_begin_file(archiver->bba_next, relative_path, statbuf);
+}
+
+static void
+bbarchiver_manifest_file_contents(bbarchiver *archiver,
+								  const char *data, size_t len)
+{
+	bbarchiver_manifest *myarchiver = (bbarchiver_manifest *) archiver;
+
+	pg_checksum_update(&myarchiver->file_checksum_ctx,
+					   (uint8 *) data, len);
+
+	bbarchiver_file_contents(archiver->bba_next, data, len);
+}
+
+static void
+bbarchiver_manifest_end_file(bbarchiver *archiver)
+{
+	bbarchiver_manifest *myarchiver = (bbarchiver_manifest *) archiver;
+
+	AddFileToBackupManifest(myarchiver->manifest,
+							myarchiver->spcoid,
+							myarchiver->file_pathname,
+							myarchiver->file_size,
+							myarchiver->file_mtime,
+							&myarchiver->file_checksum_ctx);
+
+	bbarchiver_end_file(archiver->bba_next);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index c606e7cf58..0e0b043b13 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -58,23 +58,17 @@ typedef struct
 static void archive_database_cluster(List *tablespaces, bbarchiver *archiver,
 									 StringInfo labelfile,
 									 StringInfo tblspc_map_file,
-									 bool leave_main_tablespace_open,
-									 backup_manifest_info *manifest);
-static void archive_tablespace(bbarchiver *archiver, char *path, char *oid,
-							   struct backup_manifest_info *manifest);
+									 bool leave_main_tablespace_open);
+static void archive_tablespace(bbarchiver *archiver, char *path);
 static void archive_directory(bbarchiver *archiver, const char *path,
 							  int basepathlen, List *tablespaces,
-							  bool sendtblspclinks,
-							  backup_manifest_info *manifest,
-							  const char *spcoid);
+							  bool sendtblspclinks);
 static void archive_file(bbarchiver *archiver, const char *readfilename,
 						 const char *tarfilename, struct stat *statbuf,
-						 bool missing_ok, Oid dboid,
-						 backup_manifest_info *manifest, const char *spcoid);
+						 bool missing_ok, Oid dboid);
 static void archive_file_with_content(bbarchiver *archiver,
 									  const char *filename,
-									  const char *content,
-									  backup_manifest_info *manifest);
+									  const char *content);
 static void convert_link_to_directory(const char *pathbuf, struct stat *statbuf);
 static void perform_base_backup(basebackup_options *opt);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
@@ -251,6 +245,14 @@ perform_base_backup(basebackup_options *opt)
 	bbarchiver *archiver;
 	bbarchiver *size_archiver;
 
+	/*
+	 * The backup manifest code uses a BufFile, so create a ResourceOwner.
+	 * This is cheap enough that we don't worry about doing it only if it's
+	 * needed, and there might be other uses for it in the future.
+	 */
+	Assert(CurrentResourceOwner == NULL);
+	CurrentResourceOwner = ResourceOwnerCreate(NULL, "base backup");
+
 	/* Set up network throttling, if client requested it */
 	if (opt->maxrate > 0)
 		sink = bbsink_throttle_new(sink, opt->maxrate);
@@ -262,9 +264,13 @@ perform_base_backup(basebackup_options *opt)
 	archiver = bbarchiver_tar_new(sink);
 	size_archiver = bbarchiver_tarsize_new();
 
-	/* we're going to use a BufFile, so we need a ResourceOwner */
-	Assert(CurrentResourceOwner == NULL);
-	CurrentResourceOwner = ResourceOwnerCreate(NULL, "base backup");
+	/* Set up backup manifest gneration, if enabled. */
+	if (opt->manifest != MANIFEST_OPTION_NO)
+	{
+		InitializeBackupManifest(&manifest, opt->manifest,
+								 opt->manifest_checksum_type);
+		archiver = bbarchiver_manifest_new(archiver, &manifest);
+	}
 
 	datadirpathlen = strlen(DataDir);
 
@@ -272,8 +278,6 @@ perform_base_backup(basebackup_options *opt)
 
 	labelfile = makeStringInfo();
 	tblspc_map_file = makeStringInfo();
-	InitializeBackupManifest(&manifest, opt->manifest,
-							 opt->manifest_checksum_type);
 
 	total_checksum_failures = 0;
 
@@ -318,7 +322,7 @@ perform_base_backup(basebackup_options *opt)
 			basebackup_progress_estimate_backup_size();
 
 			archive_database_cluster(tablespaces, size_archiver, labelfile,
-									 tblspc_map_file, false, NULL);
+									 tblspc_map_file, false);
 		}
 
 		/* notify basebackup sink about start of backup */
@@ -331,7 +335,7 @@ perform_base_backup(basebackup_options *opt)
 		 * so that we can archive the WAL files as well.
 		 */
 		archive_database_cluster(tablespaces, archiver, labelfile,
-								 tblspc_map_file, opt->includewal, &manifest);
+								 tblspc_map_file, opt->includewal);
 
 		basebackup_progress_wait_wal_archive(progress_sink);
 		endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
@@ -534,7 +538,7 @@ perform_base_backup(basebackup_options *opt)
 			 * complete segment.
 			 */
 			StatusFilePath(pathbuf, walFileName, ".done");
-			archive_file_with_content(archiver, pathbuf, "", &manifest);
+			archive_file_with_content(archiver, pathbuf, "");
 		}
 
 		/*
@@ -558,19 +562,23 @@ perform_base_backup(basebackup_options *opt)
 						 errmsg("could not stat file \"%s\": %m", pathbuf)));
 
 			archive_file(archiver, pathbuf, pathbuf, &statbuf, false,
-						 InvalidOid, &manifest, NULL);
+						 InvalidOid);
 
 			/* unconditionally mark file as archived */
 			StatusFilePath(pathbuf, fname, ".done");
-			archive_file_with_content(archiver, pathbuf, "", &manifest);
+			archive_file_with_content(archiver, pathbuf, "");
 		}
 
 		bbsink_end_archive(sink);
 	}
 
-	AddWALInfoToBackupManifest(&manifest, startptr, starttli, endptr, endtli);
 
-	SendBackupManifest(&manifest, sink);
+	if (opt->manifest != MANIFEST_OPTION_NO)
+	{
+		AddWALInfoToBackupManifest(&manifest, startptr, starttli,
+								   endptr, endtli);
+		SendBackupManifest(&manifest, sink);
+	}
 
 	bbsink_end_backup(sink, endptr, endtli);
 
@@ -598,8 +606,7 @@ perform_base_backup(basebackup_options *opt)
 static void
 archive_database_cluster(List *tablespaces, bbarchiver *archiver,
 						 StringInfo labelfile, StringInfo tblspc_map_file,
-						 bool leave_main_tablespace_open,
-						 backup_manifest_info *manifest)
+						 bool leave_main_tablespace_open)
 {
 	ListCell   *lc;
 
@@ -617,20 +624,18 @@ archive_database_cluster(List *tablespaces, bbarchiver *archiver,
 
 			/* For the main tablespace, archive the backup_label first... */
 			archive_file_with_content(archiver, BACKUP_LABEL_FILE,
-									  labelfile->data, manifest);
+									  labelfile->data);
 
 			/* Then the tablespace_map file, if present... */
 			if (tblspc_map_file != NULL)
 			{
 				archive_file_with_content(archiver, TABLESPACE_MAP,
-										  tblspc_map_file->data,
-										  manifest);
+										  tblspc_map_file->data);
 				sendtblspclinks = false;
 			}
 
 			/* Then the bulk of the files... */
-			archive_directory(archiver, ".", 1, tablespaces,
-							  sendtblspclinks, manifest, NULL);
+			archive_directory(archiver, ".", 1, tablespaces, sendtblspclinks);
 
 			/* ... and pg_control after everything else. */
 			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -639,10 +644,10 @@ archive_database_cluster(List *tablespaces, bbarchiver *archiver,
 						 errmsg("could not stat file \"%s\": %m",
 								XLOG_CONTROL_FILE)));
 			archive_file(archiver, XLOG_CONTROL_FILE, XLOG_CONTROL_FILE,
-						 &statbuf, false, InvalidOid, manifest, NULL);
+						 &statbuf, false, InvalidOid);
 		}
 		else
-			archive_tablespace(archiver, ti->path, ti->oid, manifest);
+			archive_tablespace(archiver, ti->path);
 
 		/*
 		 * If we were asked to leave the main tablespace open, then do so.
@@ -873,14 +878,10 @@ SendBaseBackup(BaseBackupCmd *cmd)
  */
 static void
 archive_file_with_content(bbarchiver *archiver, const char *filename,
-						  const char *content, backup_manifest_info *manifest)
+						  const char *content)
 {
 	struct stat statbuf;
 	int			len;
-	pg_checksum_context checksum_ctx;
-
-	if (manifest != NULL)
-		pg_checksum_init(&checksum_ctx, manifest->checksum_type);
 
 	len = strlen(content);
 
@@ -904,13 +905,6 @@ archive_file_with_content(bbarchiver *archiver, const char *filename,
 	if (bbarchiver_needs_file_contents(archiver))
 		bbarchiver_file_contents(archiver, content, len);
 	bbarchiver_end_file(archiver);
-
-	if (manifest != NULL)
-	{
-		pg_checksum_update(&checksum_ctx, (uint8 *) content, len);
-		AddFileToBackupManifest(manifest, NULL, filename, len,
-								(pg_time_t) statbuf.st_mtime, &checksum_ctx);
-	}
 }
 
 /*
@@ -921,8 +915,7 @@ archive_file_with_content(bbarchiver *archiver, const char *filename,
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 static void
-archive_tablespace(bbarchiver *archiver, char *path, char *spcoid,
-				   backup_manifest_info *manifest)
+archive_tablespace(bbarchiver *archiver, char *path)
 {
 	char		pathbuf[MAXPGPATH];
 	struct stat statbuf;
@@ -953,8 +946,7 @@ archive_tablespace(bbarchiver *archiver, char *path, char *spcoid,
 	bbarchiver_directory(archiver, TABLESPACE_VERSION_DIRECTORY, &statbuf);
 
 	/* Send all the files in the tablespace version directory */
-	archive_directory(archiver, pathbuf, strlen(path), NIL, true, manifest,
-					  spcoid);
+	archive_directory(archiver, pathbuf, strlen(path), NIL, true);
 }
 
 /*
@@ -971,8 +963,7 @@ archive_tablespace(bbarchiver *archiver, char *path, char *spcoid,
  */
 static void
 archive_directory(bbarchiver *archiver, const char *path, int basepathlen,
-				  List *tablespaces, bool sendtblspclinks,
-				  backup_manifest_info *manifest, const char *spcoid)
+				  List *tablespaces, bool sendtblspclinks)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -1258,14 +1249,13 @@ archive_directory(bbarchiver *archiver, const char *path, int basepathlen,
 
 			if (!skip_this_dir)
 				archive_directory(archiver, pathbuf, basepathlen, tablespaces,
-								  sendtblspclinks, manifest, spcoid);
+								  sendtblspclinks);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			archive_file(archiver, pathbuf, pathbuf + basepathlen + 1,
 						 &statbuf, true,
-						 isDbDir ? atooid(lastDir + 1) : InvalidOid,
-						 manifest, spcoid);
+						 isDbDir ? atooid(lastDir + 1) : InvalidOid);
 		}
 		else
 			ereport(WARNING,
@@ -1326,7 +1316,7 @@ is_checksummed_file(const char *fullpath, const char *filename)
 static void
 archive_file(bbarchiver *archiver, const char *readfilename,
 			 const char *tarfilename, struct stat *statbuf, bool missing_ok,
-			 Oid dboid, backup_manifest_info *manifest, const char *spcoid)
+			 Oid dboid)
 {
 	FILE	   *fp;
 	BlockNumber blkno = 0;
@@ -1342,10 +1332,6 @@ archive_file(bbarchiver *archiver, const char *readfilename,
 	int			segmentno = 0;
 	char	   *segmentpath;
 	bool		verify_checksum = false;
-	pg_checksum_context checksum_ctx;
-
-	if (manifest != NULL)
-		pg_checksum_init(&checksum_ctx, manifest->checksum_type);
 
 	bbarchiver_begin_file(archiver, tarfilename, statbuf);
 
@@ -1518,10 +1504,6 @@ archive_file(bbarchiver *archiver, const char *readfilename,
 
 		bbarchiver_file_contents(archiver, buf, cnt);
 
-		/* Also feed it to the checksum machinery. */
-		if (manifest != NULL)
-			pg_checksum_update(&checksum_ctx, (uint8 *) buf, cnt);
-
 		len += cnt;
 
 		if (feof(fp) || len >= statbuf->st_size)
@@ -1545,8 +1527,6 @@ archive_file(bbarchiver *archiver, const char *readfilename,
 		{
 			cnt = Min(sizeof(buf), statbuf->st_size - len);
 			bbarchiver_file_contents(archiver, buf, cnt);
-			if (manifest != NULL)
-				pg_checksum_update(&checksum_ctx, (uint8 *) buf, cnt);
 			len += cnt;
 		}
 	}
@@ -1567,11 +1547,6 @@ archive_file(bbarchiver *archiver, const char *readfilename,
 	}
 
 	total_checksum_failures += checksum_failures;
-
-	if (manifest != NULL)
-		AddFileToBackupManifest(manifest, spcoid, tarfilename,
-								statbuf->st_size,
-								(pg_time_t) statbuf->st_mtime, &checksum_ctx);
 }
 
 /*
diff --git a/src/include/replication/backup_manifest.h b/src/include/replication/backup_manifest.h
index 043635b31c..e9211d04bf 100644
--- a/src/include/replication/backup_manifest.h
+++ b/src/include/replication/backup_manifest.h
@@ -14,7 +14,7 @@
 
 #include "common/checksum_helper.h"
 #include "pgtime.h"
-#include "replication/basebackup_sink.h"
+#include "replication/basebackup_archiver.h"
 #include "storage/buffile.h"
 
 typedef enum manifest_option
@@ -49,4 +49,7 @@ extern void AddWALInfoToBackupManifest(backup_manifest_info *manifest,
 									   TimeLineID endtli);
 extern void SendBackupManifest(backup_manifest_info *manifest, bbsink *sink);
 
+extern bbarchiver *bbarchiver_manifest_new(bbarchiver *next,
+										   backup_manifest_info *manifest);
+
 #endif
-- 
2.24.2 (Apple Git-127)

