diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index bf754ea..aee7904 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -24,17 +24,13 @@ #include "storage/lmgr.h" #include "utils/memutils.h" -/* - * State kept across vacuum stages. - */ typedef struct { - IndexBulkDeleteResult stats; /* must be first */ + IndexBulkDeleteResult *stats; /* kept across vacuum stages. */ /* - * These are used to memorize all internal and empty leaf pages in the 1st - * vacuum stage. They are used in the 2nd stage, to delete all the empty - * pages. + * These are used to memorize all internal and empty leaf pages. They are + * used for deleting all the empty pages. */ IntegerSet *internal_page_set; IntegerSet *empty_leaf_set; @@ -61,7 +57,7 @@ static bool gistdeletepage(IndexVacuumInfo *info, GistBulkDeleteResult *stats, Buffer buffer, OffsetNumber downlink, Buffer leafBuffer); -/* allocate the 'stats' struct that's kept over vacuum stages */ +/* allocate the gist 'stats' struct */ static GistBulkDeleteResult * create_GistBulkDeleteResult(void) { @@ -83,15 +79,28 @@ IndexBulkDeleteResult * gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state) { - GistBulkDeleteResult *gist_stats = (GistBulkDeleteResult *) stats; + GistBulkDeleteResult *gist_stats; + + gist_stats = create_GistBulkDeleteResult(); /* allocate stats if first time through, else re-use existing struct */ - if (gist_stats == NULL) - gist_stats = create_GistBulkDeleteResult(); + if (stats == NULL) + stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); + + gist_stats->stats = stats; gistvacuumscan(info, gist_stats, callback, callback_state); - return (IndexBulkDeleteResult *) gist_stats; + /* + * If we saw any empty pages, try to unlink them from the tree so that + * they can be reused. + */ + gistvacuum_delete_empty_pages(info, gist_stats); + + /* we don't need the internal and empty page sets anymore */ + MemoryContextDelete(gist_stats->page_set_context); + + return stats; } /* @@ -100,8 +109,6 @@ gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteResult * gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { - GistBulkDeleteResult *gist_stats = (GistBulkDeleteResult *) stats; - /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) return stats; @@ -111,23 +118,23 @@ gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) * stats from the latest gistbulkdelete call. If it wasn't called, we * still need to do a pass over the index, to obtain index statistics. */ - if (gist_stats == NULL) + if (stats == NULL) { - gist_stats = create_GistBulkDeleteResult(); + GistBulkDeleteResult *gist_stats = create_GistBulkDeleteResult(); + + stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); + gist_stats->stats = stats; gistvacuumscan(info, gist_stats, NULL, NULL); - } - /* - * If we saw any empty pages, try to unlink them from the tree so that - * they can be reused. - */ - gistvacuum_delete_empty_pages(info, gist_stats); + /* + * If we saw any empty pages, try to unlink them from the tree so that + * they can be reused. + */ + gistvacuum_delete_empty_pages(info, gist_stats); - /* we don't need the internal and empty page sets anymore */ - MemoryContextDelete(gist_stats->page_set_context); - gist_stats->page_set_context = NULL; - gist_stats->internal_page_set = NULL; - gist_stats->empty_leaf_set = NULL; + /* we don't need the internal and empty page sets anymore */ + MemoryContextDelete(gist_stats->page_set_context); + } /* * It's quite possible for us to be fooled by concurrent page splits into @@ -137,18 +144,18 @@ gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) */ if (!info->estimated_count) { - if (gist_stats->stats.num_index_tuples > info->num_heap_tuples) - gist_stats->stats.num_index_tuples = info->num_heap_tuples; + if (stats->num_index_tuples > info->num_heap_tuples) + stats->num_index_tuples = info->num_heap_tuples; } - return (IndexBulkDeleteResult *) gist_stats; + return stats; } /* * gistvacuumscan --- scan the index for VACUUMing purposes * * This scans the index for leaf tuples that are deletable according to the - * vacuum callback, and updates the stats. Both btbulkdelete and + * vacuum callback, and updates the stats-> Both btbulkdelete and * btvacuumcleanup invoke this (the latter only if no btbulkdelete call * occurred). * @@ -174,11 +181,11 @@ gistvacuumscan(IndexVacuumInfo *info, GistBulkDeleteResult *stats, * Reset counts that will be incremented during the scan; needed in case * of multiple scans during a single VACUUM command. */ - stats->stats.estimated_count = false; - stats->stats.num_index_tuples = 0; - stats->stats.pages_deleted = 0; - stats->stats.pages_free = 0; - MemoryContextReset(stats->page_set_context); + stats->stats->estimated_count = false; + stats->stats->num_index_tuples = 0; + stats->stats->pages_deleted = 0; + stats->stats->pages_free = 0; + stats->internal_page_set = intset_create(); stats->empty_leaf_set = intset_create(); @@ -247,11 +254,11 @@ gistvacuumscan(IndexVacuumInfo *info, GistBulkDeleteResult *stats, * Note that if no recyclable pages exist, we don't bother vacuuming the * FSM at all. */ - if (stats->stats.pages_free > 0) + if (stats->stats->pages_free > 0) IndexFreeSpaceMapVacuum(rel); /* update statistics */ - stats->stats.num_pages = num_pages; + stats->stats->num_pages = num_pages; } /* @@ -297,13 +304,13 @@ restart: { /* Okay to recycle this page */ RecordFreeIndexPage(rel, blkno); - stats->stats.pages_free++; - stats->stats.pages_deleted++; + stats->stats->pages_free++; + stats->stats->pages_deleted++; } else if (GistPageIsDeleted(page)) { /* Already deleted, but can't recycle yet */ - stats->stats.pages_deleted++; + stats->stats->pages_deleted++; } else if (GistPageIsLeaf(page)) { @@ -378,7 +385,7 @@ restart: END_CRIT_SECTION(); - stats->stats.tuples_removed += ntodelete; + stats->stats->tuples_removed += ntodelete; /* must recompute maxoff */ maxoff = PageGetMaxOffsetNumber(page); } @@ -398,7 +405,7 @@ restart: intset_add_member(stats->empty_leaf_set, blkno); } else - stats->stats.num_index_tuples += nremain; + stats->stats->num_index_tuples += nremain; } else { @@ -563,7 +570,7 @@ gistvacuum_delete_empty_pages(IndexVacuumInfo *info, GistBulkDeleteResult *stats ReleaseBuffer(buffer); /* update stats */ - stats->stats.pages_removed += deleted; + stats->stats->pages_removed += deleted; /* * We can stop the scan as soon as we have seen the downlinks, even if @@ -655,7 +662,7 @@ gistdeletepage(IndexVacuumInfo *info, GistBulkDeleteResult *stats, /* mark the page as deleted */ MarkBufferDirty(leafBuffer); GistPageSetDeleted(leafPage, txid); - stats->stats.pages_deleted++; + stats->stats->pages_deleted++; /* remove the downlink from the parent */ MarkBufferDirty(parentBuffer);