summaryrefslogtreecommitdiff
path: root/src/backend/replication/basebackup.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2021-11-16 15:20:50 -0500
committerRobert Haas <rhaas@postgresql.org>2022-01-20 10:46:33 -0500
commit3500ccc39b0dadd1068a03938e4b8ff562587ccc (patch)
tree1c5d639bebf9c9f493a4cebffd59baa4c7dafbb9 /src/backend/replication/basebackup.c
parentf80900be06f784a6bda705800305c550e05d6edf (diff)
Support base backup targets.
pg_basebackup now has a --target=TARGET[:DETAIL] option. If specfied, it is sent to the server as the value of the TARGET option to the BASE_BACKUP command. If DETAIL is included, it is sent as the value of the new TARGET_DETAIL option to the BASE_BACKUP command. If the target is anything other than 'client', pg_basebackup assumes that it will now be the server's job to write the backup in a location somehow defined by the target, and that it therefore needs to write nothing locally. However, the server will still send messages to the client for progress reporting purposes. On the server side, we now support two additional types of backup targets. There is a 'blackhole' target, which just throws away the backup data without doing anything at all with it. Naturally, this should only be used for testing and debugging purposes, since you will not actually have a backup when it finishes running. More usefully, there is also a 'server' target, so you can now use something like 'pg_basebackup -Xnone -t server:/SOME/PATH' to write a backup to some location on the server. We can extend this to more types of targets in the future, and might even want to create an extensibility mechanism for adding new target types. Since WAL fetching is handled with separate client-side logic, it's not part of this mechanism; thus, backups with non-default targets must use -Xnone or -Xfetch. Patch by me, with a bug fix by Jeevan Ladhe. The patch set of which this is a part has also had review and/or testing from Tushar Ahuja, Suraj Kharage, Dipesh Pandit, and Mark Dilger. Discussion: http://postgr.es/m/CA+TgmoaYZbz0=Yk797aOJwkGJC-LK3iXn+wzzMx7KdwNpZhS5g@mail.gmail.com
Diffstat (limited to 'src/backend/replication/basebackup.c')
-rw-r--r--src/backend/replication/basebackup.c81
1 files changed, 68 insertions, 13 deletions
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 3afbbe7e02e..d32da515355 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -55,8 +55,10 @@
typedef enum
{
+ BACKUP_TARGET_BLACKHOLE,
BACKUP_TARGET_COMPAT,
- BACKUP_TARGET_CLIENT
+ BACKUP_TARGET_CLIENT,
+ BACKUP_TARGET_SERVER
} backup_target_type;
typedef struct
@@ -69,6 +71,7 @@ typedef struct
uint32 maxrate;
bool sendtblspcmapfile;
backup_target_type target;
+ char *target_detail;
backup_manifest_option manifest;
pg_checksum_type manifest_checksum_type;
} basebackup_options;
@@ -702,6 +705,8 @@ parse_basebackup_options(List *options, basebackup_options *opt)
bool o_manifest = false;
bool o_manifest_checksums = false;
bool o_target = false;
+ bool o_target_detail = false;
+ char *target_str = "compat"; /* placate compiler */
MemSet(opt, 0, sizeof(*opt));
opt->target = BACKUP_TARGET_COMPAT;
@@ -847,25 +852,35 @@ parse_basebackup_options(List *options, basebackup_options *opt)
}
else if (strcmp(defel->defname, "target") == 0)
{
- char *optval = defGetString(defel);
+ target_str = defGetString(defel);
if (o_target)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("duplicate option \"%s\"", defel->defname)));
- if (strcmp(optval, "client") == 0)
+ if (strcmp(target_str, "blackhole") == 0)
+ opt->target = BACKUP_TARGET_BLACKHOLE;
+ else if (strcmp(target_str, "client") == 0)
opt->target = BACKUP_TARGET_CLIENT;
+ else if (strcmp(target_str, "server") == 0)
+ opt->target = BACKUP_TARGET_SERVER;
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("unrecognized target: \"%s\"", optval)));
+ errmsg("unrecognized target: \"%s\"", target_str)));
o_target = true;
}
- else
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("option \"%s\" not recognized",
- defel->defname));
+ else if (strcmp(defel->defname, "target_detail") == 0)
+ {
+ char *optval = defGetString(defel);
+
+ if (o_target_detail)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("duplicate option \"%s\"", defel->defname)));
+ opt->target_detail = optval;
+ o_target_detail = true;
+ }
}
if (opt->label == NULL)
opt->label = "base backup";
@@ -877,6 +892,22 @@ parse_basebackup_options(List *options, basebackup_options *opt)
errmsg("manifest checksums require a backup manifest")));
opt->manifest_checksum_type = CHECKSUM_TYPE_NONE;
}
+ if (opt->target == BACKUP_TARGET_SERVER)
+ {
+ if (opt->target_detail == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("target '%s' requires a target detail",
+ target_str)));
+ }
+ else
+ {
+ if (opt->target_detail != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("target '%s' does not accept a target detail",
+ target_str)));
+ }
}
@@ -908,14 +939,38 @@ SendBaseBackup(BaseBackupCmd *cmd)
/*
* If the TARGET option was specified, then we can use the new copy-stream
- * protocol. If not, we must fall back to the old and less capable
- * copy-tablespace protocol.
+ * protocol. If the target is specifically 'client' then set up to stream
+ * the backup to the client; otherwise, it's being sent someplace else and
+ * should not be sent to the client.
+ *
+ * If the TARGET option was not specified, we must fall back to the older
+ * and less capable copy-tablespace protocol.
*/
- if (opt.target != BACKUP_TARGET_COMPAT)
- sink = bbsink_copystream_new();
+ if (opt.target == BACKUP_TARGET_CLIENT)
+ sink = bbsink_copystream_new(true);
+ else if (opt.target != BACKUP_TARGET_COMPAT)
+ sink = bbsink_copystream_new(false);
else
sink = bbsink_copytblspc_new();
+ /*
+ * If a non-default backup target is in use, arrange to send the data
+ * wherever it needs to go.
+ */
+ switch (opt.target)
+ {
+ case BACKUP_TARGET_BLACKHOLE:
+ /* Nothing to do, just discard data. */
+ break;
+ case BACKUP_TARGET_COMPAT:
+ case BACKUP_TARGET_CLIENT:
+ /* Nothing to do, handling above is sufficient. */
+ break;
+ case BACKUP_TARGET_SERVER:
+ sink = bbsink_server_new(sink, opt.target_detail);
+ break;
+ }
+
/* Set up network throttling, if client requested it */
if (opt.maxrate > 0)
sink = bbsink_throttle_new(sink, opt.maxrate);