Skip to content
Snippets Groups Projects
Commit 3866ff61 authored by Magnus Hagander's avatar Magnus Hagander
Browse files

Enumerate available tablespaces after starting the backup

This closes a race condition where if a tablespace was created
after the enumeration happened but before the do_pg_start_backup()
was called, the backup would be incomplete. Now that it's done
while we are in backup mode, WAL replay will recreate it during
restore.

Noted by Heikki.
parent 3ab80cfe
Branches
Tags
No related merge requests found
......@@ -40,7 +40,7 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
static void SendBackupHeader(List *tablespaces);
static void SendBackupDirectory(char *location, char *spcoid);
static void base_backup_cleanup(int code, Datum arg);
static void perform_base_backup(const char *backup_label, List *tablespaces);
static void perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir);
typedef struct
{
......@@ -67,13 +67,50 @@ base_backup_cleanup(int code, Datum arg)
* clobbered by longjmp" from stupider versions of gcc.
*/
static void
perform_base_backup(const char *backup_label, List *tablespaces)
perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir)
{
do_pg_start_backup(backup_label, true);
PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
{
List *tablespaces = NIL;
ListCell *lc;
struct dirent *de;
tablespaceinfo *ti;
/* Add a node for the base directory */
ti = palloc0(sizeof(tablespaceinfo));
ti->size = progress ? sendDir(".", 1, true) : -1;
tablespaces = lappend(tablespaces, ti);
/* Collect information about all tablespaces */
while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
{
char fullpath[MAXPGPATH];
char linkpath[MAXPGPATH];
/* Skip special stuff */
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
continue;
snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
MemSet(linkpath, 0, sizeof(linkpath));
if (readlink(fullpath, linkpath, sizeof(linkpath) - 1) == -1)
{
ereport(WARNING,
(errmsg("unable to read symbolic link %s: %m", fullpath)));
continue;
}
ti = palloc(sizeof(tablespaceinfo));
ti->oid = pstrdup(de->d_name);
ti->path = pstrdup(linkpath);
ti->size = progress ? sendDir(linkpath, strlen(linkpath), true) : -1;
tablespaces = lappend(tablespaces, ti);
}
/* Send tablespace header */
SendBackupHeader(tablespaces);
......@@ -101,9 +138,6 @@ void
SendBaseBackup(const char *backup_label, bool progress)
{
DIR *dir;
struct dirent *de;
List *tablespaces = NIL;
tablespaceinfo *ti;
MemoryContext backup_context;
MemoryContext old_context;
......@@ -134,41 +168,10 @@ SendBaseBackup(const char *backup_label, bool progress)
ereport(ERROR,
(errmsg("unable to open directory pg_tblspc: %m")));
/* Add a node for the base directory */
ti = palloc0(sizeof(tablespaceinfo));
ti->size = progress ? sendDir(".", 1, true) : -1;
tablespaces = lappend(tablespaces, ti);
/* Collect information about all tablespaces */
while ((de = ReadDir(dir, "pg_tblspc")) != NULL)
{
char fullpath[MAXPGPATH];
char linkpath[MAXPGPATH];
/* Skip special stuff */
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
continue;
snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
MemSet(linkpath, 0, sizeof(linkpath));
if (readlink(fullpath, linkpath, sizeof(linkpath) - 1) == -1)
{
ereport(WARNING,
(errmsg("unable to read symbolic link %s: %m", fullpath)));
continue;
}
perform_base_backup(backup_label, progress, dir);
ti = palloc(sizeof(tablespaceinfo));
ti->oid = pstrdup(de->d_name);
ti->path = pstrdup(linkpath);
ti->size = progress ? sendDir(linkpath, strlen(linkpath), true) : -1;
tablespaces = lappend(tablespaces, ti);
}
FreeDir(dir);
perform_base_backup(backup_label, tablespaces);
MemoryContextSwitchTo(old_context);
MemoryContextDelete(backup_context);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment