From 92eab334ce94b4e5e8dba5189ce2ffbecdeb67e6 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathandbossart@gmail.com>
Date: Fri, 27 Jan 2023 21:57:13 -0800
Subject: [PATCH 3/4] restructure archive module API

---
 contrib/basic_archive/basic_archive.c   | 13 +++++++++----
 src/backend/postmaster/pgarch.c         | 18 ++++++++---------
 src/backend/postmaster/shell_archive.c  | 14 ++++++++-----
 src/include/postmaster/archive_module.h | 26 ++++++++++---------------
 4 files changed, 36 insertions(+), 35 deletions(-)

diff --git a/contrib/basic_archive/basic_archive.c b/contrib/basic_archive/basic_archive.c
index 87bbb2174d..1655f72b5b 100644
--- a/contrib/basic_archive/basic_archive.c
+++ b/contrib/basic_archive/basic_archive.c
@@ -49,6 +49,12 @@ static void basic_archive_file_internal(const char *file, const char *path);
 static bool check_archive_directory(char **newval, void **extra, GucSource source);
 static bool compare_files(const char *file1, const char *file2);
 
+static const ArchiveModuleCallbacks basic_archive_callbacks = {
+	.check_configured_cb = basic_archive_configured,
+	.archive_file_cb = basic_archive_file,
+	.shutdown_cb = NULL
+};
+
 /*
  * _PG_init
  *
@@ -78,13 +84,12 @@ _PG_init(void)
  *
  * Returns the module's archiving callbacks.
  */
-void
-_PG_archive_module_init(ArchiveModuleCallbacks *cb)
+const ArchiveModuleCallbacks *
+_PG_archive_module_init(void)
 {
 	AssertVariableIsOfType(&_PG_archive_module_init, ArchiveModuleInit);
 
-	cb->check_configured_cb = basic_archive_configured;
-	cb->archive_file_cb = basic_archive_file;
+	return &basic_archive_callbacks;
 }
 
 /*
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index eca02d5e74..627c579f0e 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -98,7 +98,7 @@ char	   *XLogArchiveLibrary = "";
  */
 static time_t last_sigterm_time = 0;
 static PgArchData *PgArch = NULL;
-static ArchiveModuleCallbacks ArchiveCallbacks;
+static const ArchiveModuleCallbacks *ArchiveCallbacks;
 
 
 /*
@@ -417,8 +417,8 @@ pgarch_ArchiverCopyLoop(void)
 			HandlePgArchInterrupts();
 
 			/* can't do anything if not configured ... */
-			if (ArchiveCallbacks.check_configured_cb != NULL &&
-				!ArchiveCallbacks.check_configured_cb())
+			if (ArchiveCallbacks->check_configured_cb != NULL &&
+				!ArchiveCallbacks->check_configured_cb())
 			{
 				ereport(WARNING,
 						(errmsg("archive_mode enabled, yet archiving is not configured")));
@@ -519,7 +519,7 @@ pgarch_archiveXlog(char *xlog)
 	snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog);
 	set_ps_display(activitymsg);
 
-	ret = ArchiveCallbacks.archive_file_cb(xlog, pathname);
+	ret = ArchiveCallbacks->archive_file_cb(xlog, pathname);
 	if (ret)
 		snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog);
 	else
@@ -838,8 +838,6 @@ LoadArchiveLibrary(void)
 				 errmsg("both archive_command and archive_library set"),
 				 errdetail("Only one of archive_command, archive_library may be set.")));
 
