From e95680832854cf300e64c10de9cc2f586df558e8 Mon Sep 17 00:00:00 2001 From: Teodor Sigaev Date: Mon, 7 Sep 2015 16:24:01 +0300 Subject: [PATCH] Add pages deleted from pending list to FSM Add pages deleted from GIN's pending list during cleanup to free space map immediately. Clean up process could be initiated by ordinary insert but adding page to FSM might occur only at vacuum. On some workload like never-vacuumed insert-only tables it could cause a huge bloat. Jeff Janes --- src/backend/access/gin/ginfast.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c index ae446653a9..fa8d8a756e 100644 --- a/src/backend/access/gin/ginfast.c +++ b/src/backend/access/gin/ginfast.c @@ -24,6 +24,7 @@ #include "miscadmin.h" #include "utils/memutils.h" #include "utils/rel.h" +#include "storage/indexfsm.h" /* GUC parameter */ int gin_pending_list_limit = 0; @@ -521,10 +522,12 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead, int64 nDeletedHeapTuples = 0; ginxlogDeleteListPages data; Buffer buffers[GIN_NDELETE_AT_ONCE]; + BlockNumber freespace[GIN_NDELETE_AT_ONCE]; data.ndeleted = 0; while (data.ndeleted < GIN_NDELETE_AT_ONCE && blknoToDelete != newHead) { + freespace[data.ndeleted] = blknoToDelete; buffers[data.ndeleted] = ReadBuffer(index, blknoToDelete); LockBuffer(buffers[data.ndeleted], GIN_EXCLUSIVE); page = BufferGetPage(buffers[data.ndeleted]); @@ -609,6 +612,10 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead, UnlockReleaseBuffer(buffers[i]); END_CRIT_SECTION(); + + for (i = 0; i < data.ndeleted; i++) + RecordFreeIndexPage(index, freespace[i]); + } while (blknoToDelete != newHead); return false; @@ -744,6 +751,7 @@ ginInsertCleanup(GinState *ginstate, BuildAccumulator accum; KeyArray datums; BlockNumber blkno; + bool fsm_vac = false; metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO); LockBuffer(metabuffer, GIN_SHARE); @@ -793,6 +801,7 @@ ginInsertCleanup(GinState *ginstate, { /* another cleanup process is running concurrently */ UnlockReleaseBuffer(buffer); + fsm_vac = false; break; } @@ -857,6 +866,7 @@ ginInsertCleanup(GinState *ginstate, /* another cleanup process is running concurrently */ UnlockReleaseBuffer(buffer); LockBuffer(metabuffer, GIN_UNLOCK); + fsm_vac = false; break; } @@ -895,9 +905,13 @@ ginInsertCleanup(GinState *ginstate, { /* another cleanup process is running concurrently */ LockBuffer(metabuffer, GIN_UNLOCK); + fsm_vac = false; break; } + /* At this point, some pending pages have been freed up */ + fsm_vac = true; + Assert(blkno == metadata->head); LockBuffer(metabuffer, GIN_UNLOCK); @@ -931,6 +945,15 @@ ginInsertCleanup(GinState *ginstate, ReleaseBuffer(metabuffer); + /* + * As pending list pages can have a high churn rate, it is + * desirable to recycle them immediately to the FreeSpace Map when + * ordinary backends clean the list. + */ + if (fsm_vac && !vac_delay) + IndexFreeSpaceMapVacuum(index); + + /* Clean up temporary space */ MemoryContextSwitchTo(oldCtx); MemoryContextDelete(opCtx);