diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index 13216d12e04a508d3334aa1fa87cbd4a379941ca..d301fd7ad17f2b671104f15db74bab3951ec7da4 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -8,7 +8,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -85,7 +85,7 @@ get_raw_page(PG_FUNCTION_ARGS) /* 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); diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index 733710ef563127cac89547e955f793fb2c48d414..ae6459c9fac555a1ca489f5266c67672e6ae29b5 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 2a917b6528aadbe8c3c8ad4040a254686a6f5d22..80710ae7368f3c2ecc091d57ba48168e93d3c3e9 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 c5edf6dcfb94d0fd3aa301cad949b18347db0b55..87b97df0ef9d5840dd09dd9f09b6d37ee4378722 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 ae21c3613e3f11c3c8506dbe5c970bf3310fbb7b..8b0c826aaf2540a9ac45323cd3d1f8ce07b2efe2 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 76f6a472aefc412d46ae9455734e9e190639f5f0..f47a8e5f3648ae22c449c0ffbfa52b2befe7b171 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 5621fc0dae0b73f59279c32a572a10fabb072bef..77ab05b53d62e46636721e7ecaa87c4fba5cf1d7 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 9abcce65483133a01b52eed0aabf71d980bb112f..5e60d6cccd19137d11a0be259e537867b5d5e55b 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); diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index c207e502ee826e599da1657d1cb13703e1d12f8a..4b164aa7c5f3e8a81b9265236710b1d34b3a98c1 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -8,7 +8,7 @@ * * * 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, * 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); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 925a8d8abd30dfaf608581d0fb7656b981c6514f..14ed83d1d304868ff3138f0378550f57437a3321 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * 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, vacuum_delay_point(); - buf = ReadBufferWithStrategy(onerel, blkno, vac_strategy); + buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno, RBM_NORMAL, + vac_strategy); page = BufferGetPage(buf); /* @@ -1919,7 +1920,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, /* * 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; @@ -2173,9 +2175,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, 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); @@ -2318,9 +2320,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, 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))); @@ -2402,14 +2404,14 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, /* 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) @@ -2502,9 +2504,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, 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 */ @@ -2681,9 +2683,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, 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)) @@ -2770,7 +2771,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, 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); @@ -3150,7 +3152,8 @@ update_hint_bits(Relation rel, VacPageList fraged_pages, int num_fraged_pages, 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); @@ -3219,9 +3222,8 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages) 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); diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index fbaeb8d602aa8651af1f008a9d36af0bf8903e83..48be3f411af088cb21959c0cad68b88ece4d63e9 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -29,7 +29,7 @@ * * * 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, 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); @@ -618,7 +619,8 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats) 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); @@ -880,7 +882,8 @@ count_nondeletable_pages(Relation onerel, LVRelStats *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); diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 86281c11288d78cf51301d526d2737f145a77a11..67f46857238bfd797f563e70ec96ee56d7308544 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -72,11 +72,10 @@ static bool IsForInput; 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); @@ -96,7 +95,17 @@ static void AtProcExit_Buffers(int code, Datum arg); /* - * 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 @@ -107,75 +116,29 @@ static void AtProcExit_Buffers(int code, Datum arg); * 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; @@ -189,12 +152,30 @@ ReadBuffer_relcache(Relation reln, ForkNumber forkNum, BlockNumber blockNum, */ 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 * @@ -202,7 +183,7 @@ ReadBuffer_relcache(Relation reln, ForkNumber forkNum, BlockNumber blockNum, */ 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; @@ -295,8 +276,8 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, ForkNumber forkNum, 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."))); /* @@ -356,7 +337,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, ForkNumber forkNum, * 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 { @@ -365,24 +346,25 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, ForkNumber forkNum, /* 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))); } } } @@ -1679,10 +1661,10 @@ PrintBufferLeakWarning(Buffer buffer) /* 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); } @@ -1991,11 +1973,11 @@ PrintBufferDescs(void) { /* 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]); } @@ -2015,11 +1997,11 @@ PrintPinnedBufs(void) { /* 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]); } @@ -2654,11 +2636,11 @@ AbortBufferIO(void) /* 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."))); } } @@ -2676,9 +2658,10 @@ buffer_write_error_callback(void *arg) /* 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); } diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 9872e5c722201dddf1bc679449f50e72e62a1fea..724e87fa2044714b9f4f9a5a6c63d2e2478d9877 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -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.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: @@ -504,6 +504,7 @@ static Buffer fsm_readbuf(Relation rel, FSMAddress addr, bool extend) { BlockNumber blkno = fsm_logical_to_physical(addr); + Buffer buf; RelationOpenSmgr(rel); @@ -518,7 +519,18 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend) 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; } /* @@ -779,23 +791,18 @@ fsm_redo_truncate(xl_fsm_truncate *xlrec) * 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 diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h index 0c81d42e44dcd136dd18075bb6227ea2d4b44699..53ce771f71c70fa26e2704253b47a713dbc95a50 100644 --- a/src/include/access/xlogutils.h +++ b/src/include/access/xlogutils.h @@ -6,12 +6,13 @@ * 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" @@ -25,8 +26,8 @@ extern void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, 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); diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 72d4aec39797497175f95c4d8b5a4cee5c0ec6d7..56f584a78ba8b4251ae93b8d8c02de9d3f967779 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -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/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 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; @@ -144,13 +152,12 @@ extern PGDLLIMPORT int32 *LocalRefCount; * 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);