]> granicus.if.org Git - postgresql/commitdiff
Unite ReadBufferWithFork, ReadBufferWithStrategy, and ZeroOrReadBuffer
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 31 Oct 2008 15:05:00 +0000 (15:05 +0000)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 31 Oct 2008 15:05:00 +0000 (15:05 +0000)
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.

15 files changed:
contrib/pageinspect/rawpage.c
src/backend/access/gin/ginvacuum.c
src/backend/access/gist/gistvacuum.c
src/backend/access/hash/hashpage.c
src/backend/access/heap/heapam.c
src/backend/access/nbtree/nbtree.c
src/backend/access/transam/xlog.c
src/backend/access/transam/xlogutils.c
src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/storage/buffer/bufmgr.c
src/backend/storage/freespace/freespace.c
src/include/access/xlogutils.h
src/include/storage/bufmgr.h

index 13216d12e04a508d3334aa1fa87cbd4a379941ca..d301fd7ad17f2b671104f15db74bab3951ec7da4 100644 (file)
@@ -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);
index 733710ef563127cac89547e955f793fb2c48d414..ae6459c9fac555a1ca489f5266c67672e6ae29b5 100644 (file)
@@ -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);
 
index 2a917b6528aadbe8c3c8ad4040a254686a6f5d22..80710ae7368f3c2ecc091d57ba48168e93d3c3e9 100644 (file)
@@ -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);
index c5edf6dcfb94d0fd3aa301cad949b18347db0b55..87b97df0ef9d5840dd09dd9f09b6d37ee4378722 100644 (file)
@@ -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);
index ae21c3613e3f11c3c8506dbe5c970bf3310fbb7b..8b0c826aaf2540a9ac45323cd3d1f8ce07b2efe2 100644 (file)
@@ -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)
index 76f6a472aefc412d46ae9455734e9e190639f5f0..f47a8e5f3648ae22c449c0ffbfa52b2befe7b171 100644 (file)
@@ -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);
index 5621fc0dae0b73f59279c32a572a10fabb072bef..77ab05b53d62e46636721e7ecaa87c4fba5cf1d7 100644 (file)
@@ -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);
 
index 9abcce65483133a01b52eed0aabf71d980bb112f..5e60d6cccd19137d11a0be259e537867b5d5e55b 100644 (file)
@@ -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);
index c207e502ee826e599da1657d1cb13703e1d12f8a..4b164aa7c5f3e8a81b9265236710b1d34b3a98c1 100644 (file)
@@ -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);
index 925a8d8abd30dfaf608581d0fb7656b981c6514f..14ed83d1d304868ff3138f0378550f57437a3321 100644 (file)
@@ -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);
index fbaeb8d602aa8651af1f008a9d36af0bf8903e83..48be3f411af088cb21959c0cad68b88ece4d63e9 100644 (file)
@@ -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);
index 86281c11288d78cf51301d526d2737f145a77a11..67f46857238bfd797f563e70ec96ee56d7308544 100644 (file)
@@ -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);
 }
index 9872e5c722201dddf1bc679449f50e72e62a1fea..724e87fa2044714b9f4f9a5a6c63d2e2478d9877 100644 (file)
@@ -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
index 0c81d42e44dcd136dd18075bb6227ea2d4b44699..53ce771f71c70fa26e2704253b47a713dbc95a50 100644 (file)
@@ -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);
index 72d4aec39797497175f95c4d8b5a4cee5c0ec6d7..56f584a78ba8b4251ae93b8d8c02de9d3f967779 100644 (file)
@@ -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);