1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Redesign archive modules

A new callback named startup_cb, called shortly after a module is
loaded, is added.  This makes possible the initialization of any
additional state data required by a module.  This initial state data can
be saved in a ArchiveModuleState, that is now passed down to all the
callbacks that can be defined in a module.  With this design, it is
possible to have a per-module state, aimed at opening the door to the
support of more than one archive module.

The initialization of the callbacks is changed so as
_PG_archive_module_init() does not anymore give in input a
ArchiveModuleCallbacks that a module has to fill in with callback
definitions.  Instead, a module now needs to return a const
ArchiveModuleCallbacks.

All the structure and callback definitions of archive modules are moved
into their own header, named archive_module.h, from pgarch.h.
Command-based archiving follows the same line, with a new set of files
named shell_archive.{c,h}.

There are a few more items that are under discussion to improve the
design of archive modules, like the fact that basic_archive calls
sigsetjmp() by itself to define its own error handling flow.  These will
be adjusted later, the changes done here cover already a good portion
of what has been discussed.

Any modules created for v15 will need to be adjusted to this new
design.

Author: Nathan Bossart
Reviewed-by: Andres Freund
Discussion: https://postgr.es/m/20230130194810.6fztfgbn32e7qarj@awork3.anarazel.de
This commit is contained in:
Michael Paquier
2023-02-17 14:26:42 +09:00
parent d2ea2d310d
commit 35739b87dc
15 changed files with 253 additions and 90 deletions

View File

@ -30,9 +30,9 @@
#include <sys/time.h>
#include <unistd.h>
#include "archive/archive_module.h"
#include "common/int.h"
#include "miscadmin.h"
#include "postmaster/pgarch.h"
#include "storage/copydir.h"
#include "storage/fd.h"
#include "utils/guc.h"
@ -40,14 +40,27 @@
PG_MODULE_MAGIC;
static char *archive_directory = NULL;
static MemoryContext basic_archive_context;
typedef struct BasicArchiveData
{
MemoryContext context;
} BasicArchiveData;
static bool basic_archive_configured(void);
static bool basic_archive_file(const char *file, const char *path);
static char *archive_directory = NULL;
static void basic_archive_startup(ArchiveModuleState *state);
static bool basic_archive_configured(ArchiveModuleState *state);
static bool basic_archive_file(ArchiveModuleState *state, const char *file, const char *path);
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 void basic_archive_shutdown(ArchiveModuleState *state);
static const ArchiveModuleCallbacks basic_archive_callbacks = {
.startup_cb = basic_archive_startup,
.check_configured_cb = basic_archive_configured,
.archive_file_cb = basic_archive_file,
.shutdown_cb = basic_archive_shutdown
};
/*
* _PG_init
@ -67,10 +80,6 @@ _PG_init(void)
check_archive_directory, NULL, NULL);
MarkGUCPrefixReserved("basic_archive");
basic_archive_context = AllocSetContextCreate(TopMemoryContext,
"basic_archive",
ALLOCSET_DEFAULT_SIZES);
}
/*
@ -78,11 +87,28 @@ _PG_init(void)
*
* Returns the module's archiving callbacks.
*/
void
_PG_archive_module_init(ArchiveModuleCallbacks *cb)
const ArchiveModuleCallbacks *
_PG_archive_module_init(void)
{
cb->check_configured_cb = basic_archive_configured;
cb->archive_file_cb = basic_archive_file;
return &basic_archive_callbacks;
}
/*
* basic_archive_startup
*
* Creates the module's memory context.
*/
void
basic_archive_startup(ArchiveModuleState *state)
{
BasicArchiveData *data;
data = (BasicArchiveData *) MemoryContextAllocZero(TopMemoryContext,
sizeof(BasicArchiveData));
data->context = AllocSetContextCreate(TopMemoryContext,
"basic_archive",
ALLOCSET_DEFAULT_SIZES);
state->private_data = (void *) data;
}
/*
@ -133,7 +159,7 @@ check_archive_directory(char **newval, void **extra, GucSource source)
* Checks that archive_directory is not blank.
*/
static bool
basic_archive_configured(void)
basic_archive_configured(ArchiveModuleState *state)
{
return archive_directory != NULL && archive_directory[0] != '\0';
}
@ -144,10 +170,12 @@ basic_archive_configured(void)
* Archives one file.
*/
static bool
basic_archive_file(const char *file, const char *path)
basic_archive_file(ArchiveModuleState *state, const char *file, const char *path)
{
sigjmp_buf local_sigjmp_buf;
MemoryContext oldcontext;
BasicArchiveData *data = (BasicArchiveData *) state->private_data;
MemoryContext basic_archive_context = data->context;
/*
* We run basic_archive_file_internal() in our own memory context so that
@ -366,3 +394,35 @@ compare_files(const char *file1, const char *file2)
return ret;
}
/*
* basic_archive_shutdown
*
* Frees our allocated state.
*/
static void
basic_archive_shutdown(ArchiveModuleState *state)
{
BasicArchiveData *data = (BasicArchiveData *) state->private_data;
MemoryContext basic_archive_context;
/*
* If we didn't get to storing the pointer to our allocated state, we don't
* have anything to clean up.
*/
if (data == NULL)
return;
basic_archive_context = data->context;
Assert(CurrentMemoryContext != basic_archive_context);
if (MemoryContextIsValid(basic_archive_context))
MemoryContextDelete(basic_archive_context);
data->context = NULL;
/*
* Finally, free the state.
*/
pfree(data);
state->private_data = NULL;
}