PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
basebackup_target.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * basebackup_target.c
4 * Base backups can be "targeted", which means that they can be sent
5 * somewhere other than to the client which requested the backup.
6 * Furthermore, new targets can be defined by extensions. This file
7 * contains code to support that functionality.
8 *
9 * Portions Copyright (c) 2010-2024, PostgreSQL Global Development Group
10 *
11 * IDENTIFICATION
12 * src/backend/backup/basebackup_target.c
13 *
14 *-------------------------------------------------------------------------
15 */
16#include "postgres.h"
17
19#include "utils/memutils.h"
20
22{
23 char *name;
24 void *(*check_detail) (char *, char *);
25 bbsink *(*get_sink) (bbsink *, void *);
27
29{
32};
33
34static void initialize_target_list(void);
35static bbsink *blackhole_get_sink(bbsink *next_sink, void *detail_arg);
36static bbsink *server_get_sink(bbsink *next_sink, void *detail_arg);
37static void *reject_target_detail(char *target, char *target_detail);
38static void *server_check_detail(char *target, char *target_detail);
39
41{
42 {
44 },
45 {
47 },
48 {
49 NULL
50 }
51};
52
54
55/*
56 * Add a new base backup target type.
57 *
58 * This is intended for use by server extensions.
59 */
60void
62 void *(*check_detail) (char *, char *),
63 bbsink *(*get_sink) (bbsink *, void *))
64{
65 BaseBackupTargetType *newtype;
66 MemoryContext oldcontext;
67 ListCell *lc;
68
69 /* If the target list is not yet initialized, do that first. */
72
73 /* Search the target type list for an existing entry with this name. */
74 foreach(lc, BaseBackupTargetTypeList)
75 {
76 BaseBackupTargetType *ttype = lfirst(lc);
77
78 if (strcmp(ttype->name, name) == 0)
79 {
80 /*
81 * We found one, so update it.
82 *
83 * It is probably not a great idea to call BaseBackupAddTarget for
84 * the same name multiple times, but if it happens, this seems
85 * like the sanest behavior.
86 */
87 ttype->check_detail = check_detail;
88 ttype->get_sink = get_sink;
89 return;
90 }
91 }
92
93 /*
94 * We use TopMemoryContext for allocations here to make sure that the data
95 * we need doesn't vanish under us; that's also why we copy the target
96 * name into a newly-allocated chunk of memory.
97 */
99 newtype = palloc(sizeof(BaseBackupTargetType));
100 newtype->name = pstrdup(name);
101 newtype->check_detail = check_detail;
102 newtype->get_sink = get_sink;
104 MemoryContextSwitchTo(oldcontext);
105}
106
107/*
108 * Look up a base backup target and validate the target_detail.
109 *
110 * Extensions that define new backup targets will probably define a new
111 * type of bbsink to match. Validation of the target_detail can be performed
112 * either in the check_detail routine called here, or in the bbsink
113 * constructor, which will be called from BaseBackupGetSink. It's mostly
114 * a matter of taste, but the check_detail function runs somewhat earlier.
115 */
117BaseBackupGetTargetHandle(char *target, char *target_detail)
118{
119 ListCell *lc;
120
121 /* If the target list is not yet initialized, do that first. */
124
125 /* Search the target type list for a match. */
126 foreach(lc, BaseBackupTargetTypeList)
127 {
128 BaseBackupTargetType *ttype = lfirst(lc);
129
130 if (strcmp(ttype->name, target) == 0)
131 {
133
134 /* Found the target. */
135 handle = palloc(sizeof(BaseBackupTargetHandle));
136 handle->type = ttype;
137 handle->detail_arg = ttype->check_detail(target, target_detail);
138
139 return handle;
140 }
141 }
142
143 /* Did not find the target. */
145 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
146 errmsg("unrecognized target: \"%s\"", target)));
147
148 /* keep compiler quiet */
149 return NULL;
150}
151
152/*
153 * Construct a bbsink that will implement the backup target.
154 *
155 * The get_sink function does all the real work, so all we have to do here
156 * is call it with the correct arguments. Whatever the check_detail function
157 * returned is here passed through to the get_sink function. This lets those
158 * two functions communicate with each other, if they wish. If not, the
159 * check_detail function can simply return the target_detail and let the
160 * get_sink function take it from there.
161 */
162bbsink *
164{
165 return handle->type->get_sink(next_sink, handle->detail_arg);
166}
167
168/*
169 * Load predefined target types into BaseBackupTargetTypeList.
170 */
171static void
173{
175 MemoryContext oldcontext;
176
178 while (ttype->name != NULL)
179 {
181 ++ttype;
182 }
183 MemoryContextSwitchTo(oldcontext);
184}
185
186/*
187 * Normally, a get_sink function should construct and return a new bbsink that
188 * implements the backup target, but the 'blackhole' target just throws the
189 * data away. We could implement that by adding a bbsink that does nothing
190 * but forward, but it's even cheaper to implement that by not adding a bbsink
191 * at all.
192 */
193static bbsink *
194blackhole_get_sink(bbsink *next_sink, void *detail_arg)
195{
196 return next_sink;
197}
198
199/*
200 * Create a bbsink implementing a server-side backup.
201 */
202static bbsink *
203server_get_sink(bbsink *next_sink, void *detail_arg)
204{
205 return bbsink_server_new(next_sink, detail_arg);
206}
207
208/*
209 * Implement target-detail checking for a target that does not accept a
210 * detail.
211 */
212static void *
213reject_target_detail(char *target, char *target_detail)
214{
215 if (target_detail != NULL)
217 (errcode(ERRCODE_SYNTAX_ERROR),
218 errmsg("target \"%s\" does not accept a target detail",
219 target)));
220
221 return NULL;
222}
223
224/*
225 * Implement target-detail checking for a server-side backup.
226 *
227 * target_detail should be the name of the directory to which the backup
228 * should be written, but we don't check that here. Rather, that check,
229 * as well as the necessary permissions checking, happens in bbsink_server_new.
230 */
231static void *
232server_check_detail(char *target, char *target_detail)
233{
234 if (target_detail == NULL)
236 (errcode(ERRCODE_SYNTAX_ERROR),
237 errmsg("target \"%s\" requires a target detail",
238 target)));
239
240 return target_detail;
241}
bbsink * bbsink_server_new(bbsink *next, char *pathname)
struct BaseBackupTargetType BaseBackupTargetType
static void * reject_target_detail(char *target, char *target_detail)
BaseBackupTargetHandle * BaseBackupGetTargetHandle(char *target, char *target_detail)
static bbsink * server_get_sink(bbsink *next_sink, void *detail_arg)
static List * BaseBackupTargetTypeList
static bbsink * blackhole_get_sink(bbsink *next_sink, void *detail_arg)
bbsink * BaseBackupGetSink(BaseBackupTargetHandle *handle, bbsink *next_sink)
static BaseBackupTargetType builtin_backup_targets[]
static void * server_check_detail(char *target, char *target_detail)
void BaseBackupAddTarget(char *name, void *(*check_detail)(char *, char *), bbsink *(*get_sink)(bbsink *, void *))
static void initialize_target_list(void)
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
List * lappend(List *list, void *datum)
Definition: list.c:339
char * pstrdup(const char *in)
Definition: mcxt.c:1696
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * palloc(Size size)
Definition: mcxt.c:1317
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
MemoryContextSwitchTo(old_ctx)
BaseBackupTargetType * type
void *(* check_detail)(char *, char *)
bbsink *(* get_sink)(bbsink *, void *)
Definition: pg_list.h:54
const char * name