diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 5016181fd7..d024b4fa59 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8056,6 +8056,7 @@ heap_xlog_clean(XLogReaderState *record) xl_heap_clean *xlrec = (xl_heap_clean *) XLogRecGetData(record); Buffer buffer; Size freespace = 0; + bool know_freespace = false; RelFileNode rnode; BlockNumber blkno; XLogRedoAction action; @@ -8107,8 +8108,6 @@ heap_xlog_clean(XLogReaderState *record) nowdead, ndead, nowunused, nunused); - freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */ - /* * Note: we don't worry about updating the page's prunability hints. * At worst this will cause an extra prune cycle to occur soon. @@ -8118,16 +8117,16 @@ heap_xlog_clean(XLogReaderState *record) MarkBufferDirty(buffer); } if (BufferIsValid(buffer)) + { + freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */ + know_freespace = true; UnlockReleaseBuffer(buffer); + } /* - * Update the FSM as well. - * - * XXX: Don't do this if the page was restored from full page image. We - * don't bother to update the FSM in that case, it doesn't need to be - * totally accurate anyway. + * Update the FSM as well, if we can. */ - if (action == BLK_NEEDS_REDO) + if (know_freespace) XLogRecordPageWithFreeSpace(rnode, blkno, freespace); } @@ -8149,6 +8148,8 @@ heap_xlog_visible(XLogReaderState *record) Page page; RelFileNode rnode; BlockNumber blkno; + Size space; + bool know_freespace = false; XLogRedoAction action; XLogRecGetBlockTag(record, 1, &rnode, NULL, &blkno); @@ -8201,8 +8202,31 @@ heap_xlog_visible(XLogReaderState *record) * wal_log_hints enabled.) */ } + if (BufferIsValid(buffer)) + { + space = PageGetFreeSpace(BufferGetPage(buffer)); /* for later */ + know_freespace = true; UnlockReleaseBuffer(buffer); + } + + /* + * Since FSM is not WAL-logged and only updated heuristicaly, it easily + * becomes stale in standbys. If the standby is later promoted and runs + * VACUUM, it will skip updating individual free space figures for pages + * that became frozen, which is troublesome when FreeSpaceMapVacuum + * propagates too optimistic free space values to upper FSM layers; later + * inserters try to use such pages only to find out that they are + * unusable. This can cause long stalls when there are many such pages. + * + * Forestall those problems by updating FSM's idea about a page that is + * becoming frozen. + * + * Do this regardless of full-page image being applied, since the FSM data + * is not in the page anyway. + */ + if ((xlrec->flags & VISIBILITYMAP_ALL_FROZEN) && know_freespace) + XLogRecordPageWithFreeSpace(rnode, blkno, space); /* * Even if we skipped the heap page update due to the LSN interlock, it's