Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 35739b8

Browse files
committed
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
1 parent d2ea2d3 commit 35739b8

File tree

15 files changed

+252
-89
lines changed

15 files changed

+252
-89
lines changed

contrib/basic_archive/basic_archive.c

+73-13
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,37 @@
3030
#include <sys/time.h>
3131
#include <unistd.h>
3232

33+
#include "archive/archive_module.h"
3334
#include "common/int.h"
3435
#include "miscadmin.h"
35-
#include "postmaster/pgarch.h"
3636
#include "storage/copydir.h"
3737
#include "storage/fd.h"
3838
#include "utils/guc.h"
3939
#include "utils/memutils.h"
4040

4141
PG_MODULE_MAGIC;
4242

43+
typedef struct BasicArchiveData
44+
{
45+
MemoryContext context;
46+
} BasicArchiveData;
47+
4348
static char *archive_directory = NULL;
44-
static MemoryContext basic_archive_context;
4549

46-
static bool basic_archive_configured(void);
47-
static bool basic_archive_file(const char *file, const char *path);
50+
static void basic_archive_startup(ArchiveModuleState *state);
51+
static bool basic_archive_configured(ArchiveModuleState *state);
52+
static bool basic_archive_file(ArchiveModuleState *state, const char *file, const char *path);
4853
static void basic_archive_file_internal(const char *file, const char *path);
4954
static bool check_archive_directory(char **newval, void **extra, GucSource source);
5055
static bool compare_files(const char *file1, const char *file2);
56+
static void basic_archive_shutdown(ArchiveModuleState *state);
57+
58+
static const ArchiveModuleCallbacks basic_archive_callbacks = {
59+
.startup_cb = basic_archive_startup,
60+
.check_configured_cb = basic_archive_configured,
61+
.archive_file_cb = basic_archive_file,
62+
.shutdown_cb = basic_archive_shutdown
63+
};
5164

5265
/*
5366
* _PG_init
@@ -67,22 +80,35 @@ _PG_init(void)
6780
check_archive_directory, NULL, NULL);
6881

6982
MarkGUCPrefixReserved("basic_archive");
70-
71-
basic_archive_context = AllocSetContextCreate(TopMemoryContext,
72-
"basic_archive",
73-
ALLOCSET_DEFAULT_SIZES);
7483
}
7584

7685
/*
7786
* _PG_archive_module_init
7887
*
7988
* Returns the module's archiving callbacks.
8089
*/
90+
const ArchiveModuleCallbacks *
91+
_PG_archive_module_init(void)
92+
{
93+
return &basic_archive_callbacks;
94+
}
95+
96+
/*
97+
* basic_archive_startup
98+
*
99+
* Creates the module's memory context.
100+
*/
81101
void
82-
_PG_archive_module_init(ArchiveModuleCallbacks *cb)
102+
basic_archive_startup(ArchiveModuleState *state)
83103
{
84-
cb->check_configured_cb = basic_archive_configured;
85-
cb->archive_file_cb = basic_archive_file;
104+
BasicArchiveData *data;
105+
106+
data = (BasicArchiveData *) MemoryContextAllocZero(TopMemoryContext,
107+
sizeof(BasicArchiveData));
108+
data->context = AllocSetContextCreate(TopMemoryContext,
109+
"basic_archive",
110+
ALLOCSET_DEFAULT_SIZES);
111+
state->private_data = (void *) data;
86112
}
87113

