Skip to content

Commit f06ef2b

Browse files
committed
Fix WAL redo of FSM truncation. We can't call smgrtruncate() during WAL
replay, because it tries to XLogInsert().
1 parent 6ca1b1c commit f06ef2b

File tree

1 file changed

+44
-13
lines changed

1 file changed

+44
-13
lines changed

src/backend/storage/freespace/freespace.c

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.62 2008/09/30 14:15:58 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.63 2008/10/01 08:12:14 heikki Exp $
1212
*
1313
*
1414
* NOTES:
@@ -123,6 +123,8 @@ static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
123123
static BlockNumber fsm_search(Relation rel, uint8 min_cat);
124124
static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof);
125125

126+
static void fsm_redo_truncate(xl_fsm_truncate *xlrec);
127+
126128

127129
/******** Public API ********/
128130

@@ -281,7 +283,7 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
281283
* record, but that's not enough to zero out the last remaining FSM page.
282284
* (if we didn't need to zero out anything above, we can skip this)
283285
*/
284-
if (!rel->rd_istemp && !InRecovery && first_removed_slot != 0)
286+
if (!rel->rd_istemp && first_removed_slot != 0)
285287
{
286288
xl_fsm_truncate xlrec;
287289
XLogRecData rdata;
@@ -310,8 +312,8 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
310312
* Need to invalidate the relcache entry, because rd_fsm_nblocks_cache
311313
* seen by other backends is no longer valid.
312314
*/
313-
if (!InRecovery)
314-
CacheInvalidateRelcache(rel);
315+
CacheInvalidateRelcache(rel);
316+
315317
rel->rd_fsm_nblocks_cache = new_nfsmblocks;
316318
}
317319

@@ -762,6 +764,43 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p)
762764

763765
/****** WAL-logging ******/
764766

767+
static void
768+
fsm_redo_truncate(xl_fsm_truncate *xlrec)
769+
{
770+
FSMAddress first_removed_address;
771+
uint16 first_removed_slot;
772+
BlockNumber fsmblk;
773+
Buffer buf;
774+
775+
/* Get the location in the FSM of the first removed heap block */
776+
first_removed_address = fsm_get_location(xlrec->nheapblocks,
777+
&first_removed_slot);
778+
fsmblk = fsm_logical_to_physical(first_removed_address);
779+
780+
/*
781+
* Zero out the tail of the last remaining FSM page. We rely on the
782+
* replay of the smgr truncation record to remove completely unused
783+
* pages.
784+
*/
785+
buf = XLogReadBufferWithFork(xlrec->node, FSM_FORKNUM, fsmblk, false);
786+
if (BufferIsValid(buf))
787+
{
788+
fsm_truncate_avail(BufferGetPage(buf), first_removed_slot);
789+
MarkBufferDirty(buf);
790+
UnlockReleaseBuffer(buf);
791+
}
792+
else
793+
{
794+
/*
795+
* The page doesn't exist. Because FSM extensions are not WAL-logged,
796+
* it's normal to have a truncation record for a page that doesn't
797+
* exist. Tell xlogutils.c not to PANIC at the end of recovery
798+
* because of the missing page
799+
*/
800+
XLogTruncateRelation(xlrec->node, FSM_FORKNUM, fsmblk);
801+
}
802+
}
803+
765804
void
766805
fsm_redo(XLogRecPtr lsn, XLogRecord *record)
767806
{
@@ -770,15 +809,7 @@ fsm_redo(XLogRecPtr lsn, XLogRecord *record)
770809
switch (info)
771810
{
772811
case XLOG_FSM_TRUNCATE:
773-
{
774-
xl_fsm_truncate *xlrec;
775-
Relation rel;
776-
777-
xlrec = (xl_fsm_truncate *) XLogRecGetData(record);
778-
rel = CreateFakeRelcacheEntry(xlrec->node);
779-
FreeSpaceMapTruncateRel(rel, xlrec->nheapblocks);
780-
FreeFakeRelcacheEntry(rel);
781-
}
812+
fsm_redo_truncate((xl_fsm_truncate *) XLogRecGetData(record));
782813
break;
783814
default:
784815
elog(PANIC, "fsm_redo: unknown op code %u", info);

0 commit comments

Comments
 (0)