mirror of
https://github.com/postgres/postgres.git
synced 2025-05-15 19:15:29 +03: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
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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:
|
* 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 BlockNumber fsm_search(Relation rel, uint8 min_cat);
|
||||||
static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof);
|
static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof);
|
||||||
|
|
||||||
|
static void fsm_redo_truncate(xl_fsm_truncate *xlrec);
|
||||||
|
|
||||||
|
|
||||||
/******** Public API ********/
|
/******** 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.
|
* 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 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;
|
xl_fsm_truncate xlrec;
|
||||||
XLogRecData rdata;
|
XLogRecData rdata;
|
||||||
@ -310,8 +312,8 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
|
|||||||
* Need to invalidate the relcache entry, because rd_fsm_nblocks_cache
|
* Need to invalidate the relcache entry, because rd_fsm_nblocks_cache
|
||||||
* seen by other backends is no longer valid.
|
* seen by other backends is no longer valid.
|
||||||
*/
|
*/
|
||||||
if (!InRecovery)
|
CacheInvalidateRelcache(rel);
|
||||||
CacheInvalidateRelcache(rel);
|
|
||||||
rel->rd_fsm_nblocks_cache = new_nfsmblocks;
|
rel->rd_fsm_nblocks_cache = new_nfsmblocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,6 +764,43 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p)
|
|||||||
|
|
||||||
/****** WAL-logging ******/
|
/****** 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
|
void
|
||||||
fsm_redo(XLogRecPtr lsn, XLogRecord *record)
|
fsm_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||||
{
|
{
|
||||||
@ -770,15 +809,7 @@ fsm_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
switch (info)
|
switch (info)
|
||||||
{
|
{
|
||||||
case XLOG_FSM_TRUNCATE:
|
case XLOG_FSM_TRUNCATE:
|
||||||
{
|
fsm_redo_truncate((xl_fsm_truncate *) XLogRecGetData(record));
|
||||||
xl_fsm_truncate *xlrec;
|
|
||||||
Relation rel;
|
|
||||||
|
|
||||||
xlrec = (xl_fsm_truncate *) XLogRecGetData(record);
|
|
||||||
rel = CreateFakeRelcacheEntry(xlrec->node);
|
|
||||||
FreeSpaceMapTruncateRel(rel, xlrec->nheapblocks);
|
|
||||||
FreeFakeRelcacheEntry(rel);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(PANIC, "fsm_redo: unknown op code %u", info);
|
elog(PANIC, "fsm_redo: unknown op code %u", info);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user