Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix broken cleanup interlock for GIN pending list.
authorRobert Haas <rhaas@postgresql.org>
Thu, 16 Nov 2017 19:19:27 +0000 (14:19 -0500)
committerRobert Haas <rhaas@postgresql.org>
Thu, 16 Nov 2017 20:24:19 +0000 (15:24 -0500)
The pending list must (for correctness) always be cleaned up by vacuum, and
should (for the avoidance of surprising behavior) always be cleaned up
by an explicit call to gin_clean_pending_list, but cleanup is optional
when inserting.  The old logic got this backward: cleanup was forced
if (stats == NULL), but that's going to be *false* when vacuuming and
*true* for inserts.

Masahiko Sawada, reviewed by me.

Discussion: http://postgr.es/m/CAD21AoBLUSyiYKnTYtSAbC+F=XDjiaBrOUEGK+zUXdQ8owfPKw@mail.gmail.com

src/backend/access/gin/ginfast.c
src/backend/access/gin/ginvacuum.c
src/include/access/gin_private.h

index 59e435465acba6883f71d3124a889c7be5949cab..ff610ef218439c8e03dbdf3ab720cc62881cf6f7 100644 (file)
@@ -440,8 +440,12 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
 
    END_CRIT_SECTION();
 
+   /*
+    * Since it could contend with concurrent cleanup process we cleanup
+    * pending list not forcibly.
+    */
    if (needCleanup)
-       ginInsertCleanup(ginstate, false, true, NULL);
+       ginInsertCleanup(ginstate, false, true, false, NULL);
 }
 
 /*
@@ -727,7 +731,8 @@ processPendingPage(BuildAccumulator *accum, KeyArray *ka,
  */
 void
 ginInsertCleanup(GinState *ginstate, bool full_clean,
-                bool fill_fsm, IndexBulkDeleteResult *stats)
+                bool fill_fsm, bool forceCleanup,
+                IndexBulkDeleteResult *stats)
 {
    Relation    index = ginstate->index;
    Buffer      metabuffer,
@@ -744,7 +749,6 @@ ginInsertCleanup(GinState *ginstate, bool full_clean,
    bool        cleanupFinish = false;
    bool        fsm_vac = false;
    Size        workMemory;
-   bool        inVacuum = (stats == NULL);
 
    /*
     * We would like to prevent concurrent cleanup process. For that we will
@@ -753,7 +757,7 @@ ginInsertCleanup(GinState *ginstate, bool full_clean,
     * insertion into pending list
     */
 
-   if (inVacuum)
+   if (forceCleanup)
    {
        /*
         * We are called from [auto]vacuum/analyze or gin_clean_pending_list()
@@ -1016,7 +1020,7 @@ gin_clean_pending_list(PG_FUNCTION_ARGS)
 
    memset(&stats, 0, sizeof(stats));
    initGinState(&ginstate, indexRel);
-   ginInsertCleanup(&ginstate, true, true, &stats);
+   ginInsertCleanup(&ginstate, true, true, true, &stats);
 
    index_close(indexRel, AccessShareLock);
 
index 31425e9963e583c789d442897ceab03510bddba5..d3e4a1776701dc7998aa22672ebd2570e8ac3bc8 100644 (file)
@@ -570,7 +570,7 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
         * and cleanup any pending inserts
         */
        ginInsertCleanup(&gvs.ginstate, !IsAutoVacuumWorkerProcess(),
-                        false, stats);
+                        false, true, stats);
    }
 
    /* we'll re-count the tuples each time */
@@ -683,7 +683,7 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
        if (IsAutoVacuumWorkerProcess())
        {
            initGinState(&ginstate, index);
-           ginInsertCleanup(&ginstate, false, true, stats);
+           ginInsertCleanup(&ginstate, false, true, true, stats);
        }
        return stats;
    }
@@ -697,7 +697,7 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
        stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
        initGinState(&ginstate, index);
        ginInsertCleanup(&ginstate, !IsAutoVacuumWorkerProcess(),
-                        false, stats);
+                        false, true, stats);
    }
 
    memset(&idxStat, 0, sizeof(idxStat));
index adfdb0c6d9c2517e5e4a324b604808526c631382..f57ba5594c2265f10a55f1019ecff51979796675 100644 (file)
@@ -439,7 +439,7 @@ extern void ginHeapTupleFastCollect(GinState *ginstate,
                        OffsetNumber attnum, Datum value, bool isNull,
                        ItemPointer ht_ctid);
 extern void ginInsertCleanup(GinState *ginstate, bool full_clean,
-                bool fill_fsm, IndexBulkDeleteResult *stats);
+                bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats);
 
 /* ginpostinglist.c */