88114
/*
@@ -133,7 +159,7 @@ check_archive_directory(char **newval, void **extra, GucSource source)
133159
* Checks that archive_directory is not blank.
134160
*/
135161
static bool
136-
basic_archive_configured(void)
162+
basic_archive_configured(ArchiveModuleState *state)
137163
{
138164
return archive_directory != NULL && archive_directory[0] != '\0';
139165
}
@@ -144,10 +170,12 @@ basic_archive_configured(void)
144170
* Archives one file.
145171
*/
146172
static bool
147-
basic_archive_file(const char *file, const char *path)
173+
basic_archive_file(ArchiveModuleState *state, const char *file, const char *path)
148174
{
149175
sigjmp_buf local_sigjmp_buf;
150176
MemoryContext oldcontext;
177+
BasicArchiveData *data = (BasicArchiveData *) state->private_data;
178+
MemoryContext basic_archive_context = data->context;
151179

152180
/*
153181
* 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)
366394

367395
return ret;
368396
}
397+
398+
/*
399+
* basic_archive_shutdown
400+
*
401+
* Frees our allocated state.
402+
*/
403+
static void
404+
basic_archive_shutdown(ArchiveModuleState *state)
405+
{
406+
BasicArchiveData *data = (BasicArchiveData *) state->private_data;
407+
MemoryContext basic_archive_context;
408+
409+
/*
410+
* If we didn't get to storing the pointer to our allocated state, we don't
411+
* have anything to clean up.
412+
*/
413+
if (data == NULL)
414+
return;
415+
416+
basic_archive_context = data->context;
417+
Assert(CurrentMemoryContext != basic_archive_context);
418+
419+
if (MemoryContextIsValid(basic_archive_context))
420+
MemoryContextDelete(basic_archive_context);
421+
data->context = NULL;
422+
423+
/*
424+
* Finally, free the state.
425+
*/
426+
pfree(data);
427+
state->private_data = NULL;
428+
}

doc/src/sgml/archive-modules.sgml

+27-8
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,22 @@
4747
normal library search path is used to locate the library. To provide the
4848
required archive module callbacks and to indicate that the library is
4949
actually an archive module, it needs to provide a function named
50-
<function>_PG_archive_module_init</function>. This function is passed a
51-
struct that needs to be filled with the callback function pointers for
52-
individual actions.
50+
<function>_PG_archive_module_init</function>. The result of the function
51+
must be a pointer to a struct of type
52+
<structname>ArchiveModuleCallbacks</structname>, which contains everything
53+
that the core code needs to know how to make use of the archive module. The
54+
return value needs to be of server lifetime, which is typically achieved by
55+
defining it as a <literal>static const</literal> variable in global scope.
5356

5457
<programlisting>
5558
typedef struct ArchiveModuleCallbacks
5659
{
60+
ArchiveStartupCB startup_cb;
5761
ArchiveCheckConfiguredCB check_configured_cb;
5862
ArchiveFileCB archive_file_cb;
5963
ArchiveShutdownCB shutdown_cb;
6064
} ArchiveModuleCallbacks;
61-
typedef void (*ArchiveModuleInit) (struct ArchiveModuleCallbacks *cb);
65+
typedef const ArchiveModuleCallbacks *(*ArchiveModuleInit) (void);
6266
</programlisting>
6367

6468
Only the <function>archive_file_cb</function> callback is required. The
@@ -73,6 +77,20 @@ typedef void (*ArchiveModuleInit) (struct ArchiveModuleCallbacks *cb);
7377
The server will call them as required to process each individual WAL file.
7478
</para>
7579

80+
<sect2 id="archive-module-startup">
81+
<title>Startup Callback</title>
82+
<para>
83+
The <function>startup_cb</function> callback is called shortly after the
84+
module is loaded. This callback can be used to perform any additional
85+
initialization required. If the archive module has a state, it can use
86+
<structfield>state->private_data</structfield> to store it.
87+
88+
<programlisting>
89+
typedef void (*ArchiveStartupCB) (ArchiveModuleState *state);
90+
</programlisting>
91+
</para>
92+
</sect2>
93+
7694
<sect2 id="archive-module-check">
7795
<title>Check Callback</title>
7896
<para>
@@ -83,7 +101,7 @@ typedef void (*ArchiveModuleInit) (struct ArchiveModuleCallbacks *cb);
83101
assumes the module is configured.
84102

85103
<programlisting>
86-
typedef bool (*ArchiveCheckConfiguredCB) (void);
104+
typedef bool (*ArchiveCheckConfiguredCB) (ArchiveModuleState *state);
87105
</programlisting>
88106

89107
If <literal>true</literal> is returned, the server will proceed with
@@ -105,7 +123,7 @@ WARNING: archive_mode enabled, yet archiving is not configured
105123
single WAL file.
106124

107125
<programlisting>
108-
typedef bool (*ArchiveFileCB) (const char *file, const char *path);
126+
typedef bool (*ArchiveFileCB) (ArchiveModuleState *state, const char *file, const char *path);
109127
</programlisting>
110128

111129
If <literal>true</literal> is returned, the server proceeds as if the file
@@ -125,10 +143,11 @@ typedef bool (*ArchiveFileCB) (const char *file, const char *path);
125143
process exits (e.g., after an error) or the value of
126144
<xref linkend="guc-archive-library"/> changes. If no
127145
<function>shutdown_cb</function> is defined, no special action is taken in
128-
these situations.
146+
these situations. If the archive module has a state, this callback should
147+
free it to avoid leaks.
129148

130149
<programlisting>
131-
typedef void (*ArchiveShutdownCB) (void);
150+
typedef void (*ArchiveShutdownCB) (ArchiveModuleState *state);
132151
</programlisting>
133152
</para>
134153
</sect2>

src/backend/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ subdir = src/backend
1717
top_builddir = ../..
1818
include $(top_builddir)/src/Makefile.global
1919

20-
SUBDIRS = access backup bootstrap catalog parser commands executor \
20+
SUBDIRS = access archive backup bootstrap catalog parser commands executor \
2121
foreign lib libpq \
2222
main nodes optimizer partitioning port postmaster \
2323
regex replication rewrite \

src/backend/archive/Makefile

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#-------------------------------------------------------------------------
2+
#
3+
# Makefile--
4+
# Makefile for src/backend/archive
5+
#
6+
# IDENTIFICATION
7+
# src/backend/archive/Makefile
8+
#
9+
#-------------------------------------------------------------------------
10+
11+
subdir = src/backend/archive
12+
top_builddir = ../../..
13+
include $(top_builddir)/src/Makefile.global
14+
15+
OBJS = \
16+
shell_archive.o
17+
18+
include $(top_srcdir)/src/backend/common.mk

src/backend/archive/meson.build

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright (c) 2023, PostgreSQL Global Development Group
2+
3+
backend_sources += files(
4+
'shell_archive.c'
5+
)

src/backend/postmaster/shell_archive.c renamed to src/backend/archive/shell_archive.c

+26-15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Copyright (c) 2022-2023, PostgreSQL Global Development Group
1010
*
1111
* IDENTIFICATION
12-
* src/backend/postmaster/shell_archive.c
12+
* src/backend/archive/shell_archive.c
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -18,30 +18,39 @@
1818
#include <sys/wait.h>
1919

2020
#include "access/xlog.h"
21+
#include "archive/archive_module.h"
22+
#include "archive/shell_archive.h"
2123
#include "common/percentrepl.h"
2224
#include "pgstat.h"
23-
#include "postmaster/pgarch.h"
2425

25-
static bool shell_archive_configured(void);
26-
static bool shell_archive_file(const char *file, const char *path);
27-
static void shell_archive_shutdown(void);
28-
29-
void
30-
shell_archive_init(ArchiveModuleCallbacks *cb)
26+
static bool shell_archive_configured(ArchiveModuleState *state);
27+
static bool shell_archive_file(ArchiveModuleState *state,
28+
const char *file,
29+
const char *path);
30+
static void shell_archive_shutdown(ArchiveModuleState *state);
31+
32+
static const ArchiveModuleCallbacks shell_archive_callbacks = {
33+
.startup_cb = NULL,
34+
.check_configured_cb = shell_archive_configured,
35+
.archive_file_cb = shell_archive_file,
36+
.shutdown_cb = shell_archive_shutdown
37+
};
38+
39+
const ArchiveModuleCallbacks *
40+
shell_archive_init(void)
3141
{
32-
cb->check_configured_cb = shell_archive_configured;
33-
cb->archive_file_cb = shell_archive_file;
34-
cb->shutdown_cb = shell_archive_shutdown;
42+
return &shell_archive_callbacks;
3543
}
3644

3745
static bool
38-
shell_archive_configured(void)
46+
shell_archive_configured(ArchiveModuleState *state)
3947
{
4048
return XLogArchiveCommand[0] != '\0';
4149
}
4250

4351
static bool
44-
shell_archive_file(const char *file, const char *path)
52+
shell_archive_file(ArchiveModuleState *state, const char *file,
53+
const char *path)
4554
{
4655
char *xlogarchcmd;
4756
char *nativePath = NULL;
@@ -53,7 +62,9 @@ shell_archive_file(const char *file, const char *path)
5362
make_native_path(nativePath);
5463
}
5564

56-
xlogarchcmd = replace_percent_placeholders(XLogArchiveCommand, "archive_command", "fp", file, nativePath);
65+
xlogarchcmd = replace_percent_placeholders(XLogArchiveCommand,
66+
"archive_command", "fp",
67+
file, nativePath);
5768

5869
if (nativePath)
5970
pfree(nativePath);
@@ -123,7 +134,7 @@ shell_archive_file(const char *file, const char *path)
123134
}
124135

125136
static void
126-
shell_archive_shutdown(void)
137+
shell_archive_shutdown(ArchiveModuleState *state)
127138
{
128139
elog(DEBUG1, "archiver process shutting down");
129140
}

src/backend/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ backend_link_with = [pgport_srv, common_srv]
77
generated_backend_sources = []
88

99
subdir('access')
10+
subdir('archive')
1011
subdir('backup')
1112
subdir('bootstrap')
1213
subdir('catalog')

src/backend/postmaster/Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ OBJS = \
2222
interrupt.o \
2323
pgarch.o \
2424
postmaster.o \
25-
shell_archive.o \
2625
startup.o \
2726
syslogger.o \
2827
walwriter.o

src/backend/postmaster/meson.build

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ backend_sources += files(
1010
'interrupt.c',
1111
'pgarch.c',
1212
'postmaster.c',
13-
'shell_archive.c',
1413
'startup.c',
1514
'syslogger.c',
1615
'walwriter.c',

0 commit comments

Comments
 (0)