Do index FSM vacuuming sooner.

In btree and SP-GiST indexes, move the responsibility for calling
IndexFreeSpaceMapVacuum from the vacuumcleanup phase to the bulkdelete
phase, and do it if and only if we found some pages that could be put into
FSM.  As in commit 851a26e26, the idea is to make free pages visible to FSM
searchers sooner when vacuuming very large tables (large enough to need
multiple bulkdelete scans).  This adds more redundant work than that commit
did, since we have to scan the entire index FSM each time rather than being
able to localize what needs to be updated; but it still seems worthwhile.
However, we can buy something back by not touching the FSM at all when
there are no pages that can be put in it.  That will result in slower
recovery from corrupt upper FSM pages in such a scenario, but it doesn't
seem like that's a case we need to optimize for.

Hash indexes don't use FSM at all.  GIN, GiST, and bloom indexes update
FSM during the vacuumcleanup phase not bulkdelete, so that doing something
comparable to this would be a much more invasive change, and it's not clear
it's worth it.  BRIN indexes do things sufficiently differently that this
change doesn't apply to them, either.

Claudio Freire, reviewed by Masahiko Sawada and Jing Wang, some additional
tweaks by me

Discussion: https://postgr.es/m/CAGTBQpYR0uJCNTt3M5GOzBRHo+-GccNO1nCaQ8yEJmZKSW5q1A@mail.gmail.com
This commit is contained in:
Tom Lane 2018-03-30 11:48:17 -04:00
parent 96030f9a48
commit c79f6df75d
2 changed files with 32 additions and 9 deletions

View File

@ -832,9 +832,6 @@ btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
btvacuumscan(info, stats, NULL, NULL, 0);
}
/* Finally, vacuum the FSM */
IndexFreeSpaceMapVacuum(info->index);
/*
* It's quite possible for us to be fooled by concurrent page splits into
* double-counting some index tuples, so disbelieve any total that exceeds
@ -976,6 +973,21 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
MemoryContextDelete(vstate.pagedelcontext);
/*
* If we found any recyclable pages (and recorded them in the FSM), then
* forcibly update the upper-level FSM pages to ensure that searchers can
* find them. It's possible that the pages were also found during
* previous scans and so this is a waste of time, but it's cheap enough
* relative to scanning the index that it shouldn't matter much, and
* making sure that free pages are available sooner not later seems
* worthwhile.
*
* Note that if no recyclable pages exist, we don't bother vacuuming the
* FSM at all.
*/
if (vstate.totFreePages > 0)
IndexFreeSpaceMapVacuum(rel);
/* update statistics */
stats->num_pages = num_pages;
stats->pages_free = vstate.totFreePages;

View File

@ -845,6 +845,21 @@ spgvacuumscan(spgBulkDeleteState *bds)
/* Propagate local lastUsedPage cache to metablock */
SpGistUpdateMetaPage(index);
/*
* If we found any empty pages (and recorded them in the FSM), then
* forcibly update the upper-level FSM pages to ensure that searchers can
* find them. It's possible that the pages were also found during
* previous scans and so this is a waste of time, but it's cheap enough
* relative to scanning the index that it shouldn't matter much, and
* making sure that free pages are available sooner not later seems
* worthwhile.
*
* Note that if no empty pages exist, we don't bother vacuuming the FSM at
* all.
*/
if (bds->stats->pages_deleted > 0)
IndexFreeSpaceMapVacuum(index);
/*
* Truncate index if possible
*
@ -916,7 +931,6 @@ dummy_callback(ItemPointer itemptr, void *state)
IndexBulkDeleteResult *
spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
Relation index = info->index;
spgBulkDeleteState bds;
/* No-op in ANALYZE ONLY mode */
@ -926,8 +940,8 @@ spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
/*
* We don't need to scan the index if there was a preceding bulkdelete
* pass. Otherwise, make a pass that won't delete any live tuples, but
* might still accomplish useful stuff with redirect/placeholder cleanup,
* and in any case will provide stats.
* might still accomplish useful stuff with redirect/placeholder cleanup
* and/or FSM housekeeping, and in any case will provide stats.
*/
if (stats == NULL)
{
@ -940,9 +954,6 @@ spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
spgvacuumscan(&bds);
}
/* Finally, vacuum the FSM */
IndexFreeSpaceMapVacuum(index);
/*
* It's quite possible for us to be fooled by concurrent tuple moves into
* double-counting some index tuples, so disbelieve any total that exceeds