Commit 19c8dc83 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Unite ReadBufferWithFork, ReadBufferWithStrategy, and ZeroOrReadBuffer

functions into one ReadBufferExtended function, that takes the strategy
and mode as argument. There's three modes, RBM_NORMAL which is the default
used by plain ReadBuffer(), RBM_ZERO, which replaces ZeroOrReadBuffer, and
a new mode RBM_ZERO_ON_ERROR, which allows callers to read corrupt pages
without throwing an error. The FSM needs the new mode to recover from
corrupt pages, which could happend if we crash after extending an FSM file,
and the new page is "torn".

Add fork number to some error messages in bufmgr.c, that still lacked it.
parent 29077051
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Copyright (c) 2007-2008, PostgreSQL Global Development Group * Copyright (c) 2007-2008, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/contrib/pageinspect/rawpage.c,v 1.8 2008/10/06 14:13:17 heikki Exp $ * $PostgreSQL: pgsql/contrib/pageinspect/rawpage.c,v 1.9 2008/10/31 15:04:59 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -85,7 +85,7 @@ get_raw_page(PG_FUNCTION_ARGS) ...@@ -85,7 +85,7 @@ get_raw_page(PG_FUNCTION_ARGS)
/* Take a verbatim copy of the page */ /* Take a verbatim copy of the page */
buf = ReadBufferWithFork(rel, forknum, blkno); buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL, NULL);
LockBuffer(buf, BUFFER_LOCK_SHARE); LockBuffer(buf, BUFFER_LOCK_SHARE);
memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ); memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
......
...@@ -8,7 +8,7 @@ ...@@ -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/access/gin/ginvacuum.c,v 1.23 2008/10/06 08:04:11 heikki Exp $ * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.24 2008/10/31 15:04:59 heikki Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -155,10 +155,14 @@ xlogVacuumPage(Relation index, Buffer buffer) ...@@ -155,10 +155,14 @@ xlogVacuumPage(Relation index, Buffer buffer)
static bool static bool
ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer) ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer)
{ {
Buffer buffer = ReadBufferWithStrategy(gvs->index, blkno, gvs->strategy); Buffer buffer;
Page page = BufferGetPage(buffer); Page page;
bool hasVoidPage = FALSE; bool hasVoidPage = FALSE;
buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
RBM_NORMAL, gvs->strategy);
page = BufferGetPage(buffer);
/* /*
* We should be sure that we don't concurrent with inserts, insert process * We should be sure that we don't concurrent with inserts, insert process
* never release root page until end (but it can unlock it and lock * never release root page until end (but it can unlock it and lock
...@@ -241,13 +245,24 @@ static void ...@@ -241,13 +245,24 @@ static void
ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno, ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno,
BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot) BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
{ {
Buffer dBuffer = ReadBufferWithStrategy(gvs->index, deleteBlkno, gvs->strategy); Buffer dBuffer;
Buffer lBuffer = (leftBlkno == InvalidBlockNumber) ? Buffer lBuffer;
InvalidBuffer : ReadBufferWithStrategy(gvs->index, leftBlkno, gvs->strategy); Buffer pBuffer;
Buffer pBuffer = ReadBufferWithStrategy(gvs->index, parentBlkno, gvs->strategy);
Page page, Page page,
parentPage; parentPage;
dBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, deleteBlkno,
RBM_NORMAL, gvs->strategy);
if (leftBlkno != InvalidBlockNumber)
lBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, leftBlkno,
RBM_NORMAL, gvs->strategy);
else
lBuffer = InvalidBuffer;
pBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, parentBlkno,
RBM_NORMAL, gvs->strategy);
LockBuffer(dBuffer, GIN_EXCLUSIVE); LockBuffer(dBuffer, GIN_EXCLUSIVE);
if (!isParentRoot) /* parent is already locked by if (!isParentRoot) /* parent is already locked by
* LockBufferForCleanup() */ * LockBufferForCleanup() */
...@@ -401,7 +416,8 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel ...@@ -401,7 +416,8 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel
me = parent->child; me = parent->child;
} }
buffer = ReadBufferWithStrategy(gvs->index, blkno, gvs->strategy); buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
RBM_NORMAL, gvs->strategy);
page = BufferGetPage(buffer); page = BufferGetPage(buffer);
Assert(GinPageIsData(page)); Assert(GinPageIsData(page));
...@@ -589,7 +605,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) ...@@ -589,7 +605,8 @@ ginbulkdelete(PG_FUNCTION_ARGS)
gvs.strategy = info->strategy; gvs.strategy = info->strategy;
initGinState(&gvs.ginstate, index); initGinState(&gvs.ginstate, index);
buffer = ReadBufferWithStrategy(index, blkno, info->strategy); buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
RBM_NORMAL, info->strategy);
/* find leaf page */ /* find leaf page */
for (;;) for (;;)
...@@ -621,7 +638,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) ...@@ -621,7 +638,8 @@ ginbulkdelete(PG_FUNCTION_ARGS)
Assert(blkno != InvalidBlockNumber); Assert(blkno != InvalidBlockNumber);
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
buffer = ReadBufferWithStrategy(index, blkno, info->strategy); buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
RBM_NORMAL, info->strategy);
} }
/* right now we found leftmost page in entry's BTree */ /* right now we found leftmost page in entry's BTree */
...@@ -663,7 +681,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) ...@@ -663,7 +681,8 @@ ginbulkdelete(PG_FUNCTION_ARGS)
if (blkno == InvalidBlockNumber) /* rightmost page */ if (blkno == InvalidBlockNumber) /* rightmost page */
break; break;
buffer = ReadBufferWithStrategy(index, blkno, info->strategy); buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
RBM_NORMAL, info->strategy);
LockBuffer(buffer, GIN_EXCLUSIVE); LockBuffer(buffer, GIN_EXCLUSIVE);
} }
...@@ -718,7 +737,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -718,7 +737,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
vacuum_delay_point(); vacuum_delay_point();
buffer = ReadBufferWithStrategy(index, blkno, info->strategy); buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
RBM_NORMAL, info->strategy);
LockBuffer(buffer, GIN_SHARE); LockBuffer(buffer, GIN_SHARE);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
......
...@@ -8,7 +8,7 @@ ...@@ -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/access/gist/gistvacuum.c,v 1.38 2008/10/06 08:04:11 heikki Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.39 2008/10/31 15:04:59 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -86,7 +86,8 @@ gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno) ...@@ -86,7 +86,8 @@ gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
Buffer buffer; Buffer buffer;
Page page; Page page;
buffer = ReadBufferWithStrategy(gv->index, blkno, gv->strategy); buffer = ReadBufferExtended(gv->index, MAIN_FORKNUM, blkno, RBM_NORMAL,
gv->strategy);
LockBuffer(buffer, GIST_EXCLUSIVE); LockBuffer(buffer, GIST_EXCLUSIVE);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
...@@ -306,7 +307,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion) ...@@ -306,7 +307,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
vacuum_delay_point(); vacuum_delay_point();
buffer = ReadBufferWithStrategy(gv->index, blkno, gv->strategy); buffer = ReadBufferExtended(gv->index, MAIN_FORKNUM, blkno, RBM_NORMAL,
gv->strategy);
LockBuffer(buffer, GIST_EXCLUSIVE); LockBuffer(buffer, GIST_EXCLUSIVE);
gistcheckpage(gv->index, buffer); gistcheckpage(gv->index, buffer);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
...@@ -595,7 +597,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -595,7 +597,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
vacuum_delay_point(); vacuum_delay_point();
buffer = ReadBufferWithStrategy(rel, blkno, info->strategy); buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
info->strategy);
LockBuffer(buffer, GIST_SHARE); LockBuffer(buffer, GIST_SHARE);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
...@@ -691,13 +694,15 @@ gistbulkdelete(PG_FUNCTION_ARGS) ...@@ -691,13 +694,15 @@ gistbulkdelete(PG_FUNCTION_ARGS)
while (stack) while (stack)
{ {
Buffer buffer = ReadBufferWithStrategy(rel, stack->blkno, info->strategy); Buffer buffer;
Page page; Page page;
OffsetNumber i, OffsetNumber i,
maxoff; maxoff;
IndexTuple idxtuple; IndexTuple idxtuple;
ItemId iid; ItemId iid;
buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
RBM_NORMAL, info->strategy);
LockBuffer(buffer, GIST_SHARE); LockBuffer(buffer, GIST_SHARE);
gistcheckpage(rel, buffer); gistcheckpage(rel, buffer);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.77 2008/09/15 18:43:41 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.78 2008/10/31 15:04:59 heikki Exp $
* *
* NOTES * NOTES
* Postgres hash pages look like ordinary relation pages. The opaque * Postgres hash pages look like ordinary relation pages. The opaque
...@@ -158,7 +158,7 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno) ...@@ -158,7 +158,7 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno)
if (blkno == P_NEW) if (blkno == P_NEW)
elog(ERROR, "hash AM does not use P_NEW"); elog(ERROR, "hash AM does not use P_NEW");
buf = ReadOrZeroBuffer(rel, MAIN_FORKNUM, blkno); buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO, NULL);
LockBuffer(buf, HASH_WRITE); LockBuffer(buf, HASH_WRITE);
...@@ -203,7 +203,7 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno) ...@@ -203,7 +203,7 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno)
BufferGetBlockNumber(buf), blkno); BufferGetBlockNumber(buf), blkno);
} }
else else
buf = ReadOrZeroBuffer(rel, MAIN_FORKNUM, blkno); buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO, NULL);
LockBuffer(buf, HASH_WRITE); LockBuffer(buf, HASH_WRITE);
...@@ -231,7 +231,7 @@ _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, ...@@ -231,7 +231,7 @@ _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno,
if (blkno == P_NEW) if (blkno == P_NEW)
elog(ERROR, "hash AM does not use P_NEW"); elog(ERROR, "hash AM does not use P_NEW");
buf = ReadBufferWithStrategy(rel, blkno, bstrategy); buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
if (access != HASH_NOLOCK) if (access != HASH_NOLOCK)
LockBuffer(buf, access); LockBuffer(buf, access);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.266 2008/10/27 21:50:12 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.267 2008/10/31 15:04:59 heikki Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -205,9 +205,8 @@ heapgetpage(HeapScanDesc scan, BlockNumber page) ...@@ -205,9 +205,8 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
} }
/* read page using selected strategy */ /* read page using selected strategy */
scan->rs_cbuf = ReadBufferWithStrategy(scan->rs_rd, scan->rs_cbuf = ReadBufferExtended(scan->rs_rd, MAIN_FORKNUM, page,
page, RBM_NORMAL, scan->rs_strategy);
scan->rs_strategy);
scan->rs_cblock = page; scan->rs_cblock = page;
if (!scan->rs_pageatatime) if (!scan->rs_pageatatime)
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,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/access/nbtree/nbtree.c,v 1.163 2008/10/06 08:04:11 heikki Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.164 2008/10/31 15:04:59 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -750,7 +750,8 @@ restart: ...@@ -750,7 +750,8 @@ restart:
* recycle all-zero pages, not fail. Also, we want to use a nondefault * recycle all-zero pages, not fail. Also, we want to use a nondefault
* buffer access strategy. * buffer access strategy.
*/ */
buf = ReadBufferWithStrategy(rel, blkno, info->strategy); buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
info->strategy);
LockBuffer(buf, BT_READ); LockBuffer(buf, BT_READ);
page = BufferGetPage(buf); page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.320 2008/10/30 04:06:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.321 2008/10/31 15:04:59 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2897,8 +2897,8 @@ RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn) ...@@ -2897,8 +2897,8 @@ RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn)
memcpy(&bkpb, blk, sizeof(BkpBlock)); memcpy(&bkpb, blk, sizeof(BkpBlock));
blk += sizeof(BkpBlock); blk += sizeof(BkpBlock);
buffer = XLogReadBufferWithFork(bkpb.node, bkpb.fork, bkpb.block, buffer = XLogReadBufferExtended(bkpb.node, bkpb.fork, bkpb.block,
true); RBM_ZERO);
Assert(BufferIsValid(buffer)); Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.59 2008/09/30 10:52:11 heikki Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.60 2008/10/31 15:04:59 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -200,6 +200,20 @@ XLogCheckInvalidPages(void) ...@@ -200,6 +200,20 @@ XLogCheckInvalidPages(void)
invalid_page_tab = NULL; invalid_page_tab = NULL;
} }
/*
* XLogReadBufferExtended
* A shorthand of XLogReadBufferExtended(), for reading from the main
* fork.
*
* For historical reasons, instead of a ReadBufferMode argument, this only
* supports RBM_ZERO (init == true) and RBM_NORMAL (init == false) modes.
*/
Buffer
XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init)
{
return XLogReadBufferExtended(rnode, MAIN_FORKNUM, blkno,
init ? RBM_ZERO : RBM_NORMAL);
}
/* /*
* XLogReadBuffer * XLogReadBuffer
...@@ -211,34 +225,21 @@ XLogCheckInvalidPages(void) ...@@ -211,34 +225,21 @@ XLogCheckInvalidPages(void)
* expect that this is only used during single-process XLOG replay, but * expect that this is only used during single-process XLOG replay, but
* some subroutines such as MarkBufferDirty will complain if we don't.) * some subroutines such as MarkBufferDirty will complain if we don't.)
* *
* If "init" is true then the caller intends to rewrite the page fully * There's some differences in the behavior wrt. the "mode" argument,
* using the info in the XLOG record. In this case we will extend the * compared to ReadBufferExtended:
* relation if needed to make the page exist, and we will not complain about
* the page being "new" (all zeroes); in fact, we usually will supply a
* zeroed buffer without reading the page at all, so as to avoid unnecessary
* failure if the page is present on disk but has corrupt headers.
* *
* If "init" is false then the caller needs the page to be valid already. * In RBM_NORMAL mode, if the page doesn't exist, or contains all-zeroes, we
* If the page doesn't exist or contains zeroes, we return InvalidBuffer. * return InvalidBuffer. In this case the caller should silently skip the
* In this case the caller should silently skip the update on this page. * update on this page. (In this situation, we expect that the page was later
* (In this situation, we expect that the page was later dropped or truncated. * dropped or truncated. If we don't see evidence of that later in the WAL
* If we don't see evidence of that later in the WAL sequence, we'll complain * sequence, we'll complain at the end of WAL replay.)
* at the end of WAL replay.) *
*/ * In RBM_ZERO and RBM_ZERO_ON_ERROR modes, if the page doesn't exist, the
Buffer * relation is extended with all-zeroes pages up to the given block number.
XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init)
{
return XLogReadBufferWithFork(rnode, MAIN_FORKNUM, blkno, init);
}
/*
* XLogReadBufferWithFork
* Like XLogReadBuffer, but for reading other relation forks than
* the main one.
*/ */
Buffer Buffer
XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
BlockNumber blkno, bool init) BlockNumber blkno, ReadBufferMode mode)
{ {
BlockNumber lastblock; BlockNumber lastblock;
Buffer buffer; Buffer buffer;
...@@ -264,12 +265,13 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, ...@@ -264,12 +265,13 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum,
if (blkno < lastblock) if (blkno < lastblock)
{ {
/* page exists in file */ /* page exists in file */
buffer = ReadBufferWithoutRelcache(rnode, false, forknum, blkno, init); buffer = ReadBufferWithoutRelcache(rnode, false, forknum, blkno,
mode, NULL);
} }
else else
{ {
/* hm, page doesn't exist in file */ /* hm, page doesn't exist in file */
if (!init) if (mode == RBM_NORMAL)
{ {
log_invalid_page(rnode, forknum, blkno, false); log_invalid_page(rnode, forknum, blkno, false);
return InvalidBuffer; return InvalidBuffer;
...@@ -283,7 +285,7 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, ...@@ -283,7 +285,7 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum,
if (buffer != InvalidBuffer) if (buffer != InvalidBuffer)
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
buffer = ReadBufferWithoutRelcache(rnode, false, forknum, buffer = ReadBufferWithoutRelcache(rnode, false, forknum,
P_NEW, false); P_NEW, mode, NULL);
lastblock++; lastblock++;
} }
Assert(BufferGetBlockNumber(buffer) == blkno); Assert(BufferGetBlockNumber(buffer) == blkno);
...@@ -291,7 +293,7 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, ...@@ -291,7 +293,7 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum,
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
if (!init) if (mode == RBM_NORMAL)
{ {
/* check that page has been initialized */ /* check that page has been initialized */
Page page = (Page) BufferGetPage(buffer); Page page = (Page) BufferGetPage(buffer);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.125 2008/08/25 22:42:32 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.126 2008/10/31 15:05:00 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -911,7 +911,8 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows, ...@@ -911,7 +911,8 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
* each tuple, but since we aren't doing much work per tuple, the * each tuple, but since we aren't doing much work per tuple, the
* extra lock traffic is probably better avoided. * extra lock traffic is probably better avoided.
*/ */
targbuffer = ReadBufferWithStrategy(onerel, targblock, vac_strategy); targbuffer = ReadBufferExtended(onerel, MAIN_FORKNUM, targblock,
RBM_NORMAL, vac_strategy);
LockBuffer(targbuffer, BUFFER_LOCK_SHARE); LockBuffer(targbuffer, BUFFER_LOCK_SHARE);
targpage = BufferGetPage(targbuffer); targpage = BufferGetPage(targbuffer);
maxoffset = PageGetMaxOffsetNumber(targpage); maxoffset = PageGetMaxOffsetNumber(targpage);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.378 2008/09/30 10:52:12 heikki Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.379 2008/10/31 15:05:00 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1348,7 +1348,8 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, ...@@ -1348,7 +1348,8 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
vacuum_delay_point(); vacuum_delay_point();
buf = ReadBufferWithStrategy(onerel, blkno, vac_strategy); buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno, RBM_NORMAL,
vac_strategy);
page = BufferGetPage(buf); page = BufferGetPage(buf);
/* /*
...@@ -1919,7 +1920,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -1919,7 +1920,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
/* /*
* Process this page of relation. * Process this page of relation.
*/ */
buf = ReadBufferWithStrategy(onerel, blkno, vac_strategy); buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno, RBM_NORMAL,
vac_strategy);
page = BufferGetPage(buf); page = BufferGetPage(buf);
vacpage->offsets_free = 0; vacpage->offsets_free = 0;
...@@ -2173,9 +2175,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2173,9 +2175,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
nextTid = tp.t_data->t_ctid; nextTid = tp.t_data->t_ctid;
priorXmax = HeapTupleHeaderGetXmax(tp.t_data); priorXmax = HeapTupleHeaderGetXmax(tp.t_data);
/* assume block# is OK (see heap_fetch comments) */ /* assume block# is OK (see heap_fetch comments) */
nextBuf = ReadBufferWithStrategy(onerel, nextBuf = ReadBufferExtended(onerel, MAIN_FORKNUM,
ItemPointerGetBlockNumber(&nextTid), ItemPointerGetBlockNumber(&nextTid),
vac_strategy); RBM_NORMAL, vac_strategy);
nextPage = BufferGetPage(nextBuf); nextPage = BufferGetPage(nextBuf);
/* If bogus or unused slot, assume tp is end of chain */ /* If bogus or unused slot, assume tp is end of chain */
nextOffnum = ItemPointerGetOffsetNumber(&nextTid); nextOffnum = ItemPointerGetOffsetNumber(&nextTid);
...@@ -2318,9 +2320,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2318,9 +2320,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
break; /* out of check-all-items loop */ break; /* out of check-all-items loop */
} }
tp.t_self = vtlp->this_tid; tp.t_self = vtlp->this_tid;
Pbuf = ReadBufferWithStrategy(onerel, Pbuf = ReadBufferExtended(onerel, MAIN_FORKNUM,
ItemPointerGetBlockNumber(&(tp.t_self)), ItemPointerGetBlockNumber(&(tp.t_self)),
vac_strategy); RBM_NORMAL, vac_strategy);
Ppage = BufferGetPage(Pbuf); Ppage = BufferGetPage(Pbuf);
Pitemid = PageGetItemId(Ppage, Pitemid = PageGetItemId(Ppage,
ItemPointerGetOffsetNumber(&(tp.t_self))); ItemPointerGetOffsetNumber(&(tp.t_self)));
...@@ -2402,14 +2404,14 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2402,14 +2404,14 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
/* Get page to move from */ /* Get page to move from */
tuple.t_self = vtmove[ti].tid; tuple.t_self = vtmove[ti].tid;
Cbuf = ReadBufferWithStrategy(onerel, Cbuf = ReadBufferExtended(onerel, MAIN_FORKNUM,
ItemPointerGetBlockNumber(&(tuple.t_self)), ItemPointerGetBlockNumber(&(tuple.t_self)),
vac_strategy); RBM_NORMAL, vac_strategy);
/* Get page to move to */ /* Get page to move to */
dst_buffer = ReadBufferWithStrategy(onerel, dst_buffer = ReadBufferExtended(onerel, MAIN_FORKNUM,
destvacpage->blkno, destvacpage->blkno,
vac_strategy); RBM_NORMAL, vac_strategy);
LockBuffer(dst_buffer, BUFFER_LOCK_EXCLUSIVE); LockBuffer(dst_buffer, BUFFER_LOCK_EXCLUSIVE);
if (dst_buffer != Cbuf) if (dst_buffer != Cbuf)
...@@ -2502,9 +2504,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2502,9 +2504,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
if (i == num_fraged_pages) if (i == num_fraged_pages)
break; /* can't move item anywhere */ break; /* can't move item anywhere */
dst_vacpage = fraged_pages->pagedesc[i]; dst_vacpage = fraged_pages->pagedesc[i];
dst_buffer = ReadBufferWithStrategy(onerel, dst_buffer = ReadBufferExtended(onerel, MAIN_FORKNUM,
dst_vacpage->blkno, dst_vacpage->blkno,
vac_strategy); RBM_NORMAL, vac_strategy);
LockBuffer(dst_buffer, BUFFER_LOCK_EXCLUSIVE); LockBuffer(dst_buffer, BUFFER_LOCK_EXCLUSIVE);
dst_page = BufferGetPage(dst_buffer); dst_page = BufferGetPage(dst_buffer);
/* if this page was not used before - clean it */ /* if this page was not used before - clean it */
...@@ -2681,9 +2683,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2681,9 +2683,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
Page page; Page page;
/* this page was not used as a move target, so must clean it */ /* this page was not used as a move target, so must clean it */
buf = ReadBufferWithStrategy(onerel, buf = ReadBufferExtended(onerel, MAIN_FORKNUM, (*curpage)->blkno,
(*curpage)->blkno, RBM_NORMAL, vac_strategy);
vac_strategy);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
if (!PageIsEmpty(page)) if (!PageIsEmpty(page))
...@@ -2770,7 +2771,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2770,7 +2771,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
int uncnt = 0; int uncnt = 0;
int num_tuples = 0; int num_tuples = 0;
buf = ReadBufferWithStrategy(onerel, vacpage->blkno, vac_strategy); buf = ReadBufferExtended(onerel, MAIN_FORKNUM, vacpage->blkno,
RBM_NORMAL, vac_strategy);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
maxoff = PageGetMaxOffsetNumber(page); maxoff = PageGetMaxOffsetNumber(page);
...@@ -3150,7 +3152,8 @@ update_hint_bits(Relation rel, VacPageList fraged_pages, int num_fraged_pages, ...@@ -3150,7 +3152,8 @@ update_hint_bits(Relation rel, VacPageList fraged_pages, int num_fraged_pages,
break; /* no need to scan any further */ break; /* no need to scan any further */
if ((*curpage)->offsets_used == 0) if ((*curpage)->offsets_used == 0)
continue; /* this page was never used as a move dest */ continue; /* this page was never used as a move dest */
buf = ReadBufferWithStrategy(rel, (*curpage)->blkno, vac_strategy); buf = ReadBufferExtended(rel, MAIN_FORKNUM, (*curpage)->blkno,
RBM_NORMAL, vac_strategy);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
max_offset = PageGetMaxOffsetNumber(page); max_offset = PageGetMaxOffsetNumber(page);
...@@ -3219,9 +3222,8 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages) ...@@ -3219,9 +3222,8 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
if ((*vacpage)->offsets_free > 0) if ((*vacpage)->offsets_free > 0)
{ {
buf = ReadBufferWithStrategy(onerel, buf = ReadBufferExtended(onerel, MAIN_FORKNUM, (*vacpage)->blkno,
(*vacpage)->blkno, RBM_NORMAL, vac_strategy);
vac_strategy);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
vacuum_page(onerel, buf, *vacpage); vacuum_page(onerel, buf, *vacpage);
UnlockReleaseBuffer(buf); UnlockReleaseBuffer(buf);
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.108 2008/09/30 10:52:12 heikki Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.109 2008/10/31 15:05:00 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -301,7 +301,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -301,7 +301,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
vacrelstats->num_index_scans++; vacrelstats->num_index_scans++;
} }
buf = ReadBufferWithStrategy(onerel, blkno, vac_strategy); buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno,
RBM_NORMAL, vac_strategy);
/* We need buffer cleanup lock so that we can prune HOT chains. */ /* We need buffer cleanup lock so that we can prune HOT chains. */
LockBufferForCleanup(buf); LockBufferForCleanup(buf);
...@@ -618,7 +619,8 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats) ...@@ -618,7 +619,8 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
vacuum_delay_point(); vacuum_delay_point();
tblk = ItemPointerGetBlockNumber(&vacrelstats->dead_tuples[tupindex]); tblk = ItemPointerGetBlockNumber(&vacrelstats->dead_tuples[tupindex]);
buf = ReadBufferWithStrategy(onerel, tblk, vac_strategy); buf = ReadBufferExtended(onerel, MAIN_FORKNUM, tblk, RBM_NORMAL,
vac_strategy);
LockBufferForCleanup(buf); LockBufferForCleanup(buf);
tupindex = lazy_vacuum_page(onerel, tblk, buf, tupindex, vacrelstats); tupindex = lazy_vacuum_page(onerel, tblk, buf, tupindex, vacrelstats);
...@@ -880,7 +882,8 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) ...@@ -880,7 +882,8 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
blkno--; blkno--;
buf = ReadBufferWithStrategy(onerel, blkno, vac_strategy); buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno,
RBM_NORMAL, vac_strategy);
/* In this phase we only need shared access to the buffer */ /* In this phase we only need shared access to the buffer */
LockBuffer(buf, BUFFER_LOCK_SHARE); LockBuffer(buf, BUFFER_LOCK_SHARE);
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -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.64 2008/10/01 14:59:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.65 2008/10/31 15:05:00 heikki Exp $
* *
* *
* NOTES: * NOTES:
...@@ -504,6 +504,7 @@ static Buffer ...@@ -504,6 +504,7 @@ static Buffer
fsm_readbuf(Relation rel, FSMAddress addr, bool extend) fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
{ {
BlockNumber blkno = fsm_logical_to_physical(addr); BlockNumber blkno = fsm_logical_to_physical(addr);
Buffer buf;
RelationOpenSmgr(rel); RelationOpenSmgr(rel);
...@@ -518,7 +519,18 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend) ...@@ -518,7 +519,18 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
else else
return InvalidBuffer; return InvalidBuffer;
} }
return ReadBufferWithFork(rel, FSM_FORKNUM, blkno);
/*
* Use ZERO_ON_ERROR mode, and initialize the page if necessary. The FSM
* information is not accurate anyway, so it's better to clear corrupt
* pages than error out. Since the FSM changes are not WAL-logged, the
* so-called torn page problem on crash can lead to pages with corrupt
* headers, for example.
*/
buf = ReadBufferExtended(rel, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR, NULL);
if (PageIsNew(BufferGetPage(buf)))
PageInit(BufferGetPage(buf), BLCKSZ, 0);
return buf;
} }
/* /*
...@@ -779,23 +791,18 @@ fsm_redo_truncate(xl_fsm_truncate *xlrec) ...@@ -779,23 +791,18 @@ fsm_redo_truncate(xl_fsm_truncate *xlrec)
* replay of the smgr truncation record to remove completely unused * replay of the smgr truncation record to remove completely unused
* pages. * pages.
*/ */
buf = XLogReadBufferWithFork(xlrec->node, FSM_FORKNUM, fsmblk, false); buf = XLogReadBufferExtended(xlrec->node, FSM_FORKNUM, fsmblk,
RBM_ZERO_ON_ERROR);
if (BufferIsValid(buf)) if (BufferIsValid(buf))
{ {
fsm_truncate_avail(BufferGetPage(buf), first_removed_slot); Page page = BufferGetPage(buf);
if (PageIsNew(page))
PageInit(page, BLCKSZ, 0);
fsm_truncate_avail(page, first_removed_slot);
MarkBufferDirty(buf); MarkBufferDirty(buf);
UnlockReleaseBuffer(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
......
...@@ -6,12 +6,13 @@ ...@@ -6,12 +6,13 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/xlogutils.h,v 1.26 2008/08/11 11:05:11 heikki Exp $ * $PostgreSQL: pgsql/src/include/access/xlogutils.h,v 1.27 2008/10/31 15:05:00 heikki Exp $
*/ */
#ifndef XLOG_UTILS_H #ifndef XLOG_UTILS_H
#define XLOG_UTILS_H #define XLOG_UTILS_H
#include "storage/buf.h" #include "storage/buf.h"
#include "storage/bufmgr.h"
#include "storage/relfilenode.h" #include "storage/relfilenode.h"
#include "storage/block.h" #include "storage/block.h"
#include "utils/relcache.h" #include "utils/relcache.h"
...@@ -25,8 +26,8 @@ extern void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, ...@@ -25,8 +26,8 @@ extern void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum,
BlockNumber nblocks); BlockNumber nblocks);
extern Buffer XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init); extern Buffer XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init);
extern Buffer XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, extern Buffer XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
BlockNumber blkno, bool init); BlockNumber blkno, ReadBufferMode mode);
extern Relation CreateFakeRelcacheEntry(RelFileNode rnode); extern Relation CreateFakeRelcacheEntry(RelFileNode rnode);
extern void FreeFakeRelcacheEntry(Relation fakerel); extern void FreeFakeRelcacheEntry(Relation fakerel);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.115 2008/08/11 11:05:11 heikki Exp $ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.116 2008/10/31 15:05:00 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,6 +31,14 @@ typedef enum BufferAccessStrategyType ...@@ -31,6 +31,14 @@ typedef enum BufferAccessStrategyType
BAS_VACUUM /* VACUUM */ BAS_VACUUM /* VACUUM */
} BufferAccessStrategyType; } BufferAccessStrategyType;
/* Possible modes for ReadBufferExtended() */
typedef enum
{
RBM_NORMAL, /* Normal read */
RBM_ZERO, /* Don't read from disk, caller will initialize */
RBM_ZERO_ON_ERROR /* Read, but return an all-zeros page on error */
} ReadBufferMode;
/* in globals.c ... this duplicates miscadmin.h */ /* in globals.c ... this duplicates miscadmin.h */
extern PGDLLIMPORT int NBuffers; extern PGDLLIMPORT int NBuffers;
...@@ -144,13 +152,12 @@ extern PGDLLIMPORT int32 *LocalRefCount; ...@@ -144,13 +152,12 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* prototypes for functions in bufmgr.c * prototypes for functions in bufmgr.c
*/ */
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum); extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
extern Buffer ReadBufferWithFork(Relation reln, ForkNumber forkNum, BlockNumber blockNum); extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
extern Buffer ReadBufferWithStrategy(Relation reln, BlockNumber blockNum, BlockNumber blockNum, ReadBufferMode mode,
BufferAccessStrategy strategy); BufferAccessStrategy strategy);
extern Buffer ReadOrZeroBuffer(Relation reln, ForkNumber forkNum,
BlockNumber blockNum);
extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp, extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp,
ForkNumber forkNum, BlockNumber blockNum, bool zeroPage); ForkNumber forkNum, BlockNumber blockNum,
ReadBufferMode mode, BufferAccessStrategy strategy);
extern void ReleaseBuffer(Buffer buffer); extern void ReleaseBuffer(Buffer buffer);
extern void UnlockReleaseBuffer(Buffer buffer); extern void UnlockReleaseBuffer(Buffer buffer);
extern void MarkBufferDirty(Buffer buffer); extern void MarkBufferDirty(Buffer buffer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment