Add UUID version 7 generation function.
[pgsql.git] / src / backend / backup / basebackup_target.c
blobbb50bdfe1d7a186154f2e89e0cfb1533082657cc
1 /*-------------------------------------------------------------------------
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.
9 * Portions Copyright (c) 2010-2024, PostgreSQL Global Development Group
11 * IDENTIFICATION
12 * src/backend/backup/basebackup_target.c
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include "backup/basebackup_target.h"
19 #include "utils/memutils.h"
21 typedef struct BaseBackupTargetType
23 char *name;
24 void *(*check_detail) (char *, char *);
25 bbsink *(*get_sink) (bbsink *, void *);
26 } BaseBackupTargetType;
28 struct BaseBackupTargetHandle
30 BaseBackupTargetType *type;
31 void *detail_arg;
34 static void initialize_target_list(void);
35 static bbsink *blackhole_get_sink(bbsink *next_sink, void *detail_arg);
36 static bbsink *server_get_sink(bbsink *next_sink, void *detail_arg);
37 static void *reject_target_detail(char *target, char *target_detail);
38 static void *server_check_detail(char *target, char *target_detail);
40 static BaseBackupTargetType builtin_backup_targets[] =
43 "blackhole", reject_target_detail, blackhole_get_sink
46 "server", server_check_detail, server_get_sink
49 NULL
53 static List *BaseBackupTargetTypeList = NIL;
56 * Add a new base backup target type.
58 * This is intended for use by server extensions.
60 void
61 BaseBackupAddTarget(char *name,
62 void *(*check_detail) (char *, char *),
63 bbsink *(*get_sink) (bbsink *, void *))
65 BaseBackupTargetType *newtype;
66 MemoryContext oldcontext;
67 ListCell *lc;
69 /* If the target list is not yet initialized, do that first. */
70 if (BaseBackupTargetTypeList == NIL)
71 initialize_target_list();
73 /* Search the target type list for an existing entry with this name. */
74 foreach(lc, BaseBackupTargetTypeList)
76 BaseBackupTargetType *ttype = lfirst(lc);
78 if (strcmp(ttype->name, name) == 0)
81 * We found one, so update it.
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.
87 ttype->check_detail = check_detail;
88 ttype->get_sink = get_sink;
89 return;
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.
98 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
99 newtype = palloc(sizeof(BaseBackupTargetType));
100 newtype->name = pstrdup(name);
101 newtype->check_detail = check_detail;
102 newtype->get_sink = get_sink;
103 BaseBackupTargetTypeList = lappend(BaseBackupTargetTypeList, newtype);
104 MemoryContextSwitchTo(oldcontext);
108 * Look up a base backup target and validate the target_detail.
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.
116 BaseBackupTargetHandle *
117 BaseBackupGetTargetHandle(char *target, char *target_detail)
119 ListCell *lc;
121 /* If the target list is not yet initialized, do that first. */
122 if (BaseBackupTargetTypeList == NIL)
123 initialize_target_list();
125 /* Search the target type list for a match. */
126 foreach(lc, BaseBackupTargetTypeList)
128 BaseBackupTargetType *ttype = lfirst(lc);
130 if (strcmp(ttype->name, target) == 0)
132 BaseBackupTargetHandle *handle;
134 /* Found the target. */
135 handle = palloc(sizeof(BaseBackupTargetHandle));
136 handle->type = ttype;
137 handle->detail_arg = ttype->check_detail(target, target_detail);
139 return handle;
143 /* Did not find the target. */
144 ereport(ERROR,
145 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
146 errmsg("unrecognized target: \"%s\"", target)));
148 /* keep compiler quiet */
149 return NULL;
153 * Construct a bbsink that will implement the backup target.
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.
162 bbsink *
163 BaseBackupGetSink(BaseBackupTargetHandle *handle, bbsink *next_sink)
165 return handle->type->get_sink(next_sink, handle->detail_arg);
169 * Load predefined target types into BaseBackupTargetTypeList.
171 static void
172 initialize_target_list(void)
174 BaseBackupTargetType *ttype = builtin_backup_targets;
175 MemoryContext oldcontext;
177 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
178 while (ttype->name != NULL)
180 BaseBackupTargetTypeList = lappend(BaseBackupTargetTypeList, ttype);
181 ++ttype;
183 MemoryContextSwitchTo(oldcontext);
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.
193 static bbsink *
194 blackhole_get_sink(bbsink *next_sink, void *detail_arg)
196 return next_sink;
200 * Create a bbsink implementing a server-side backup.
202 static bbsink *
203 server_get_sink(bbsink *next_sink, void *detail_arg)
205 return bbsink_server_new(next_sink, detail_arg);
209 * Implement target-detail checking for a target that does not accept a
210 * detail.
212 static void *
213 reject_target_detail(char *target, char *target_detail)
215 if (target_detail != NULL)
216 ereport(ERROR,
217 (errcode(ERRCODE_SYNTAX_ERROR),
218 errmsg("target \"%s\" does not accept a target detail",
219 target)));
221 return NULL;
225 * Implement target-detail checking for a server-side backup.
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.
231 static void *
232 server_check_detail(char *target, char *target_detail)
234 if (target_detail == NULL)
235 ereport(ERROR,
236 (errcode(ERRCODE_SYNTAX_ERROR),
237 errmsg("target \"%s\" requires a target detail",
238 target)));
240 return target_detail;