Improve parallel restore's ability to cope with selective restore (-L option).
The original coding tended to break down in the face of modified restore orders, as shown in bug #5626 from Albert Ullrich, because it would flip over into parallel-restore operation too soon. That causes problems because we don't have sufficient dependency information in dump archives to allow safe parallel processing of SECTION_PRE_DATA items. Even if we did, it's probably undesirable to allow that to override the commanded restore order. To fix the problem of omitted items causing unexpected changes in restore order, tweak SortTocFromFile so that omitted items end up at the head of the list not the tail. This ensures that they'll be examined and their dependencies will be marked satisfied before we get to any interesting items. In HEAD and 9.0, we can easily change restore_toc_entries_parallel so that all SECTION_PRE_DATA items are guaranteed to be processed in the initial serial-restore loop, and hence in commanded order. Only DATA and POST_DATA items are candidates for parallel processing. For them there might be variations from the commanded order because of parallelism, but we should do it in a safe order thanks to dependencies. In 8.4 it's much harder to make such a guarantee. I settled for not letting the initial loop break out into parallel processing mode if it sees a DATA/POST_DATA item that's not to be restored; this at least prevents a non-restorable item from causing premature exit from the loop. This means that 8.4 will be more likely to fail given a badly-ordered -L list than 9.x, but we don't really promise any such thing will work anyway.
This commit is contained in:
parent
affcd50e40
commit
01faed3678
@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.172.2.2 2010/06/28 02:07:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.172.2.3 2010/08/21 13:59:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -99,7 +99,7 @@ static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include
|
||||
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
|
||||
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
|
||||
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
|
||||
static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
|
||||
static void _moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
|
||||
static int _discoverArchiveFormat(ArchiveHandle *AH);
|
||||
|
||||
static void dump_lo_buf(ArchiveHandle *AH);
|
||||
@ -962,15 +962,11 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
|
||||
char *endptr;
|
||||
DumpId id;
|
||||
TocEntry *te;
|
||||
TocEntry *tePrev;
|
||||
|
||||
/* Allocate space for the 'wanted' array, and init it */
|
||||
ropt->idWanted = (bool *) malloc(sizeof(bool) * AH->maxDumpId);
|
||||
memset(ropt->idWanted, 0, sizeof(bool) * AH->maxDumpId);
|
||||
|
||||
/* Set prev entry as head of list */
|
||||
tePrev = AH->toc;
|
||||
|
||||
/* Setup the file */
|
||||
fh = fopen(ropt->tocFile, PG_BINARY_R);
|
||||
if (!fh)
|
||||
@ -985,7 +981,7 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
|
||||
cmnt[0] = '\0';
|
||||
|
||||
/* Ignore if all blank */
|
||||
if (strspn(buf, " \t\r") == strlen(buf))
|
||||
if (strspn(buf, " \t\r\n") == strlen(buf))
|
||||
continue;
|
||||
|
||||
/* Get an ID, check it's valid and not already seen */
|
||||
@ -1003,10 +999,21 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
|
||||
die_horribly(AH, modulename, "could not find entry for ID %d\n",
|
||||
id);
|
||||
|
||||
/* Mark it wanted */
|
||||
ropt->idWanted[id - 1] = true;
|
||||
|
||||
_moveAfter(AH, tePrev, te);
|
||||
tePrev = te;
|
||||
/*
|
||||
* Move each item to the end of the list as it is selected, so that
|
||||
* they are placed in the desired order. Any unwanted items will end
|
||||
* up at the front of the list, which may seem unintuitive but it's
|
||||
* what we need. In an ordinary serial restore that makes no
|
||||
* difference, but in a parallel restore we need to mark unrestored
|
||||
* items' dependencies as satisfied before we start examining
|
||||
* restorable items. Otherwise they could have surprising
|
||||
* side-effects on the order in which restorable items actually get
|
||||
* restored.
|
||||
*/
|
||||
_moveBefore(AH, AH->toc, te);
|
||||
}
|
||||
|
||||
if (fclose(fh) != 0)
|
||||
@ -1439,33 +1446,37 @@ warn_or_die_horribly(ArchiveHandle *AH,
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
||||
static void
|
||||
_moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
|
||||
{
|
||||
/* Unlink te from list */
|
||||
te->prev->next = te->next;
|
||||
te->next->prev = te->prev;
|
||||
|
||||
/* and insert it after "pos" */
|
||||
te->prev = pos;
|
||||
te->next = pos->next;
|
||||
|
||||
pos->next->prev = te;
|
||||
pos->next = te;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
#endif
|
||||
|
||||
static void
|
||||
_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
|
||||
{
|
||||
/* Unlink te from list */
|
||||
te->prev->next = te->next;
|
||||
te->next->prev = te->prev;
|
||||
|
||||
/* and insert it before "pos" */
|
||||
te->prev = pos->prev;
|
||||
te->next = pos;
|
||||
pos->prev->next = te;
|
||||
pos->prev = te;
|
||||
}
|
||||
#endif
|
||||
|
||||
static TocEntry *
|
||||
getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
|
||||
@ -3116,7 +3127,14 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
|
||||
{
|
||||
if (next_work_item->section == SECTION_DATA ||
|
||||
next_work_item->section == SECTION_POST_DATA)
|
||||
break;
|
||||
{
|
||||
teReqs reqs;
|
||||
|
||||
/* If not to be dumped, we can stay in this loop */
|
||||
reqs = _tocEntryRequired(next_work_item, AH->ropt, false);
|
||||
if ((reqs & (REQ_SCHEMA | REQ_DATA)) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
ahlog(AH, 1, "processing item %d %s %s\n",
|
||||
next_work_item->dumpId,
|
||||
|
Loading…
x
Reference in New Issue
Block a user