Enumerate available tablespaces after starting the backup
authorMagnus Hagander <magnus@hagander.net>
Sat, 15 Jan 2011 18:18:14 +0000 (19:18 +0100)
committerMagnus Hagander <magnus@hagander.net>
Sat, 15 Jan 2011 18:31:16 +0000 (19:31 +0100)
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.

src/backend/replication/basebackup.c

index 1ed5e2a6c9eeecdb4642bc619448c330f700035c..b4d5bbe412e7791b36f509b7a27077b020fe0d2b 100644 (file)
@@ -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);
 }