postgresql/src/backend/backup/basebackup_server.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

312 lines
8.5 KiB
C
Raw Normal View History

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
2021-11-16 21:20:50 +01:00
/*-------------------------------------------------------------------------
*
* basebackup_server.c
* store basebackup archives on the server
*
* IDENTIFICATION
* src/backend/backup/basebackup_server.c
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
2021-11-16 21:20:50 +01:00
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/xact.h"
#include "backup/basebackup.h"
#include "backup/basebackup_sink.h"
#include "catalog/pg_authid.h"
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
2021-11-16 21:20:50 +01:00
#include "miscadmin.h"
#include "storage/fd.h"
#include "utils/acl.h"
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
2021-11-16 21:20:50 +01:00
#include "utils/timestamp.h"
#include "utils/wait_event.h"
typedef struct bbsink_server
{
/* Common information for all types of sink. */
bbsink base;
/* Directory in which backup is to be stored. */
char *pathname;
/* Currently open file (or 0 if nothing open). */
File file;
/* Current file position. */
off_t filepos;
} bbsink_server;
static void bbsink_server_begin_archive(bbsink *sink,
const char *archive_name);
static void bbsink_server_archive_contents(bbsink *sink, size_t len);
static void bbsink_server_end_archive(bbsink *sink);
static void bbsink_server_begin_manifest(bbsink *sink);
static void bbsink_server_manifest_contents(bbsink *sink, size_t len);
static void bbsink_server_end_manifest(bbsink *sink);
static const bbsink_ops bbsink_server_ops = {
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
2021-11-16 21:20:50 +01:00
.begin_backup = bbsink_forward_begin_backup,
.begin_archive = bbsink_server_begin_archive,
.archive_contents = bbsink_server_archive_contents,
.end_archive = bbsink_server_end_archive,
.begin_manifest = bbsink_server_begin_manifest,
.manifest_contents = bbsink_server_manifest_contents,
.end_manifest = bbsink_server_end_manifest,
.end_backup = bbsink_forward_end_backup,
.cleanup = bbsink_forward_cleanup
};
/*
* Create a new 'server' bbsink.
*/
bbsink *
bbsink_server_new(bbsink *next, char *pathname)
{
bbsink_server *sink = palloc0(sizeof(bbsink_server));
*((const bbsink_ops **) &sink->base.bbs_ops) = &bbsink_server_ops;
sink->pathname = pathname;
sink->base.bbs_next = next;
/* Replication permission is not sufficient in this case. */
StartTransactionCommand();
if (!has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
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
2021-11-16 21:20:50 +01:00
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create backup stored on server"),
errdetail("Only roles with privileges of the \"%s\" role may create a backup stored on the server.",
"pg_write_server_files")));
CommitTransactionCommand();
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
2021-11-16 21:20:50 +01:00
/*
* It's not a good idea to store your backups in the same directory that
* you're backing up. If we allowed a relative path here, that could
* easily happen accidentally, so we don't. The user could still
* accomplish the same thing by including the absolute path to $PGDATA in
* the pathname, but that's likely an intentional bad decision rather than
* an accident.
*/
if (!is_absolute_path(pathname))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
2022-09-25 00:38:35 +02:00
errmsg("relative path not allowed for backup stored on server")));
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
2021-11-16 21:20:50 +01:00
switch (pg_check_dir(pathname))
{
case 0:
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
2021-11-16 21:20:50 +01:00
/*
* Does not exist, so create it using the same permissions we'd
* use for a new subdirectory of the data directory itself.
*/
if (MakePGDirectory(pathname) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create directory \"%s\": %m", pathname)));
break;
case 1:
/* Exists, empty. */
break;
case 2:
case 3:
case 4:
/* Exists, not empty. */
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FILE),
errmsg("directory \"%s\" exists but is not empty",
pathname)));
break;
default:
/* Access problem. */
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not access directory \"%s\": %m",
pathname)));
}
return &sink->base;
}
/*
* Open the correct output file for this archive.
*/
static void
bbsink_server_begin_archive(bbsink *sink, const char *archive_name)
{
bbsink_server *mysink = (bbsink_server *) sink;
char *filename;
Assert(mysink->file == 0);
Assert(mysink->filepos == 0);
filename = psprintf("%s/%s", mysink->pathname, archive_name);
mysink->file = PathNameOpenFile(filename,
O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
if (mysink->file <= 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create file \"%s\": %m", filename)));
pfree(filename);
bbsink_forward_begin_archive(sink, archive_name);
}
/*
* Write the data to the output file.
*/
static void
bbsink_server_archive_contents(bbsink *sink, size_t len)
{
bbsink_server *mysink = (bbsink_server *) sink;
int nbytes;
nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);
if (nbytes != len)
{
if (nbytes < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write file \"%s\": %m",
FilePathName(mysink->file)),
errhint("Check free disk space.")));
/* short write: complain appropriately */
ereport(ERROR,
(errcode(ERRCODE_DISK_FULL),
errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
FilePathName(mysink->file),
nbytes, (int) len, (unsigned) mysink->filepos),
errhint("Check free disk space.")));
}
mysink->filepos += nbytes;
bbsink_forward_archive_contents(sink, len);
}
/*
* fsync and close the current output file.
*/
static void
bbsink_server_end_archive(bbsink *sink)
{
bbsink_server *mysink = (bbsink_server *) sink;
/*
* We intentionally don't use data_sync_elevel here, because the server
* shouldn't PANIC just because we can't guarantee that the backup has
* been written down to disk. Running recovery won't fix anything in this
* case anyway.
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
2021-11-16 21:20:50 +01:00
*/
if (FileSync(mysink->file, WAIT_EVENT_BASEBACKUP_SYNC) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m",
FilePathName(mysink->file))));
/* We're done with this file now. */
FileClose(mysink->file);
mysink->file = 0;
mysink->filepos = 0;
bbsink_forward_end_archive(sink);
}
/*
* Open the output file to which we will write the manifest.
*
* Just like pg_basebackup, we write the manifest first under a temporary
* name and then rename it into place after fsync. That way, if the manifest
* is there and under the correct name, the user can be sure that the backup
* completed.
*/
static void
bbsink_server_begin_manifest(bbsink *sink)
{
bbsink_server *mysink = (bbsink_server *) sink;
char *tmp_filename;
Assert(mysink->file == 0);
tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);
mysink->file = PathNameOpenFile(tmp_filename,
O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
if (mysink->file <= 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create file \"%s\": %m", tmp_filename)));
pfree(tmp_filename);
bbsink_forward_begin_manifest(sink);
}
/*
* Each chunk of manifest data is sent using a CopyData message.
*/
static void
bbsink_server_manifest_contents(bbsink *sink, size_t len)
{
bbsink_server *mysink = (bbsink_server *) sink;
int nbytes;
nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);
if (nbytes != len)
{
if (nbytes < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write file \"%s\": %m",
FilePathName(mysink->file)),
errhint("Check free disk space.")));
/* short write: complain appropriately */
ereport(ERROR,
(errcode(ERRCODE_DISK_FULL),
errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
FilePathName(mysink->file),
nbytes, (int) len, (unsigned) mysink->filepos),
errhint("Check free disk space.")));
}
mysink->filepos += nbytes;
bbsink_forward_manifest_contents(sink, len);
}
/*
* fsync the backup manifest, close the file, and then rename it into place.
*/
static void
bbsink_server_end_manifest(bbsink *sink)
{
bbsink_server *mysink = (bbsink_server *) sink;
char *tmp_filename;
char *filename;
/* We're done with this file now. */
FileClose(mysink->file);
mysink->file = 0;
/*
* Rename it into place. This also fsyncs the temporary file, so we don't
* need to do that here. We don't use data_sync_elevel here for the same
* reasons as in bbsink_server_end_archive.
*/
tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);
filename = psprintf("%s/backup_manifest", mysink->pathname);
durable_rename(tmp_filename, filename, ERROR);
pfree(filename);
pfree(tmp_filename);
bbsink_forward_end_manifest(sink);
}