mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Fix WAL redo of FSM truncation. We can't call smgrtruncate() during WAL
replay, because it tries to XLogInsert().
This commit is contained in:
parent
6ca1b1cd95
commit
f06ef2bede
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.62 2008/09/30 14:15:58 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.63 2008/10/01 08:12:14 heikki Exp $
|
||||
*
|
||||
*
|
||||
* NOTES:
|
||||
@ -123,6 +123,8 @@ static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
|
||||
static BlockNumber fsm_search(Relation rel, uint8 min_cat);
|
||||
static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof);
|
||||
|
||||
static void fsm_redo_truncate(xl_fsm_truncate *xlrec);
|
||||
|
||||
|
||||
/******** Public API ********/
|
||||
|
||||
@ -281,7 +283,7 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
|
||||
* record, but that's not enough to zero out the last remaining FSM page.
|
||||
* (if we didn't need to zero out anything above, we can skip this)
|
||||
*/
|
||||
if (!rel->rd_istemp && !InRecovery && first_removed_slot != 0)
|
||||
if (!rel->rd_istemp && first_removed_slot != 0)
|
||||
{
|
||||
xl_fsm_truncate xlrec;
|
||||
XLogRecData rdata;
|
||||
@ -310,8 +312,8 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
|
||||
* Need to invalidate the relcache entry, because rd_fsm_nblocks_cache
|
||||
* seen by other backends is no longer valid.
|
||||
*/
|
||||
if (!InRecovery)
|
||||
CacheInvalidateRelcache(rel);
|
||||
CacheInvalidateRelcache(rel);
|
||||
|
||||
rel->rd_fsm_nblocks_cache = new_nfsmblocks;
|
||||
}
|
||||
|
||||
@ -762,6 +764,43 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p)
|
||||
|
||||
/****** WAL-logging ******/
|
||||
|
||||
static void
|
||||
fsm_redo_truncate(xl_fsm_truncate *xlrec)
|
||||
{
|
||||
FSMAddress first_removed_address;
|
||||
uint16 first_removed_slot;
|
||||
BlockNumber fsmblk;
|
||||
Buffer buf;
|
||||
|
||||
/* Get the location in the FSM of the first removed heap block */
|
||||
first_removed_address = fsm_get_location(xlrec->nheapblocks,
|
||||
&first_removed_slot);
|
||||
fsmblk = fsm_logical_to_physical(first_removed_address);
|
||||
|
||||
/*
|
||||
* Zero out the tail of the last remaining FSM page. We rely on the
|
||||
* replay of the smgr truncation record to remove completely unused
|
||||
* pages.
|
||||
*/
|
||||
buf = XLogReadBufferWithFork(xlrec->node, FSM_FORKNUM, fsmblk, false);
|
||||
if (BufferIsValid(buf))
|
||||
{
|
||||
fsm_truncate_avail(BufferGetPage(buf), first_removed_slot);
|
||||
MarkBufferDirty(buf);
|
||||
UnlockReleaseBuffer(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* The page doesn't exist. Because FSM extensions are not WAL-logged,
|
||||
* it's normal to have a truncation record for a page that doesn't
|
||||
* exist. Tell xlogutils.c not to PANIC at the end of recovery
|
||||
* because of the missing page
|
||||
*/
|
||||
XLogTruncateRelation(xlrec->node, FSM_FORKNUM, fsmblk);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fsm_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
@ -770,15 +809,7 @@ fsm_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
switch (info)
|
||||
{
|
||||
case XLOG_FSM_TRUNCATE:
|
||||
{
|
||||
xl_fsm_truncate *xlrec;
|
||||
Relation rel;
|
||||
|
||||
xlrec = (xl_fsm_truncate *) XLogRecGetData(record);
|
||||
rel = CreateFakeRelcacheEntry(xlrec->node);
|
||||
FreeSpaceMapTruncateRel(rel, xlrec->nheapblocks);
|
||||
FreeFakeRelcacheEntry(rel);
|
||||
}
|
||||
fsm_redo_truncate((xl_fsm_truncate *) XLogRecGetData(record));
|
||||
break;
|
||||
default:
|
||||
elog(PANIC, "fsm_redo: unknown op code %u", info);
|
||||
|
Loading…
Reference in New Issue
Block a user