Thanks to visit codestin.com
Credit goes to github.com

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)