1 /*-------------------------------------------------------------------------
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
12 * src/backend/backup/basebackup_target.c
14 *-------------------------------------------------------------------------
18 #include "backup/basebackup_target.h"
19 #include "utils/memutils.h"
21 typedef struct BaseBackupTargetType
24 void *(*check_detail
) (char *, char *);
25 bbsink
*(*get_sink
) (bbsink
*, void *);
26 } BaseBackupTargetType
;
28 struct BaseBackupTargetHandle
30 BaseBackupTargetType
*type
;
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
53 static List
*BaseBackupTargetTypeList
= NIL
;
56 * Add a new base backup target type.
58 * This is intended for use by server extensions.
61 BaseBackupAddTarget(char *name
,
62 void *(*check_detail
) (char *, char *),
63 bbsink
*(*get_sink
) (bbsink
*, void *))
65 BaseBackupTargetType
*newtype
;
66 MemoryContext oldcontext
;
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
;
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
)
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
);
143 /* Did not find the target. */
145 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
146 errmsg("unrecognized target: \"%s\"", target
)));
148 /* keep compiler quiet */
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.
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.
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
);
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
194 blackhole_get_sink(bbsink
*next_sink
, void *detail_arg
)
200 * Create a bbsink implementing a server-side backup.
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
213 reject_target_detail(char *target
, char *target_detail
)
215 if (target_detail
!= NULL
)
217 (errcode(ERRCODE_SYNTAX_ERROR
),
218 errmsg("target \"%s\" does not accept a target detail",
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.
232 server_check_detail(char *target
, char *target_detail
)
234 if (target_detail
== NULL
)
236 (errcode(ERRCODE_SYNTAX_ERROR
),
237 errmsg("target \"%s\" requires a target detail",
240 return target_detail
;