diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2008-10-31 15:05:00 +0000 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2008-10-31 15:05:00 +0000 |
commit | 19c8dc839b64a43958f08108b85ce8ca98d06a8b (patch) | |
tree | be6bff739a33bd11e4915f47f30038840d397cd5 /src/backend/access | |
parent | 29077051deae30b7704a3e3f2cf7d0a7e3a4130a (diff) | |
download | postgresql-19c8dc839b64a43958f08108b85ce8ca98d06a8b.tar.gz postgresql-19c8dc839b64a43958f08108b85ce8ca98d06a8b.zip |
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.
Diffstat (limited to 'src/backend/access')
-rw-r--r-- | src/backend/access/gin/ginvacuum.c | 44 | ||||
-rw-r--r-- | src/backend/access/gist/gistvacuum.c | 15 | ||||
-rw-r--r-- | src/backend/access/hash/hashpage.c | 8 | ||||
-rw-r--r-- | src/backend/access/heap/heapam.c | 7 | ||||
-rw-r--r-- | src/backend/access/nbtree/nbtree.c | 5 | ||||
-rw-r--r-- | src/backend/access/transam/xlog.c | 6 | ||||
-rw-r--r-- | src/backend/access/transam/xlogutils.c | 62 |
7 files changed, 87 insertions, 60 deletions
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index 733710ef563..ae6459c9fac 100644 --- a/src/backend/access/gin/ginvacuum.c +++ b/src/backend/access/gin/ginvacuum.c @@ -8,7 +8,7 @@ * 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 $ *------------------------------------------------------------------------- */ @@ -155,10 +155,14 @@ xlogVacuumPage(Relation index, Buffer buffer) 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 @@ -241,13 +245,24 @@ static void 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() */ @@ -401,7 +416,8 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel 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)); @@ -589,7 +605,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) 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 (;;) @@ -621,7 +638,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) 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 */ @@ -663,7 +681,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) 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); } @@ -718,7 +737,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) 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); diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index 2a917b6528a..80710ae7368 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -8,7 +8,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -86,7 +86,8 @@ gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno) 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); @@ -306,7 +307,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion) 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); @@ -595,7 +597,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) 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); @@ -691,13 +694,15 @@ gistbulkdelete(PG_FUNCTION_ARGS) 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); diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index c5edf6dcfb9..87b97df0ef9 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -8,7 +8,7 @@ * * * 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 @@ -158,7 +158,7 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno) 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); @@ -203,7 +203,7 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno) BufferGetBlockNumber(buf), blkno); } else - buf = ReadOrZeroBuffer(rel, MAIN_FORKNUM, blkno); + buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO, NULL); LockBuffer(buf, HASH_WRITE); @@ -231,7 +231,7 @@ _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, 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); diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index ae21c3613e3..8b0c826aaf2 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * 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 @@ -205,9 +205,8 @@ heapgetpage(HeapScanDesc scan, BlockNumber page) } /* 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) diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 76f6a472aef..f47a8e5f364 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -12,7 +12,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -750,7 +750,8 @@ restart: * 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); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 5621fc0dae0..77ab05b53d6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -2897,8 +2897,8 @@ RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn) 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); diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 9abcce65483..5e60d6cccd1 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -11,7 +11,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -200,6 +200,20 @@ XLogCheckInvalidPages(void) 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 @@ -211,34 +225,21 @@ XLogCheckInvalidPages(void) * 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; @@ -264,12 +265,13 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, 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; @@ -283,7 +285,7 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, if (buffer != InvalidBuffer) ReleaseBuffer(buffer); buffer = ReadBufferWithoutRelcache(rnode, false, forknum, - P_NEW, false); + P_NEW, mode, NULL); lastblock++; } Assert(BufferGetBlockNumber(buffer) == blkno); @@ -291,7 +293,7 @@ XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum, LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - if (!init) + if (mode == RBM_NORMAL) { /* check that page has been initialized */ Page page = (Page) BufferGetPage(buffer); |