mirror of
https://github.com/postgres/postgres.git
synced 2025-08-21 10:42:50 +03:00
Move basebackup code to new directory src/backend/backup
Reviewed by David Steele and Justin Pryzby Discussion: http://postgr.es/m/CA+TgmoafqboATDSoXHz8VLrSwK_MDhjthK4hEpYjqf9_1Fmczw%40mail.gmail.com
This commit is contained in:
241
src/backend/backup/basebackup_target.c
Normal file
241
src/backend/backup/basebackup_target.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* basebackup_target.c
|
||||
* Base backups can be "targeted", which means that they can be sent
|
||||
* somewhere other than to the client which requested the backup.
|
||||
* Furthermore, new targets can be defined by extensions. This file
|
||||
* contains code to support that functionality.
|
||||
*
|
||||
* Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/backup/basebackup_target.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "backup/basebackup_target.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
typedef struct BaseBackupTargetType
|
||||
{
|
||||
char *name;
|
||||
void *(*check_detail) (char *, char *);
|
||||
bbsink *(*get_sink) (bbsink *, void *);
|
||||
} BaseBackupTargetType;
|
||||
|
||||
struct BaseBackupTargetHandle
|
||||
{
|
||||
BaseBackupTargetType *type;
|
||||
void *detail_arg;
|
||||
};
|
||||
|
||||
static void initialize_target_list(void);
|
||||
static bbsink *blackhole_get_sink(bbsink *next_sink, void *detail_arg);
|
||||
static bbsink *server_get_sink(bbsink *next_sink, void *detail_arg);
|
||||
static void *reject_target_detail(char *target, char *target_detail);
|
||||
static void *server_check_detail(char *target, char *target_detail);
|
||||
|
||||
static BaseBackupTargetType builtin_backup_targets[] =
|
||||
{
|
||||
{
|
||||
"blackhole", reject_target_detail, blackhole_get_sink
|
||||
},
|
||||
{
|
||||
"server", server_check_detail, server_get_sink
|
||||
},
|
||||
{
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static List *BaseBackupTargetTypeList = NIL;
|
||||
|
||||
/*
|
||||
* Add a new base backup target type.
|
||||
*
|
||||
* This is intended for use by server extensions.
|
||||
*/
|
||||
void
|
||||
BaseBackupAddTarget(char *name,
|
||||
void *(*check_detail) (char *, char *),
|
||||
bbsink *(*get_sink) (bbsink *, void *))
|
||||
{
|
||||
BaseBackupTargetType *ttype;
|
||||
MemoryContext oldcontext;
|
||||
ListCell *lc;
|
||||
|
||||
/* If the target list is not yet initialized, do that first. */
|
||||
if (BaseBackupTargetTypeList == NIL)
|
||||
initialize_target_list();
|
||||
|
||||
/* Search the target type list for an existing entry with this name. */
|
||||
foreach(lc, BaseBackupTargetTypeList)
|
||||
{
|
||||
BaseBackupTargetType *ttype = lfirst(lc);
|
||||
|
||||
if (strcmp(ttype->name, name) == 0)
|
||||
{
|
||||
/*
|
||||
* We found one, so update it.
|
||||
*
|
||||
* It is probably not a great idea to call BaseBackupAddTarget for
|
||||
* the same name multiple times, but if it happens, this seems
|
||||
* like the sanest behavior.
|
||||
*/
|
||||
ttype->check_detail = check_detail;
|
||||
ttype->get_sink = get_sink;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We use TopMemoryContext for allocations here to make sure that the data
|
||||
* we need doesn't vanish under us; that's also why we copy the target
|
||||
* name into a newly-allocated chunk of memory.
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
ttype = palloc(sizeof(BaseBackupTargetType));
|
||||
ttype->name = pstrdup(name);
|
||||
ttype->check_detail = check_detail;
|
||||
ttype->get_sink = get_sink;
|
||||
BaseBackupTargetTypeList = lappend(BaseBackupTargetTypeList, ttype);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up a base backup target and validate the target_detail.
|
||||
*
|
||||
* Extensions that define new backup targets will probably define a new
|
||||
* type of bbsink to match. Validation of the target_detail can be performed
|
||||
* either in the check_detail routine called here, or in the bbsink
|
||||
* constructor, which will be called from BaseBackupGetSink. It's mostly
|
||||
* a matter of taste, but the check_detail function runs somewhat earlier.
|
||||
*/
|
||||
BaseBackupTargetHandle *
|
||||
BaseBackupGetTargetHandle(char *target, char *target_detail)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
/* If the target list is not yet initialized, do that first. */
|
||||
if (BaseBackupTargetTypeList == NIL)
|
||||
initialize_target_list();
|
||||
|
||||
/* Search the target type list for a match. */
|
||||
foreach(lc, BaseBackupTargetTypeList)
|
||||
{
|
||||
BaseBackupTargetType *ttype = lfirst(lc);
|
||||
|
||||
if (strcmp(ttype->name, target) == 0)
|
||||
{
|
||||
BaseBackupTargetHandle *handle;
|
||||
|
||||
/* Found the target. */
|
||||
handle = palloc(sizeof(BaseBackupTargetHandle));
|
||||
handle->type = ttype;
|
||||
handle->detail_arg = ttype->check_detail(target, target_detail);
|
||||
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
/* Did not find the target. */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("unrecognized target: \"%s\"", target)));
|
||||
|
||||
/* keep compiler quiet */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a bbsink that will implement the backup target.
|
||||
*
|
||||
* The get_sink function does all the real work, so all we have to do here
|
||||
* is call it with the correct arguments. Whatever the check_detail function
|
||||
* returned is here passed through to the get_sink function. This lets those
|
||||
* two functions communicate with each other, if they wish. If not, the
|
||||
* check_detail function can simply return the target_detail and let the
|
||||
* get_sink function take it from there.
|
||||
*/
|
||||
bbsink *
|
||||
BaseBackupGetSink(BaseBackupTargetHandle *handle, bbsink *next_sink)
|
||||
{
|
||||
return handle->type->get_sink(next_sink, handle->detail_arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load predefined target types into BaseBackupTargetTypeList.
|
||||
*/
|
||||
static void
|
||||
initialize_target_list(void)
|
||||
{
|
||||
BaseBackupTargetType *ttype = builtin_backup_targets;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
while (ttype->name != NULL)
|
||||
{
|
||||
BaseBackupTargetTypeList = lappend(BaseBackupTargetTypeList, ttype);
|
||||
++ttype;
|
||||
}
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Normally, a get_sink function should construct and return a new bbsink that
|
||||
* implements the backup target, but the 'blackhole' target just throws the
|
||||
* data away. We could implement that by adding a bbsink that does nothing
|
||||
* but forward, but it's even cheaper to implement that by not adding a bbsink
|
||||
* at all.
|
||||
*/
|
||||
static bbsink *
|
||||
blackhole_get_sink(bbsink *next_sink, void *detail_arg)
|
||||
{
|
||||
return next_sink;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a bbsink implementing a server-side backup.
|
||||
*/
|
||||
static bbsink *
|
||||
server_get_sink(bbsink *next_sink, void *detail_arg)
|
||||
{
|
||||
return bbsink_server_new(next_sink, detail_arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement target-detail checking for a target that does not accept a
|
||||
* detail.
|
||||
*/
|
||||
static void *
|
||||
reject_target_detail(char *target, char *target_detail)
|
||||
{
|
||||
if (target_detail != NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("target '%s' does not accept a target detail",
|
||||
target)));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement target-detail checking for a server-side backup.
|
||||
*
|
||||
* target_detail should be the name of the directory to which the backup
|
||||
* should be written, but we don't check that here. Rather, that check,
|
||||
* as well as the necessary permissions checking, happens in bbsink_server_new.
|
||||
*/
|
||||
static void *
|
||||
server_check_detail(char *target, char *target_detail)
|
||||
{
|
||||
if (target_detail == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("target '%s' requires a target detail",
|
||||
target)));
|
||||
|
||||
return target_detail;
|
||||
}
|
Reference in New Issue
Block a user