* Copyright (c) 2007-2008, PostgreSQL Global Development Group
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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);
memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*-------------------------------------------------------------------------
*/
static bool
ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer)
{
- Buffer buffer = ReadBufferWithStrategy(gvs->index, blkno, gvs->strategy);
- Page page = BufferGetPage(buffer);
+ Buffer buffer;
+ Page page;
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
* never release root page until end (but it can unlock it and lock
ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno,
BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
{
- Buffer dBuffer = ReadBufferWithStrategy(gvs->index, deleteBlkno, gvs->strategy);
- Buffer lBuffer = (leftBlkno == InvalidBlockNumber) ?
- InvalidBuffer : ReadBufferWithStrategy(gvs->index, leftBlkno, gvs->strategy);
- Buffer pBuffer = ReadBufferWithStrategy(gvs->index, parentBlkno, gvs->strategy);
+ Buffer dBuffer;
+ Buffer lBuffer;
+ Buffer pBuffer;
Page page,
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);
if (!isParentRoot) /* parent is already locked by
* LockBufferForCleanup() */
me = parent->child;
}
- buffer = ReadBufferWithStrategy(gvs->index, blkno, gvs->strategy);
+ buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
+ RBM_NORMAL, gvs->strategy);
page = BufferGetPage(buffer);
Assert(GinPageIsData(page));
gvs.strategy = info->strategy;
initGinState(&gvs.ginstate, index);
- buffer = ReadBufferWithStrategy(index, blkno, info->strategy);
+ buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
+ RBM_NORMAL, info->strategy);
/* find leaf page */
for (;;)
Assert(blkno != InvalidBlockNumber);
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 */
if (blkno == InvalidBlockNumber) /* rightmost page */
break;
- buffer = ReadBufferWithStrategy(index, blkno, info->strategy);
+ buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
+ RBM_NORMAL, info->strategy);
LockBuffer(buffer, GIN_EXCLUSIVE);
}
vacuum_delay_point();
- buffer = ReadBufferWithStrategy(index, blkno, info->strategy);
+ buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
+ RBM_NORMAL, info->strategy);
LockBuffer(buffer, GIN_SHARE);
page = (Page) BufferGetPage(buffer);
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
Buffer buffer;
Page page;
- buffer = ReadBufferWithStrategy(gv->index, blkno, gv->strategy);
+ buffer = ReadBufferExtended(gv->index, MAIN_FORKNUM, blkno, RBM_NORMAL,
+ gv->strategy);
LockBuffer(buffer, GIST_EXCLUSIVE);
page = (Page) BufferGetPage(buffer);
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);
gistcheckpage(gv->index, buffer);
page = (Page) BufferGetPage(buffer);
vacuum_delay_point();
- buffer = ReadBufferWithStrategy(rel, blkno, info->strategy);
+ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
+ info->strategy);
LockBuffer(buffer, GIST_SHARE);
page = (Page) BufferGetPage(buffer);
while (stack)
{
- Buffer buffer = ReadBufferWithStrategy(rel, stack->blkno, info->strategy);
+ Buffer buffer;
Page page;
OffsetNumber i,
maxoff;
IndexTuple idxtuple;
ItemId iid;
+ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
+ RBM_NORMAL, info->strategy);
LockBuffer(buffer, GIST_SHARE);
gistcheckpage(rel, buffer);
page = (Page) BufferGetPage(buffer);
*
*
* 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
* Postgres hash pages look like ordinary relation pages. The opaque
if (blkno == 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);
BufferGetBlockNumber(buf), blkno);
}
else
- buf = ReadOrZeroBuffer(rel, MAIN_FORKNUM, blkno);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO, NULL);
LockBuffer(buf, HASH_WRITE);
if (blkno == 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)
LockBuffer(buf, access);
*
*
* 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
}
/* read page using selected strategy */
- scan->rs_cbuf = ReadBufferWithStrategy(scan->rs_rd,
- page,
- scan->rs_strategy);
+ scan->rs_cbuf = ReadBufferExtended(scan->rs_rd, MAIN_FORKNUM, page,
+ RBM_NORMAL, scan->rs_strategy);
scan->rs_cblock = page;
if (!scan->rs_pageatatime)
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* recycle all-zero pages, not fail. Also, we want to use a nondefault
* buffer access strategy.
*/
- buf = ReadBufferWithStrategy(rel, blkno, info->strategy);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
+ info->strategy);
LockBuffer(buf, BT_READ);
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
memcpy(&bkpb, blk, sizeof(BkpBlock));
blk += sizeof(BkpBlock);
- buffer = XLogReadBufferWithFork(bkpb.node, bkpb.fork, bkpb.block,
- true);
+ buffer = XLogReadBufferExtended(bkpb.node, bkpb.fork, bkpb.block,
+ RBM_ZERO);
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
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
* expect that this is only used during single-process XLOG replay, but
* some subroutines such as MarkBufferDirty will complain if we don't.)
*
- * If "init" is true then the caller intends to rewrite the page fully
- * using the info in the XLOG record. In this case we will extend the
- * 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.
+ * There's some differences in the behavior wrt. the "mode" argument,
+ * compared to ReadBufferExtended:
*
- * If "init" is false then the caller needs the page to be valid already.
- * If the page doesn't exist or contains zeroes, we return InvalidBuffer.
- * In this case the caller should silently skip the update on this page.
- * (In this situation, we expect that the page was later dropped or truncated.
- * If we don't see evidence of that later in the WAL sequence, we'll complain
- * at the end of WAL replay.)
- */
-Buffer
-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.
+ * In RBM_NORMAL mode, if the page doesn't exist, or contains all-zeroes, we
+ * return InvalidBuffer. In this case the caller should silently skip the
+ * update on this page. (In this situation, we expect that the page was later
+ * dropped or truncated. If we don't see evidence of that later in the WAL
+ * sequence, we'll complain at the end of WAL replay.)
+ *
+ * In RBM_ZERO and RBM_ZERO_ON_ERROR modes, if the page doesn't exist, the
+ * relation is extended with all-zeroes pages up to the given block number.
*/
Buffer
-XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum,
- BlockNumber blkno, bool init)
+XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
+ BlockNumber blkno, ReadBufferMode mode)
{
BlockNumber lastblock;
Buffer buffer;
if (blkno < lastblock)
{
/* page exists in file */
- buffer = ReadBufferWithoutRelcache(rnode, false, forknum, blkno, init);
+ buffer = ReadBufferWithoutRelcache(rnode, false, forknum, blkno,
+ mode, NULL);
}
else
{
/* hm, page doesn't exist in file */
- if (!init)
+ if (mode == RBM_NORMAL)
{
log_invalid_page(rnode, forknum, blkno, false);
return InvalidBuffer;
if (buffer != InvalidBuffer)
ReleaseBuffer(buffer);
buffer = ReadBufferWithoutRelcache(rnode, false, forknum,
- P_NEW, false);
+ P_NEW, mode, NULL);
lastblock++;
}
Assert(BufferGetBlockNumber(buffer) == blkno);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
- if (!init)
+ if (mode == RBM_NORMAL)
{
/* check that page has been initialized */
Page page = (Page) BufferGetPage(buffer);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* each tuple, but since we aren't doing much work per tuple, the
* 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);
targpage = BufferGetPage(targbuffer);
maxoffset = PageGetMaxOffsetNumber(targpage);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
vacuum_delay_point();
- buf = ReadBufferWithStrategy(onerel, blkno, vac_strategy);
+ buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno, RBM_NORMAL,
+ vac_strategy);
page = BufferGetPage(buf);
/*
/*
* Process this page of relation.
*/
- buf = ReadBufferWithStrategy(onerel, blkno, vac_strategy);
+ buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno, RBM_NORMAL,
+ vac_strategy);
page = BufferGetPage(buf);
vacpage->offsets_free = 0;
nextTid = tp.t_data->t_ctid;
priorXmax = HeapTupleHeaderGetXmax(tp.t_data);
/* assume block# is OK (see heap_fetch comments) */
- nextBuf = ReadBufferWithStrategy(onerel,
+ nextBuf = ReadBufferExtended(onerel, MAIN_FORKNUM,
ItemPointerGetBlockNumber(&nextTid),
- vac_strategy);
+ RBM_NORMAL, vac_strategy);
nextPage = BufferGetPage(nextBuf);
/* If bogus or unused slot, assume tp is end of chain */
nextOffnum = ItemPointerGetOffsetNumber(&nextTid);
break; /* out of check-all-items loop */
}
tp.t_self = vtlp->this_tid;
- Pbuf = ReadBufferWithStrategy(onerel,
+ Pbuf = ReadBufferExtended(onerel, MAIN_FORKNUM,
ItemPointerGetBlockNumber(&(tp.t_self)),
- vac_strategy);
+ RBM_NORMAL, vac_strategy);
Ppage = BufferGetPage(Pbuf);
Pitemid = PageGetItemId(Ppage,
ItemPointerGetOffsetNumber(&(tp.t_self)));
/* Get page to move from */
tuple.t_self = vtmove[ti].tid;
- Cbuf = ReadBufferWithStrategy(onerel,
+ Cbuf = ReadBufferExtended(onerel, MAIN_FORKNUM,
ItemPointerGetBlockNumber(&(tuple.t_self)),
- vac_strategy);
+ RBM_NORMAL, vac_strategy);
/* Get page to move to */
- dst_buffer = ReadBufferWithStrategy(onerel,
- destvacpage->blkno,
- vac_strategy);
+ dst_buffer = ReadBufferExtended(onerel, MAIN_FORKNUM,
+ destvacpage->blkno,
+ RBM_NORMAL, vac_strategy);
LockBuffer(dst_buffer, BUFFER_LOCK_EXCLUSIVE);
if (dst_buffer != Cbuf)
if (i == num_fraged_pages)
break; /* can't move item anywhere */
dst_vacpage = fraged_pages->pagedesc[i];
- dst_buffer = ReadBufferWithStrategy(onerel,
- dst_vacpage->blkno,
- vac_strategy);
+ dst_buffer = ReadBufferExtended(onerel, MAIN_FORKNUM,
+ dst_vacpage->blkno,
+ RBM_NORMAL, vac_strategy);
LockBuffer(dst_buffer, BUFFER_LOCK_EXCLUSIVE);
dst_page = BufferGetPage(dst_buffer);
/* if this page was not used before - clean it */
Page page;
/* this page was not used as a move target, so must clean it */
- buf = ReadBufferWithStrategy(onerel,
- (*curpage)->blkno,
- vac_strategy);
+ buf = ReadBufferExtended(onerel, MAIN_FORKNUM, (*curpage)->blkno,
+ RBM_NORMAL, vac_strategy);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
page = BufferGetPage(buf);
if (!PageIsEmpty(page))
int uncnt = 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);
page = BufferGetPage(buf);
maxoff = PageGetMaxOffsetNumber(page);
break; /* no need to scan any further */
if ((*curpage)->offsets_used == 0)
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);
page = BufferGetPage(buf);
max_offset = PageGetMaxOffsetNumber(page);
if ((*vacpage)->offsets_free > 0)
{
- buf = ReadBufferWithStrategy(onerel,
- (*vacpage)->blkno,
- vac_strategy);
+ buf = ReadBufferExtended(onerel, MAIN_FORKNUM, (*vacpage)->blkno,
+ RBM_NORMAL, vac_strategy);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
vacuum_page(onerel, buf, *vacpage);
UnlockReleaseBuffer(buf);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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. */
LockBufferForCleanup(buf);
vacuum_delay_point();
tblk = ItemPointerGetBlockNumber(&vacrelstats->dead_tuples[tupindex]);
- buf = ReadBufferWithStrategy(onerel, tblk, vac_strategy);
+ buf = ReadBufferExtended(onerel, MAIN_FORKNUM, tblk, RBM_NORMAL,
+ vac_strategy);
LockBufferForCleanup(buf);
tupindex = lazy_vacuum_page(onerel, tblk, buf, tupindex, vacrelstats);
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 */
LockBuffer(buf, BUFFER_LOCK_SHARE);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.239 2008/10/20 21:11:15 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.240 2008/10/31 15:05:00 heikki Exp $
*
*-------------------------------------------------------------------------
*/
static volatile BufferDesc *PinCountWaitBuf = NULL;
-static Buffer ReadBuffer_relcache(Relation reln, ForkNumber forkNum,
- BlockNumber blockNum, bool zeroPage, BufferAccessStrategy strategy);
static Buffer ReadBuffer_common(SMgrRelation reln, bool isLocalBuf,
- ForkNumber forkNum, BlockNumber blockNum,
- bool zeroPage, BufferAccessStrategy strategy, bool *hit);
+ ForkNumber forkNum, BlockNumber blockNum,
+ ReadBufferMode mode , BufferAccessStrategy strategy,
+ bool *hit);
static bool PinBuffer(volatile BufferDesc *buf, BufferAccessStrategy strategy);
static void PinBuffer_Locked(volatile BufferDesc *buf);
static void UnpinBuffer(volatile BufferDesc *buf, bool fixOwner);
/*
- * ReadBuffer -- returns a buffer containing the requested
+ * ReadBuffer -- a shorthand for ReadBufferExtended, for reading from main
+ * fork with RBM_NORMAL mode and default strategy.
+ */
+Buffer
+ReadBuffer(Relation reln, BlockNumber blockNum)
+{
+ return ReadBufferExtended(reln, MAIN_FORKNUM, blockNum, RBM_NORMAL, NULL);
+}
+
+/*
+ * ReadBufferExtended -- returns a buffer containing the requested
* block of the requested relation. If the blknum
* requested is P_NEW, extend the relation file and
* allocate a new block. (Caller is responsible for
* the block read. The returned buffer has been pinned.
* Does not return on error --- elog's instead.
*
- * Assume when this function is called, that reln has been
- * opened already.
- */
-Buffer
-ReadBuffer(Relation reln, BlockNumber blockNum)
-{
- return ReadBuffer_relcache(reln, MAIN_FORKNUM, blockNum, false, NULL);
-}
-
-/*
- * ReadBufferWithFork -- same as ReadBuffer, but for accessing relation
- * forks other than MAIN_FORKNUM.
- */
-Buffer
-ReadBufferWithFork(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
-{
- return ReadBuffer_relcache(reln, forkNum, blockNum, false, NULL);
-}
-
-/*
- * ReadBufferWithStrategy -- same as ReadBuffer, except caller can specify
- * a nondefault buffer access strategy. See buffer/README for details.
- */
-Buffer
-ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
- BufferAccessStrategy strategy)
-{
- return ReadBuffer_relcache(reln, MAIN_FORKNUM, blockNum, false, strategy);
-}
-
-/*
- * ReadOrZeroBuffer -- like ReadBuffer, but if the page isn't in buffer
- * cache already, it's filled with zeros instead of reading it from
- * disk. Useful when the caller intends to fill the page from scratch,
- * since this saves I/O and avoids unnecessary failure if the
- * page-on-disk has corrupt page headers.
- *
- * Caution: do not use this to read a page that is beyond the relation's
- * current physical EOF; that is likely to cause problems in md.c when
- * the page is modified and written out. P_NEW is OK, though.
- */
-Buffer
-ReadOrZeroBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
-{
- return ReadBuffer_relcache(reln, forkNum, blockNum, true, NULL);
-}
-
-/*
- * ReadBufferWithoutRelcache -- like ReadBuffer, but doesn't require a
- * relcache entry for the relation. If zeroPage is true, this behaves
- * like ReadOrZeroBuffer rather than ReadBuffer.
+ * Assume when this function is called, that reln has been opened already.
+ *
+ * In RBM_NORMAL mode, the page is read from disk, and the page header is
+ * validated. An error is thrown if the page header is not valid.
+ *
+ * RBM_ZERO_ON_ERROR is like the normal mode, but if the page header is not
+ * valid, the page is zeroed instead of throwing an error. This is intended
+ * for non-critical data, where the caller is prepared to repair errors.
+ *
+ * In RBM_ZERO mode, if the page isn't in buffer cache already, it's filled
+ * with zeros instead of reading it from disk. Useful when the caller is
+ * going to fill the page from scratch, since this saves I/O and avoids
+ * unnecessary failure if the page-on-disk has corrupt page headers.
+ * Caution: do not use this mode to read a page that is beyond the relation's
+ * current physical EOF; that is likely to cause problems in md.c when
+ * the page is modified and written out. P_NEW is OK, though.
+ *
+ * If strategy is not NULL, a nondefault buffer access strategy is used.
+ * See buffer/README for details.
*/
Buffer
-ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp,
- ForkNumber forkNum, BlockNumber blockNum, bool zeroPage)
-{
- bool hit;
-
- SMgrRelation smgr = smgropen(rnode);
- return ReadBuffer_common(smgr, isTemp, forkNum, blockNum, zeroPage, NULL, &hit);
-}
-
-/*
- * ReadBuffer_relcache -- common logic for ReadBuffer-variants that
- * operate on a Relation.
- */
-static Buffer
-ReadBuffer_relcache(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
- bool zeroPage, BufferAccessStrategy strategy)
+ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
+ ReadBufferMode mode, BufferAccessStrategy strategy)
{
bool hit;
Buffer buf;
*/
pgstat_count_buffer_read(reln);
buf = ReadBuffer_common(reln->rd_smgr, reln->rd_istemp, forkNum, blockNum,
- zeroPage, strategy, &hit);
+ mode, strategy, &hit);
if (hit)
pgstat_count_buffer_hit(reln);
return buf;
}
+
+/*
+ * ReadBufferWithoutRelcache -- like ReadBufferExtended, but doesn't require
+ * a relcache entry for the relation.
+ */
+Buffer
+ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp,
+ ForkNumber forkNum, BlockNumber blockNum,
+ ReadBufferMode mode, BufferAccessStrategy strategy)
+{
+ bool hit;
+
+ SMgrRelation smgr = smgropen(rnode);
+ return ReadBuffer_common(smgr, isTemp, forkNum, blockNum, mode, strategy,
+ &hit);
+}
+
+
/*
* ReadBuffer_common -- common logic for all ReadBuffer variants
*
*/
static Buffer
ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, ForkNumber forkNum,
- BlockNumber blockNum, bool zeroPage,
+ BlockNumber blockNum, ReadBufferMode mode,
BufferAccessStrategy strategy, bool *hit)
{
volatile BufferDesc *bufHdr;
bufBlock = isLocalBuf ? LocalBufHdrGetBlock(bufHdr) : BufHdrGetBlock(bufHdr);
if (!PageIsNew((Page) bufBlock))
ereport(ERROR,
- (errmsg("unexpected data beyond EOF in block %u of relation %u/%u/%u",
- blockNum, smgr->smgr_rnode.spcNode, smgr->smgr_rnode.dbNode, smgr->smgr_rnode.relNode),
+ (errmsg("unexpected data beyond EOF in block %u of relation %u/%u/%u/%u",
+ blockNum, smgr->smgr_rnode.spcNode, smgr->smgr_rnode.dbNode, smgr->smgr_rnode.relNode, forkNum),
errhint("This has been seen to occur with buggy kernels; consider updating your system.")));
/*
* Read in the page, unless the caller intends to overwrite it and
* just wants us to allocate a buffer.
*/
- if (zeroPage)
+ if (mode == RBM_ZERO)
MemSet((char *) bufBlock, 0, BLCKSZ);
else
{
/* check for garbage data */
if (!PageHeaderIsValid((PageHeader) bufBlock))
{
- if (zero_damaged_pages)
+ if (mode == RBM_ZERO_ON_ERROR || zero_damaged_pages)
{
ereport(WARNING,
(errcode(ERRCODE_DATA_CORRUPTED),
- errmsg("invalid page header in block %u of relation %u/%u/%u; zeroing out page",
+ errmsg("invalid page header in block %u of relation %u/%u/%u/%u; zeroing out page",
blockNum,
smgr->smgr_rnode.spcNode,
smgr->smgr_rnode.dbNode,
- smgr->smgr_rnode.relNode)));
+ smgr->smgr_rnode.relNode,
+ forkNum)));
MemSet((char *) bufBlock, 0, BLCKSZ);
}
else
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
- errmsg("invalid page header in block %u of relation %u/%u/%u",
+ errmsg("invalid page header in block %u of relation %u/%u/%u/%u",
blockNum, smgr->smgr_rnode.spcNode,
smgr->smgr_rnode.dbNode,
- smgr->smgr_rnode.relNode)));
+ smgr->smgr_rnode.relNode, forkNum)));
}
}
}
/* theoretically we should lock the bufhdr here */
elog(WARNING,
"buffer refcount leak: [%03d] "
- "(rel=%u/%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)",
+ "(rel=%u/%u/%u, forkNum=%u, blockNum=%u, flags=0x%x, refcount=%u %d)",
buffer,
buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
- buf->tag.rnode.relNode,
+ buf->tag.rnode.relNode, buf->tag.forkNum,
buf->tag.blockNum, buf->flags,
buf->refcount, loccount);
}
{
/* theoretically we should lock the bufhdr here */
elog(LOG,
- "[%02d] (freeNext=%d, rel=%u/%u/%u, "
+ "[%02d] (freeNext=%d, rel=%u/%u/%u, forkNum=%u, "
"blockNum=%u, flags=0x%x, refcount=%u %d)",
i, buf->freeNext,
buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
- buf->tag.rnode.relNode,
+ buf->tag.rnode.relNode, buf->tag.forkNum,
buf->tag.blockNum, buf->flags,
buf->refcount, PrivateRefCount[i]);
}
{
/* theoretically we should lock the bufhdr here */
elog(LOG,
- "[%02d] (freeNext=%d, rel=%u/%u/%u, "
+ "[%02d] (freeNext=%d, rel=%u/%u/%u, forkNum=%u, "
"blockNum=%u, flags=0x%x, refcount=%u %d)",
i, buf->freeNext,
buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
- buf->tag.rnode.relNode,
+ buf->tag.rnode.relNode, buf->tag.forkNum,
buf->tag.blockNum, buf->flags,
buf->refcount, PrivateRefCount[i]);
}
/* Buffer is pinned, so we can read tag without spinlock */
ereport(WARNING,
(errcode(ERRCODE_IO_ERROR),
- errmsg("could not write block %u of %u/%u/%u",
+ errmsg("could not write block %u of %u/%u/%u/%u",
buf->tag.blockNum,
buf->tag.rnode.spcNode,
buf->tag.rnode.dbNode,
- buf->tag.rnode.relNode),
+ buf->tag.rnode.relNode, buf->tag.forkNum),
errdetail("Multiple failures --- write error might be permanent.")));
}
}
/* Buffer is pinned, so we can read the tag without locking the spinlock */
if (bufHdr != NULL)
- errcontext("writing block %u of relation %u/%u/%u",
+ errcontext("writing block %u of relation %u/%u/%u/%u",
bufHdr->tag.blockNum,
bufHdr->tag.rnode.spcNode,
bufHdr->tag.rnode.dbNode,
- bufHdr->tag.rnode.relNode);
+ bufHdr->tag.rnode.relNode,
+ bufHdr->tag.forkNum);
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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:
fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
{
BlockNumber blkno = fsm_logical_to_physical(addr);
+ Buffer buf;
RelationOpenSmgr(rel);
else
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;
}
/*
* replay of the smgr truncation record to remove completely unused
* pages.
*/
- buf = XLogReadBufferWithFork(xlrec->node, FSM_FORKNUM, fsmblk, false);
+ buf = XLogReadBufferExtended(xlrec->node, FSM_FORKNUM, fsmblk,
+ RBM_ZERO_ON_ERROR);
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);
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
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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
#define XLOG_UTILS_H
#include "storage/buf.h"
+#include "storage/bufmgr.h"
#include "storage/relfilenode.h"
#include "storage/block.h"
#include "utils/relcache.h"
BlockNumber nblocks);
extern Buffer XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init);
-extern Buffer XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum,
- BlockNumber blkno, bool init);
+extern Buffer XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
+ BlockNumber blkno, ReadBufferMode mode);
extern Relation CreateFakeRelcacheEntry(RelFileNode rnode);
extern void FreeFakeRelcacheEntry(Relation fakerel);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
BAS_VACUUM /* VACUUM */
} 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 */
extern PGDLLIMPORT int NBuffers;
* prototypes for functions in bufmgr.c
*/
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
-extern Buffer ReadBufferWithFork(Relation reln, ForkNumber forkNum, BlockNumber blockNum);
-extern Buffer ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
- BufferAccessStrategy strategy);
-extern Buffer ReadOrZeroBuffer(Relation reln, ForkNumber forkNum,
- BlockNumber blockNum);
+extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
+ BlockNumber blockNum, ReadBufferMode mode,
+ BufferAccessStrategy strategy);
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 UnlockReleaseBuffer(Buffer buffer);
extern void MarkBufferDirty(Buffer buffer);