Fix bug in the GiST vacuum's 2nd stage.
authorHeikki Linnakangas <[email protected]>
Fri, 22 Mar 2019 12:11:46 +0000 (14:11 +0200)
committerHeikki Linnakangas <[email protected]>
Fri, 22 Mar 2019 12:11:46 +0000 (14:11 +0200)
We mustn't assume that the IndexVacuumInfo pointer passed to bulkdelete()
stage is still valid in the vacuumcleanup() stage.

Per very pink buildfarm.

src/backend/access/gist/gistvacuum.c

index 28d5ec9ce427423255d2cae6ce7ae824d417580c..e2029d842c03b42ec6d60141c0f966a36691ea7a 100644 (file)
@@ -31,8 +31,6 @@ typedef struct
 {
    IndexBulkDeleteResult stats;    /* must be first */
 
-   IndexVacuumInfo *info;
-
    /*
     * 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
@@ -46,6 +44,7 @@ typedef struct
 /* Working state needed by gistbulkdelete */
 typedef struct
 {
+   IndexVacuumInfo *info;
    GistBulkDeleteResult *stats;
    IndexBulkDeleteCallback callback;
    void       *callback_state;
@@ -56,8 +55,9 @@ static void gistvacuumscan(IndexVacuumInfo *info, GistBulkDeleteResult *stats,
               IndexBulkDeleteCallback callback, void *callback_state);
 static void gistvacuumpage(GistVacState *vstate, BlockNumber blkno,
               BlockNumber orig_blkno);
-static void gistvacuum_delete_empty_pages(GistBulkDeleteResult *stats);
-static bool gistdeletepage(GistBulkDeleteResult *stats,
+static void gistvacuum_delete_empty_pages(IndexVacuumInfo *info,
+                             GistBulkDeleteResult *stats);
+static bool gistdeletepage(IndexVacuumInfo *info, GistBulkDeleteResult *stats,
               Buffer buffer, OffsetNumber downlink,
               Buffer leafBuffer);
 
@@ -121,7 +121,7 @@ gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
     * If we saw any empty pages, try to unlink them from the tree so that
     * they can be reused.
     */
-   gistvacuum_delete_empty_pages(gist_stats);
+   gistvacuum_delete_empty_pages(info, gist_stats);
 
    /* we don't need the internal and empty page sets anymore */
    MemoryContextDelete(gist_stats->page_set_context);
@@ -183,7 +183,7 @@ gistvacuumscan(IndexVacuumInfo *info, GistBulkDeleteResult *stats,
    stats->empty_leaf_set = intset_create();
 
    /* Set up info to pass down to gistvacuumpage */
-   stats->info = info;
+   vstate.info = info;
    vstate.stats = stats;
    vstate.callback = callback;
    vstate.callback_state = callback_state;
@@ -269,7 +269,7 @@ static void
 gistvacuumpage(GistVacState *vstate, BlockNumber blkno, BlockNumber orig_blkno)
 {
    GistBulkDeleteResult *stats = vstate->stats;
-   IndexVacuumInfo *info = stats->info;
+   IndexVacuumInfo *info = vstate->info;
    IndexBulkDeleteCallback callback = vstate->callback;
    void       *callback_state = vstate->callback_state;
    Relation    rel = info->index;
@@ -456,9 +456,8 @@ restart:
  * Scan all internal pages, and try to delete their empty child pages.
  */
 static void
-gistvacuum_delete_empty_pages(GistBulkDeleteResult *stats)
+gistvacuum_delete_empty_pages(IndexVacuumInfo *info, GistBulkDeleteResult *stats)
 {
-   IndexVacuumInfo *info = stats->info;
    Relation    rel = info->index;
    BlockNumber empty_pages_remaining;
    uint64      blkno;
@@ -552,7 +551,9 @@ gistvacuum_delete_empty_pages(GistBulkDeleteResult *stats)
            gistcheckpage(rel, leafbuf);
 
            LockBuffer(buffer, GIST_EXCLUSIVE);
-           if (gistdeletepage(stats, buffer, todelete[i] - deleted, leafbuf))
+           if (gistdeletepage(info, stats,
+                              buffer, todelete[i] - deleted,
+                              leafbuf))
                deleted++;
            LockBuffer(buffer, GIST_UNLOCK);
 
@@ -585,7 +586,7 @@ gistvacuum_delete_empty_pages(GistBulkDeleteResult *stats)
  * prevented it.
  */
 static bool
-gistdeletepage(GistBulkDeleteResult *stats,
+gistdeletepage(IndexVacuumInfo *info, GistBulkDeleteResult *stats,
               Buffer parentBuffer, OffsetNumber downlink,
               Buffer leafBuffer)
 {
@@ -661,10 +662,10 @@ gistdeletepage(GistBulkDeleteResult *stats,
    MarkBufferDirty(parentBuffer);
    PageIndexTupleDelete(parentPage, downlink);
 
-   if (RelationNeedsWAL(stats->info->index))
+   if (RelationNeedsWAL(info->index))
        recptr = gistXLogPageDelete(leafBuffer, txid, parentBuffer, downlink);
    else
-       recptr = gistGetFakeLSN(stats->info->index);
+       recptr = gistGetFakeLSN(info->index);
    PageSetLSN(parentPage, recptr);
    PageSetLSN(leafPage, recptr);