Fix parallel pg_restore to handle comments on POST_DATA items correctly.

The previous coding would try to process all SECTION_NONE items in the
initial sequential-restore pass, which failed if they were dependencies of
not-yet-restored items.  Fix by postponing such items into the parallel
processing pass once we have skipped any non-PRE_DATA item.

Back-patch into 9.0; the original parallel-restore coding in 8.4 did not
have this bug, so no need to change it.

Report and diagnosis by Arnd Hannemann.
This commit is contained in:
Tom Lane 2011-02-18 13:11:45 -05:00
parent 472f608e43
commit 4cff100d73

View File

@ -3218,12 +3218,12 @@ dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim)
* Main engine for parallel restore. * Main engine for parallel restore.
* *
* Work is done in three phases. * Work is done in three phases.
* First we process tocEntries until we come to one that is marked * First we process all SECTION_PRE_DATA tocEntries, in a single connection,
* SECTION_DATA or SECTION_POST_DATA, in a single connection, just as for a * just as for a standard restore. Second we process the remaining non-ACL
* standard restore. Second we process the remaining non-ACL steps in * steps in parallel worker children (threads on Windows, processes on Unix),
* parallel worker children (threads on Windows, processes on Unix), each of * each of which connects separately to the database. Finally we process all
* which connects separately to the database. Finally we process all the ACL * the ACL entries in a single connection (that happens back in
* entries in a single connection (that happens back in RestoreArchive). * RestoreArchive).
*/ */
static void static void
restore_toc_entries_parallel(ArchiveHandle *AH) restore_toc_entries_parallel(ArchiveHandle *AH)
@ -3233,6 +3233,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
ParallelSlot *slots; ParallelSlot *slots;
int work_status; int work_status;
int next_slot; int next_slot;
bool skipped_some;
TocEntry pending_list; TocEntry pending_list;
TocEntry ready_list; TocEntry ready_list;
TocEntry *next_work_item; TocEntry *next_work_item;
@ -3262,12 +3263,31 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
* showing all the dependencies of SECTION_PRE_DATA items, so we do not * showing all the dependencies of SECTION_PRE_DATA items, so we do not
* risk trying to process them out-of-order. * risk trying to process them out-of-order.
*/ */
skipped_some = false;
for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next) for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next)
{ {
/* Non-PRE_DATA items are just ignored for now */ /* NB: process-or-continue logic must be the inverse of loop below */
if (next_work_item->section != SECTION_PRE_DATA)
{
/* DATA and POST_DATA items are just ignored for now */
if (next_work_item->section == SECTION_DATA || if (next_work_item->section == SECTION_DATA ||
next_work_item->section == SECTION_POST_DATA) next_work_item->section == SECTION_POST_DATA)
{
skipped_some = true;
continue; continue;
}
else
{
/*
* SECTION_NONE items, such as comments, can be processed now
* if we are still in the PRE_DATA part of the archive. Once
* we've skipped any items, we have to consider whether the
* comment's dependencies are satisfied, so skip it for now.
*/
if (skipped_some)
continue;
}
}
ahlog(AH, 1, "processing item %d %s %s\n", ahlog(AH, 1, "processing item %d %s %s\n",
next_work_item->dumpId, next_work_item->dumpId,
@ -3310,18 +3330,33 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
*/ */
par_list_header_init(&pending_list); par_list_header_init(&pending_list);
par_list_header_init(&ready_list); par_list_header_init(&ready_list);
skipped_some = false;
for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next) for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next)
{
/* NB: process-or-continue logic must be the inverse of loop above */
if (next_work_item->section == SECTION_PRE_DATA)
{ {
/* All PRE_DATA items were dealt with above */ /* All PRE_DATA items were dealt with above */
continue;
}
if (next_work_item->section == SECTION_DATA || if (next_work_item->section == SECTION_DATA ||
next_work_item->section == SECTION_POST_DATA) next_work_item->section == SECTION_POST_DATA)
{ {
/* set this flag at same point that previous loop did */
skipped_some = true;
}
else
{
/* SECTION_NONE items must be processed if previous loop didn't */
if (!skipped_some)
continue;
}
if (next_work_item->depCount > 0) if (next_work_item->depCount > 0)
par_list_append(&pending_list, next_work_item); par_list_append(&pending_list, next_work_item);
else else
par_list_append(&ready_list, next_work_item); par_list_append(&ready_list, next_work_item);
} }
}
/* /*
* main parent loop * main parent loop