-	memset(&ArchiveCallbacks, 0, sizeof(ArchiveModuleCallbacks));
-
 	/*
 	 * If shell archiving is enabled, use our special initialization function.
 	 * Otherwise, load the library and call its _PG_archive_module_init().
@@ -855,9 +853,9 @@ LoadArchiveLibrary(void)
 		ereport(ERROR,
 				(errmsg("archive modules have to define the symbol %s", "_PG_archive_module_init")));
 
-	(*archive_init) (&ArchiveCallbacks);
+	ArchiveCallbacks = (*archive_init) ();
 
-	if (ArchiveCallbacks.archive_file_cb == NULL)
+	if (ArchiveCallbacks->archive_file_cb == NULL)
 		ereport(ERROR,
 				(errmsg("archive modules must register an archive callback")));
 
@@ -870,6 +868,6 @@ LoadArchiveLibrary(void)
 static void
 pgarch_call_module_shutdown_cb(int code, Datum arg)
 {
-	if (ArchiveCallbacks.shutdown_cb != NULL)
-		ArchiveCallbacks.shutdown_cb();
+	if (ArchiveCallbacks->shutdown_cb != NULL)
+		ArchiveCallbacks->shutdown_cb();
 }
diff --git a/src/backend/postmaster/shell_archive.c b/src/backend/postmaster/shell_archive.c
index b64297e3bb..dde20c83de 100644
--- a/src/backend/postmaster/shell_archive.c
+++ b/src/backend/postmaster/shell_archive.c
@@ -26,14 +26,18 @@ static bool shell_archive_configured(void);
 static bool shell_archive_file(const char *file, const char *path);
 static void shell_archive_shutdown(void);
 
-void
-shell_archive_init(ArchiveModuleCallbacks *cb)
+static const ArchiveModuleCallbacks shell_archive_callbacks = {
+	.check_configured_cb = shell_archive_configured,
+	.archive_file_cb = shell_archive_file,
+	.shutdown_cb = shell_archive_shutdown
+};
+
+const ArchiveModuleCallbacks *
+shell_archive_init(void)
 {
 	AssertVariableIsOfType(&shell_archive_init, ArchiveModuleInit);
 
-	cb->check_configured_cb = shell_archive_configured;
-	cb->archive_file_cb = shell_archive_file;
-	cb->shutdown_cb = shell_archive_shutdown;
+	return &shell_archive_callbacks;
 }
 
 static bool
diff --git a/src/include/postmaster/archive_module.h b/src/include/postmaster/archive_module.h
index 099050c1ca..67b5624874 100644
--- a/src/include/postmaster/archive_module.h
+++ b/src/include/postmaster/archive_module.h
@@ -18,37 +18,31 @@
 extern PGDLLIMPORT char *XLogArchiveLibrary;
 
 /*
- * Archive module callbacks
- *
- * These callback functions should be defined by archive libraries and returned
- * via _PG_archive_module_init().  ArchiveFileCB is the only required callback.
- * For more information about the purpose of each callback, refer to the
- * archive modules documentation.
+ * API struct for an archive module.  This should be allocated as a static
+ * const struct and returned via _PG_archive_module_init.  archive_file_cb is
+ * the only required callback.  For more information about the purpose of each
+ * callback, refer to the archive modules documentation.
  */
-typedef bool (*ArchiveCheckConfiguredCB) (void);
-typedef bool (*ArchiveFileCB) (const char *file, const char *path);
-typedef void (*ArchiveShutdownCB) (void);
-
 typedef struct ArchiveModuleCallbacks
 {
-	ArchiveCheckConfiguredCB check_configured_cb;
-	ArchiveFileCB archive_file_cb;
-	ArchiveShutdownCB shutdown_cb;
+	bool (*check_configured_cb) (void);
+	bool (*archive_file_cb) (const char *file, const char *path);
+	void (*shutdown_cb) (void);
 } ArchiveModuleCallbacks;
 
 /*
  * Type of the shared library symbol _PG_archive_module_init that is looked
  * up when loading an archive library.
  */
-typedef void (*ArchiveModuleInit) (ArchiveModuleCallbacks *cb);
+typedef const ArchiveModuleCallbacks *(*ArchiveModuleInit) (void);
 
-extern PGDLLEXPORT void _PG_archive_module_init(ArchiveModuleCallbacks *cb);
+extern PGDLLEXPORT const ArchiveModuleCallbacks *_PG_archive_module_init(void);
 
 /*
  * Since the logic for archiving via a shell command is in the core server
  * and does not need to be loaded via a shared library, it has a special
  * initialization function.
  */
-extern void shell_archive_init(ArchiveModuleCallbacks *cb);
+extern const ArchiveModuleCallbacks *shell_archive_init(void);
 
 #endif							/* _ARCHIVE_MODULE_H */
-- 
2.25.1

